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  import java.util.Arrays;
24  
25  import org.apache.bcel.Const;
26  
27  /**
28   * This class is derived from <em>Attribute</em> and represents the list of modules required, exported, opened or
29   * provided by a module. There may be at most one Module attribute in a ClassFile structure.
30   *
31   * @see Attribute
32   * @since 6.4.0
33   */
34  public final class Module extends Attribute {
35  
36      /**
37       * The module file name extension.
38       *
39       * @since 6.7.0
40       */
41      public static final String EXTENSION = ".jmod";
42  
43      private final int moduleNameIndex;
44      private final int moduleFlags;
45      private final int moduleVersionIndex;
46  
47      private ModuleRequires[] requiresTable;
48      private ModuleExports[] exportsTable;
49      private ModuleOpens[] opensTable;
50      private final int usesCount;
51      private final int[] usesIndex;
52      private ModuleProvides[] providesTable;
53  
54      /**
55       * Constructs object from input stream.
56       *
57       * @param nameIndex Index in constant pool
58       * @param length Content length in bytes
59       * @param input Input stream
60       * @param constantPool Array of constants
61       * @throws IOException if an I/O error occurs.
62       */
63      Module(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
64          super(Const.ATTR_MODULE, nameIndex, length, constantPool);
65  
66          moduleNameIndex = input.readUnsignedShort();
67          moduleFlags = input.readUnsignedShort();
68          moduleVersionIndex = input.readUnsignedShort();
69  
70          final int requiresCount = input.readUnsignedShort();
71          requiresTable = new ModuleRequires[requiresCount];
72          for (int i = 0; i < requiresCount; i++) {
73              requiresTable[i] = new ModuleRequires(input);
74          }
75  
76          final int exportsCount = input.readUnsignedShort();
77          exportsTable = new ModuleExports[exportsCount];
78          for (int i = 0; i < exportsCount; i++) {
79              exportsTable[i] = new ModuleExports(input);
80          }
81  
82          final int opensCount = input.readUnsignedShort();
83          opensTable = new ModuleOpens[opensCount];
84          for (int i = 0; i < opensCount; i++) {
85              opensTable[i] = new ModuleOpens(input);
86          }
87  
88          usesCount = input.readUnsignedShort();
89          usesIndex = new int[usesCount];
90          for (int i = 0; i < usesCount; i++) {
91              usesIndex[i] = input.readUnsignedShort();
92          }
93  
94          final int providesCount = input.readUnsignedShort();
95          providesTable = new ModuleProvides[providesCount];
96          for (int i = 0; i < providesCount; i++) {
97              providesTable[i] = new ModuleProvides(input);
98          }
99      }
100 
101     /**
102      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
103      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
104      *
105      * @param v Visitor object
106      */
107     @Override
108     public void accept(final Visitor v) {
109         v.visitModule(this);
110     }
111 
112     // TODO add more getters and setters?
113 
114     /**
115      * @return deep copy of this attribute
116      */
117     @Override
118     public Attribute copy(final ConstantPool constantPool) {
119         final Module c = (Module) clone();
120 
121         c.requiresTable = new ModuleRequires[requiresTable.length];
122         Arrays.setAll(c.requiresTable, i -> requiresTable[i].copy());
123 
124         c.exportsTable = new ModuleExports[exportsTable.length];
125         Arrays.setAll(c.exportsTable, i -> exportsTable[i].copy());
126 
127         c.opensTable = new ModuleOpens[opensTable.length];
128         Arrays.setAll(c.opensTable, i -> opensTable[i].copy());
129 
130         c.providesTable = new ModuleProvides[providesTable.length];
131         Arrays.setAll(c.providesTable, i -> providesTable[i].copy());
132 
133         c.setConstantPool(constantPool);
134         return c;
135     }
136 
137     /**
138      * Dump Module attribute to file stream in binary format.
139      *
140      * @param file Output file stream
141      * @throws IOException if an I/O error occurs.
142      */
143     @Override
144     public void dump(final DataOutputStream file) throws IOException {
145         super.dump(file);
146 
147         file.writeShort(moduleNameIndex);
148         file.writeShort(moduleFlags);
149         file.writeShort(moduleVersionIndex);
150 
151         file.writeShort(requiresTable.length);
152         for (final ModuleRequires entry : requiresTable) {
153             entry.dump(file);
154         }
155 
156         file.writeShort(exportsTable.length);
157         for (final ModuleExports entry : exportsTable) {
158             entry.dump(file);
159         }
160 
161         file.writeShort(opensTable.length);
162         for (final ModuleOpens entry : opensTable) {
163             entry.dump(file);
164         }
165 
166         file.writeShort(usesIndex.length);
167         for (final int entry : usesIndex) {
168             file.writeShort(entry);
169         }
170 
171         file.writeShort(providesTable.length);
172         for (final ModuleProvides entry : providesTable) {
173             entry.dump(file);
174         }
175     }
176 
177     /**
178      * @return table of exported interfaces
179      * @see ModuleExports
180      */
181     public ModuleExports[] getExportsTable() {
182         return exportsTable;
183     }
184 
185     /**
186      * @return table of provided interfaces
187      * @see ModuleOpens
188      */
189     public ModuleOpens[] getOpensTable() {
190         return opensTable;
191     }
192 
193     /**
194      * @return table of provided interfaces
195      * @see ModuleProvides
196      */
197     public ModuleProvides[] getProvidesTable() {
198         return providesTable;
199     }
200 
201     /**
202      * @return table of required modules
203      * @see ModuleRequires
204      */
205     public ModuleRequires[] getRequiresTable() {
206         return requiresTable;
207     }
208 
209     /**
210      * @return String representation, i.e., a list of packages.
211      */
212     @Override
213     public String toString() {
214         final ConstantPool cp = super.getConstantPool();
215         final StringBuilder buf = new StringBuilder();
216         buf.append("Module:\n");
217         buf.append("  name:    ").append(Utility.pathToPackage(cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module))).append("\n");
218         buf.append("  flags:   ").append(String.format("%04x", moduleFlags)).append("\n");
219         final String version = moduleVersionIndex == 0 ? "0" : cp.getConstantString(moduleVersionIndex, Const.CONSTANT_Utf8);
220         buf.append("  version: ").append(version).append("\n");
221 
222         buf.append("  requires(").append(requiresTable.length).append("):\n");
223         for (final ModuleRequires module : requiresTable) {
224             buf.append("    ").append(module.toString(cp)).append("\n");
225         }
226 
227         buf.append("  exports(").append(exportsTable.length).append("):\n");
228         for (final ModuleExports module : exportsTable) {
229             buf.append("    ").append(module.toString(cp)).append("\n");
230         }
231 
232         buf.append("  opens(").append(opensTable.length).append("):\n");
233         for (final ModuleOpens module : opensTable) {
234             buf.append("    ").append(module.toString(cp)).append("\n");
235         }
236 
237         buf.append("  uses(").append(usesIndex.length).append("):\n");
238         for (final int index : usesIndex) {
239             final String className = cp.getConstantString(index, Const.CONSTANT_Class);
240             buf.append("    ").append(Utility.compactClassName(className, false)).append("\n");
241         }
242 
243         buf.append("  provides(").append(providesTable.length).append("):\n");
244         for (final ModuleProvides module : providesTable) {
245             buf.append("    ").append(module.toString(cp)).append("\n");
246         }
247 
248         return buf.substring(0, buf.length() - 1); // remove the last newline
249     }
250 }