001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.bcel.classfile; 019 020import java.io.DataInput; 021import java.io.DataOutputStream; 022import java.io.IOException; 023import java.util.Arrays; 024 025import org.apache.bcel.Const; 026 027/** 028 * This class is derived from <em>Attribute</em> and represents the list of modules required, exported, opened or 029 * provided by a module. There may be at most one Module attribute in a ClassFile structure. 030 * 031 * @see Attribute 032 * @since 6.4.0 033 */ 034public final class Module extends Attribute { 035 036 /** 037 * The module file name extension. 038 * 039 * @since 6.7.0 040 */ 041 public static final String EXTENSION = ".jmod"; 042 043 private static String getClassNameAtIndex(final ConstantPool cp, final int index, final boolean compactClassName) { 044 final String className = cp.getConstantString(index, Const.CONSTANT_Class); 045 if (compactClassName) { 046 return Utility.compactClassName(className, false); 047 } 048 return className; 049 } 050 private final int moduleNameIndex; 051 private final int moduleFlags; 052 053 private final int moduleVersionIndex; 054 private ModuleRequires[] requiresTable; 055 private ModuleExports[] exportsTable; 056 private ModuleOpens[] opensTable; 057 private final int usesCount; 058 private final int[] usesIndex; 059 060 private ModuleProvides[] providesTable; 061 062 /** 063 * Constructs object from input stream. 064 * 065 * @param nameIndex Index in constant pool 066 * @param length Content length in bytes 067 * @param input Input stream 068 * @param constantPool Array of constants 069 * @throws IOException if an I/O error occurs. 070 */ 071 Module(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { 072 super(Const.ATTR_MODULE, nameIndex, length, constantPool); 073 074 moduleNameIndex = input.readUnsignedShort(); 075 moduleFlags = input.readUnsignedShort(); 076 moduleVersionIndex = input.readUnsignedShort(); 077 078 final int requiresCount = input.readUnsignedShort(); 079 requiresTable = new ModuleRequires[requiresCount]; 080 for (int i = 0; i < requiresCount; i++) { 081 requiresTable[i] = new ModuleRequires(input); 082 } 083 084 final int exportsCount = input.readUnsignedShort(); 085 exportsTable = new ModuleExports[exportsCount]; 086 for (int i = 0; i < exportsCount; i++) { 087 exportsTable[i] = new ModuleExports(input); 088 } 089 090 final int opensCount = input.readUnsignedShort(); 091 opensTable = new ModuleOpens[opensCount]; 092 for (int i = 0; i < opensCount; i++) { 093 opensTable[i] = new ModuleOpens(input); 094 } 095 096 usesCount = input.readUnsignedShort(); 097 usesIndex = new int[usesCount]; 098 for (int i = 0; i < usesCount; i++) { 099 usesIndex[i] = input.readUnsignedShort(); 100 } 101 102 final int providesCount = input.readUnsignedShort(); 103 providesTable = new ModuleProvides[providesCount]; 104 for (int i = 0; i < providesCount; i++) { 105 providesTable[i] = new ModuleProvides(input); 106 } 107 } 108 109 /** 110 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 111 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 112 * 113 * @param v Visitor object 114 */ 115 @Override 116 public void accept(final Visitor v) { 117 v.visitModule(this); 118 } 119 120 /** 121 * @return deep copy of this attribute 122 */ 123 @Override 124 public Attribute copy(final ConstantPool constantPool) { 125 final Module c = (Module) clone(); 126 127 c.requiresTable = new ModuleRequires[requiresTable.length]; 128 Arrays.setAll(c.requiresTable, i -> requiresTable[i].copy()); 129 130 c.exportsTable = new ModuleExports[exportsTable.length]; 131 Arrays.setAll(c.exportsTable, i -> exportsTable[i].copy()); 132 133 c.opensTable = new ModuleOpens[opensTable.length]; 134 Arrays.setAll(c.opensTable, i -> opensTable[i].copy()); 135 136 c.providesTable = new ModuleProvides[providesTable.length]; 137 Arrays.setAll(c.providesTable, i -> providesTable[i].copy()); 138 139 c.setConstantPool(constantPool); 140 return c; 141 } 142 143 /** 144 * Dump Module attribute to file stream in binary format. 145 * 146 * @param file Output file stream 147 * @throws IOException if an I/O error occurs. 148 */ 149 @Override 150 public void dump(final DataOutputStream file) throws IOException { 151 super.dump(file); 152 153 file.writeShort(moduleNameIndex); 154 file.writeShort(moduleFlags); 155 file.writeShort(moduleVersionIndex); 156 157 file.writeShort(requiresTable.length); 158 for (final ModuleRequires entry : requiresTable) { 159 entry.dump(file); 160 } 161 162 file.writeShort(exportsTable.length); 163 for (final ModuleExports entry : exportsTable) { 164 entry.dump(file); 165 } 166 167 file.writeShort(opensTable.length); 168 for (final ModuleOpens entry : opensTable) { 169 entry.dump(file); 170 } 171 172 file.writeShort(usesIndex.length); 173 for (final int entry : usesIndex) { 174 file.writeShort(entry); 175 } 176 177 file.writeShort(providesTable.length); 178 for (final ModuleProvides entry : providesTable) { 179 entry.dump(file); 180 } 181 } 182 183 /** 184 * @return table of exported interfaces 185 * @see ModuleExports 186 */ 187 public ModuleExports[] getExportsTable() { 188 return exportsTable; 189 } 190 191 /** 192 * Gets flags for this module. 193 * @return module flags 194 * @since 6.10.0 195 */ 196 public int getModuleFlags() { 197 return moduleFlags; 198 } 199 200 /** 201 * Gets module name. 202 * @param cp Array of constants 203 * @return module name 204 * @since 6.10.0 205 */ 206 public String getModuleName(final ConstantPool cp) { 207 return cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module); 208 } 209 210 /** 211 * @return table of provided interfaces 212 * @see ModuleOpens 213 */ 214 public ModuleOpens[] getOpensTable() { 215 return opensTable; 216 } 217 218 /** 219 * @return table of provided interfaces 220 * @see ModuleProvides 221 */ 222 public ModuleProvides[] getProvidesTable() { 223 return providesTable; 224 } 225 226 /** 227 * @return table of required modules 228 * @see ModuleRequires 229 */ 230 public ModuleRequires[] getRequiresTable() { 231 return requiresTable; 232 } 233 234 /** 235 * Gets the array of class names for this module's uses. 236 * @param constantPool Array of constants usually obtained from the ClassFile object 237 * @param compactClassName false for original constant pool value, true to replace '/' with '.' 238 * @return array of used class names 239 * @since 6.10.0 240 */ 241 public String[] getUsedClassNames(final ConstantPool constantPool, final boolean compactClassName) { 242 final String[] usedClassNames = new String[usesCount]; 243 for (int i = 0; i < usesCount; i++) { 244 usedClassNames[i] = getClassNameAtIndex(constantPool, usesIndex[i], compactClassName); 245 } 246 return usedClassNames; 247 } 248 249 /** 250 * Gets version for this module. 251 * @param cp Array of constants 252 * @return version from constant pool, "0" if version index is 0 253 * @since 6.10.0 254 */ 255 public String getVersion(final ConstantPool cp) { 256 return moduleVersionIndex == 0 ? "0" : cp.getConstantString(moduleVersionIndex, Const.CONSTANT_Utf8); 257 } 258 259 /** 260 * @return String representation, i.e., a list of packages. 261 */ 262 @Override 263 public String toString() { 264 final ConstantPool cp = super.getConstantPool(); 265 final StringBuilder buf = new StringBuilder(); 266 buf.append("Module:\n"); 267 buf.append(" name: ").append(Utility.pathToPackage(getModuleName(cp))).append("\n"); 268 buf.append(" flags: ").append(String.format("%04x", moduleFlags)).append("\n"); 269 final String version = getVersion(cp); 270 buf.append(" version: ").append(version).append("\n"); 271 272 buf.append(" requires(").append(requiresTable.length).append("):\n"); 273 for (final ModuleRequires module : requiresTable) { 274 buf.append(" ").append(module.toString(cp)).append("\n"); 275 } 276 277 buf.append(" exports(").append(exportsTable.length).append("):\n"); 278 for (final ModuleExports module : exportsTable) { 279 buf.append(" ").append(module.toString(cp)).append("\n"); 280 } 281 282 buf.append(" opens(").append(opensTable.length).append("):\n"); 283 for (final ModuleOpens module : opensTable) { 284 buf.append(" ").append(module.toString(cp)).append("\n"); 285 } 286 287 buf.append(" uses(").append(usesIndex.length).append("):\n"); 288 for (final int index : usesIndex) { 289 final String className = getClassNameAtIndex(cp, index, true); 290 buf.append(" ").append(className).append("\n"); 291 } 292 293 buf.append(" provides(").append(providesTable.length).append("):\n"); 294 for (final ModuleProvides module : providesTable) { 295 buf.append(" ").append(module.toString(cp)).append("\n"); 296 } 297 298 return buf.substring(0, buf.length() - 1); // remove the last newline 299 } 300}