View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package org.apache.bcel.classfile;
19  
20  import java.io.DataInput;
21  import java.io.DataOutputStream;
22  import java.io.IOException;
23  
24  import org.apache.bcel.Const;
25  
26  /**
27   * This class represents an entry in the provides table of the Module attribute. Each entry describes a service
28   * implementation that the parent module provides.
29   *
30   * @see Module
31   * @since 6.4.0
32   */
33  public final class ModuleProvides implements Cloneable, Node {
34  
35      private static String getImplementationClassNameAtIndex(final ConstantPool constantPool, final int index, final boolean compactClassName) {
36          final String className = constantPool.getConstantString(index, Const.CONSTANT_Class);
37          if (compactClassName) {
38              return Utility.compactClassName(className, false);
39          }
40          return className;
41      }
42      private final int providesIndex; // points to CONSTANT_Class_info
43      private final int providesWithCount;
44  
45      private final int[] providesWithIndex; // points to CONSTANT_Class_info
46  
47      /**
48       * Constructs object from file stream.
49       *
50       * @param file Input stream
51       * @throws IOException if an I/O Exception occurs in readUnsignedShort
52       */
53      ModuleProvides(final DataInput file) throws IOException {
54          providesIndex = file.readUnsignedShort();
55          providesWithCount = file.readUnsignedShort();
56          providesWithIndex = new int[providesWithCount];
57          for (int i = 0; i < providesWithCount; i++) {
58              providesWithIndex[i] = file.readUnsignedShort();
59          }
60      }
61  
62      /**
63       * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
64       * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
65       *
66       * @param v Visitor object
67       */
68      @Override
69      public void accept(final Visitor v) {
70          v.visitModuleProvides(this);
71      }
72  
73      /**
74       * @return deep copy of this object
75       */
76      public ModuleProvides copy() {
77          try {
78              return (ModuleProvides) clone();
79          } catch (final CloneNotSupportedException e) {
80              // TODO should this throw?
81          }
82          return null;
83      }
84  
85      /**
86       * Dump table entry to file stream in binary format.
87       *
88       * @param file Output file stream
89       * @throws IOException if an I/O Exception occurs in writeShort
90       */
91      public void dump(final DataOutputStream file) throws IOException {
92          file.writeShort(providesIndex);
93          file.writeShort(providesWithCount);
94          for (final int entry : providesWithIndex) {
95              file.writeShort(entry);
96          }
97      }
98  
99      /**
100      * Gets the array of implementation class names for this ModuleProvides.
101      * @param constantPool Array of constants usually obtained from the ClassFile object
102      * @param compactClassName false for original constant pool value, true to replace '/' with '.'
103      * @return array of implementation class names
104      * @since 6.10.0
105      */
106     public String[] getImplementationClassNames(final ConstantPool constantPool, final boolean compactClassName) {
107         final String[] implementationClassNames = new String[providesWithCount];
108         for (int i = 0; i < providesWithCount; i++) {
109             implementationClassNames[i] = getImplementationClassNameAtIndex(constantPool, providesWithIndex[i], compactClassName);
110         }
111         return implementationClassNames;
112     }
113 
114     /**
115      * Gets the interface name for this ModuleProvides.
116      * @param constantPool Array of constants usually obtained from the ClassFile object
117      * @return interface name
118      * @since 6.10.0
119      */
120     public String getInterfaceName(final ConstantPool constantPool) {
121         return constantPool.constantToString(providesIndex, Const.CONSTANT_Class);
122     }
123 
124     /**
125      * @return String representation
126      */
127     @Override
128     public String toString() {
129         return "provides(" + providesIndex + ", " + providesWithCount + ", ...)";
130     }
131 
132     /**
133      * @return Resolved string representation
134      */
135     public String toString(final ConstantPool constantPool) {
136         final StringBuilder buf = new StringBuilder();
137         final String interfaceName = getInterfaceName(constantPool);
138         buf.append(interfaceName);
139         buf.append(", with(").append(providesWithCount).append("):\n");
140         for (final int index : providesWithIndex) {
141             final String className = getImplementationClassNameAtIndex(constantPool, index, true);
142             buf.append("      ").append(className).append("\n");
143         }
144         return buf.substring(0, buf.length() - 1); // remove the last newline
145     }
146 }