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 final int moduleNameIndex; 044 private final int moduleFlags; 045 private final int moduleVersionIndex; 046 047 private ModuleRequires[] requiresTable; 048 private ModuleExports[] exportsTable; 049 private ModuleOpens[] opensTable; 050 private final int usesCount; 051 private final int[] usesIndex; 052 private ModuleProvides[] providesTable; 053 054 /** 055 * Constructs object from input stream. 056 * 057 * @param nameIndex Index in constant pool 058 * @param length Content length in bytes 059 * @param input Input stream 060 * @param constantPool Array of constants 061 * @throws IOException if an I/O error occurs. 062 */ 063 Module(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { 064 super(Const.ATTR_MODULE, nameIndex, length, constantPool); 065 066 moduleNameIndex = input.readUnsignedShort(); 067 moduleFlags = input.readUnsignedShort(); 068 moduleVersionIndex = input.readUnsignedShort(); 069 070 final int requiresCount = input.readUnsignedShort(); 071 requiresTable = new ModuleRequires[requiresCount]; 072 for (int i = 0; i < requiresCount; i++) { 073 requiresTable[i] = new ModuleRequires(input); 074 } 075 076 final int exportsCount = input.readUnsignedShort(); 077 exportsTable = new ModuleExports[exportsCount]; 078 for (int i = 0; i < exportsCount; i++) { 079 exportsTable[i] = new ModuleExports(input); 080 } 081 082 final int opensCount = input.readUnsignedShort(); 083 opensTable = new ModuleOpens[opensCount]; 084 for (int i = 0; i < opensCount; i++) { 085 opensTable[i] = new ModuleOpens(input); 086 } 087 088 usesCount = input.readUnsignedShort(); 089 usesIndex = new int[usesCount]; 090 for (int i = 0; i < usesCount; i++) { 091 usesIndex[i] = input.readUnsignedShort(); 092 } 093 094 final int providesCount = input.readUnsignedShort(); 095 providesTable = new ModuleProvides[providesCount]; 096 for (int i = 0; i < providesCount; i++) { 097 providesTable[i] = new ModuleProvides(input); 098 } 099 } 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}