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 private final int moduleNameIndex; 037 private final int moduleFlags; 038 private final int moduleVersionIndex; 039 040 private ModuleRequires[] requiresTable; 041 private ModuleExports[] exportsTable; 042 private ModuleOpens[] opensTable; 043 private final int usesCount; 044 private final int[] usesIndex; 045 private ModuleProvides[] providesTable; 046 047 /** 048 * Construct object from input stream. 049 * 050 * @param nameIndex Index in constant pool 051 * @param length Content length in bytes 052 * @param input Input stream 053 * @param constantPool Array of constants 054 * @throws IOException if an I/O error occurs. 055 */ 056 Module(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { 057 super(Const.ATTR_MODULE, nameIndex, length, constantPool); 058 059 moduleNameIndex = input.readUnsignedShort(); 060 moduleFlags = input.readUnsignedShort(); 061 moduleVersionIndex = input.readUnsignedShort(); 062 063 final int requiresCount = input.readUnsignedShort(); 064 requiresTable = new ModuleRequires[requiresCount]; 065 for (int i = 0; i < requiresCount; i++) { 066 requiresTable[i] = new ModuleRequires(input); 067 } 068 069 final int exportsCount = input.readUnsignedShort(); 070 exportsTable = new ModuleExports[exportsCount]; 071 for (int i = 0; i < exportsCount; i++) { 072 exportsTable[i] = new ModuleExports(input); 073 } 074 075 final int opensCount = input.readUnsignedShort(); 076 opensTable = new ModuleOpens[opensCount]; 077 for (int i = 0; i < opensCount; i++) { 078 opensTable[i] = new ModuleOpens(input); 079 } 080 081 usesCount = input.readUnsignedShort(); 082 usesIndex = new int[usesCount]; 083 for (int i = 0; i < usesCount; i++) { 084 usesIndex[i] = input.readUnsignedShort(); 085 } 086 087 final int providesCount = input.readUnsignedShort(); 088 providesTable = new ModuleProvides[providesCount]; 089 for (int i = 0; i < providesCount; i++) { 090 providesTable[i] = new ModuleProvides(input); 091 } 092 } 093 094 /** 095 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 096 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 097 * 098 * @param v Visitor object 099 */ 100 @Override 101 public void accept(final Visitor v) { 102 v.visitModule(this); 103 } 104 105 // TODO add more getters and setters? 106 107 /** 108 * @return deep copy of this attribute 109 */ 110 @Override 111 public Attribute copy(final ConstantPool constantPool) { 112 final Module c = (Module) clone(); 113 114 c.requiresTable = new ModuleRequires[requiresTable.length]; 115 Arrays.setAll(c.requiresTable, i -> requiresTable[i].copy()); 116 117 c.exportsTable = new ModuleExports[exportsTable.length]; 118 Arrays.setAll(c.exportsTable, i -> exportsTable[i].copy()); 119 120 c.opensTable = new ModuleOpens[opensTable.length]; 121 Arrays.setAll(c.opensTable, i -> opensTable[i].copy()); 122 123 c.providesTable = new ModuleProvides[providesTable.length]; 124 Arrays.setAll(c.providesTable, i -> providesTable[i].copy()); 125 126 c.setConstantPool(constantPool); 127 return c; 128 } 129 130 /** 131 * Dump Module attribute to file stream in binary format. 132 * 133 * @param file Output file stream 134 * @throws IOException if an I/O error occurs. 135 */ 136 @Override 137 public void dump(final DataOutputStream file) throws IOException { 138 super.dump(file); 139 140 file.writeShort(moduleNameIndex); 141 file.writeShort(moduleFlags); 142 file.writeShort(moduleVersionIndex); 143 144 file.writeShort(requiresTable.length); 145 for (final ModuleRequires entry : requiresTable) { 146 entry.dump(file); 147 } 148 149 file.writeShort(exportsTable.length); 150 for (final ModuleExports entry : exportsTable) { 151 entry.dump(file); 152 } 153 154 file.writeShort(opensTable.length); 155 for (final ModuleOpens entry : opensTable) { 156 entry.dump(file); 157 } 158 159 file.writeShort(usesIndex.length); 160 for (final int entry : usesIndex) { 161 file.writeShort(entry); 162 } 163 164 file.writeShort(providesTable.length); 165 for (final ModuleProvides entry : providesTable) { 166 entry.dump(file); 167 } 168 } 169 170 /** 171 * @return table of exported interfaces 172 * @see ModuleExports 173 */ 174 public ModuleExports[] getExportsTable() { 175 return exportsTable; 176 } 177 178 /** 179 * @return table of provided interfaces 180 * @see ModuleOpens 181 */ 182 public ModuleOpens[] getOpensTable() { 183 return opensTable; 184 } 185 186 /** 187 * @return table of provided interfaces 188 * @see ModuleProvides 189 */ 190 public ModuleProvides[] getProvidesTable() { 191 return providesTable; 192 } 193 194 /** 195 * @return table of required modules 196 * @see ModuleRequires 197 */ 198 public ModuleRequires[] getRequiresTable() { 199 return requiresTable; 200 } 201 202 /** 203 * @return String representation, i.e., a list of packages. 204 */ 205 @Override 206 public String toString() { 207 final ConstantPool cp = super.getConstantPool(); 208 final StringBuilder buf = new StringBuilder(); 209 buf.append("Module:\n"); 210 buf.append(" name: ").append(Utility.pathToPackage(cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module))).append("\n"); 211 buf.append(" flags: ").append(String.format("%04x", moduleFlags)).append("\n"); 212 final String version = moduleVersionIndex == 0 ? "0" : cp.getConstantString(moduleVersionIndex, Const.CONSTANT_Utf8); 213 buf.append(" version: ").append(version).append("\n"); 214 215 buf.append(" requires(").append(requiresTable.length).append("):\n"); 216 for (final ModuleRequires module : requiresTable) { 217 buf.append(" ").append(module.toString(cp)).append("\n"); 218 } 219 220 buf.append(" exports(").append(exportsTable.length).append("):\n"); 221 for (final ModuleExports module : exportsTable) { 222 buf.append(" ").append(module.toString(cp)).append("\n"); 223 } 224 225 buf.append(" opens(").append(opensTable.length).append("):\n"); 226 for (final ModuleOpens module : opensTable) { 227 buf.append(" ").append(module.toString(cp)).append("\n"); 228 } 229 230 buf.append(" uses(").append(usesIndex.length).append("):\n"); 231 for (final int index : usesIndex) { 232 final String className = cp.getConstantString(index, Const.CONSTANT_Class); 233 buf.append(" ").append(Utility.compactClassName(className, false)).append("\n"); 234 } 235 236 buf.append(" provides(").append(providesTable.length).append("):\n"); 237 for (final ModuleProvides module : providesTable) { 238 buf.append(" ").append(module.toString(cp)).append("\n"); 239 } 240 241 return buf.substring(0, buf.length() - 1); // remove the last newline 242 } 243}