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