Module.java

  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. package org.apache.bcel.classfile;

  18. import java.io.DataInput;
  19. import java.io.DataOutputStream;
  20. import java.io.IOException;
  21. import java.util.Arrays;

  22. import org.apache.bcel.Const;

  23. /**
  24.  * This class is derived from <em>Attribute</em> and represents the list of modules required, exported, opened or
  25.  * provided by a module. There may be at most one Module attribute in a ClassFile structure.
  26.  *
  27.  * @see Attribute
  28.  * @since 6.4.0
  29.  */
  30. public final class Module extends Attribute {

  31.     /**
  32.      * The module file name extension.
  33.      *
  34.      * @since 6.7.0
  35.      */
  36.     public static final String EXTENSION = ".jmod";

  37.     private static String getClassNameAtIndex(final ConstantPool cp, final int index, final boolean compactClassName) {
  38.         final String className = cp.getConstantString(index, Const.CONSTANT_Class);
  39.         if (compactClassName) {
  40.             return Utility.compactClassName(className, false);
  41.         }
  42.         return className;
  43.     }
  44.     private final int moduleNameIndex;
  45.     private final int moduleFlags;

  46.     private final int moduleVersionIndex;
  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.      * Constructs object from input stream.
  55.      *
  56.      * @param nameIndex Index in constant pool
  57.      * @param length Content length in bytes
  58.      * @param input Input stream
  59.      * @param constantPool Array of constants
  60.      * @throws IOException if an I/O error occurs.
  61.      */
  62.     Module(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
  63.         super(Const.ATTR_MODULE, nameIndex, length, constantPool);

  64.         moduleNameIndex = input.readUnsignedShort();
  65.         moduleFlags = input.readUnsignedShort();
  66.         moduleVersionIndex = input.readUnsignedShort();

  67.         final int requiresCount = input.readUnsignedShort();
  68.         requiresTable = new ModuleRequires[requiresCount];
  69.         for (int i = 0; i < requiresCount; i++) {
  70.             requiresTable[i] = new ModuleRequires(input);
  71.         }

  72.         final int exportsCount = input.readUnsignedShort();
  73.         exportsTable = new ModuleExports[exportsCount];
  74.         for (int i = 0; i < exportsCount; i++) {
  75.             exportsTable[i] = new ModuleExports(input);
  76.         }

  77.         final int opensCount = input.readUnsignedShort();
  78.         opensTable = new ModuleOpens[opensCount];
  79.         for (int i = 0; i < opensCount; i++) {
  80.             opensTable[i] = new ModuleOpens(input);
  81.         }

  82.         usesCount = input.readUnsignedShort();
  83.         usesIndex = new int[usesCount];
  84.         for (int i = 0; i < usesCount; i++) {
  85.             usesIndex[i] = input.readUnsignedShort();
  86.         }

  87.         final int providesCount = input.readUnsignedShort();
  88.         providesTable = new ModuleProvides[providesCount];
  89.         for (int i = 0; i < providesCount; i++) {
  90.             providesTable[i] = new ModuleProvides(input);
  91.         }
  92.     }

  93.     /**
  94.      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
  95.      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
  96.      *
  97.      * @param v Visitor object
  98.      */
  99.     @Override
  100.     public void accept(final Visitor v) {
  101.         v.visitModule(this);
  102.     }

  103.     /**
  104.      * @return deep copy of this attribute
  105.      */
  106.     @Override
  107.     public Attribute copy(final ConstantPool constantPool) {
  108.         final Module c = (Module) clone();

  109.         c.requiresTable = new ModuleRequires[requiresTable.length];
  110.         Arrays.setAll(c.requiresTable, i -> requiresTable[i].copy());

  111.         c.exportsTable = new ModuleExports[exportsTable.length];
  112.         Arrays.setAll(c.exportsTable, i -> exportsTable[i].copy());

  113.         c.opensTable = new ModuleOpens[opensTable.length];
  114.         Arrays.setAll(c.opensTable, i -> opensTable[i].copy());

  115.         c.providesTable = new ModuleProvides[providesTable.length];
  116.         Arrays.setAll(c.providesTable, i -> providesTable[i].copy());

  117.         c.setConstantPool(constantPool);
  118.         return c;
  119.     }

  120.     /**
  121.      * Dump Module attribute to file stream in binary format.
  122.      *
  123.      * @param file Output file stream
  124.      * @throws IOException if an I/O error occurs.
  125.      */
  126.     @Override
  127.     public void dump(final DataOutputStream file) throws IOException {
  128.         super.dump(file);

  129.         file.writeShort(moduleNameIndex);
  130.         file.writeShort(moduleFlags);
  131.         file.writeShort(moduleVersionIndex);

  132.         file.writeShort(requiresTable.length);
  133.         for (final ModuleRequires entry : requiresTable) {
  134.             entry.dump(file);
  135.         }

  136.         file.writeShort(exportsTable.length);
  137.         for (final ModuleExports entry : exportsTable) {
  138.             entry.dump(file);
  139.         }

  140.         file.writeShort(opensTable.length);
  141.         for (final ModuleOpens entry : opensTable) {
  142.             entry.dump(file);
  143.         }

  144.         file.writeShort(usesIndex.length);
  145.         for (final int entry : usesIndex) {
  146.             file.writeShort(entry);
  147.         }

  148.         file.writeShort(providesTable.length);
  149.         for (final ModuleProvides entry : providesTable) {
  150.             entry.dump(file);
  151.         }
  152.     }

  153.     /**
  154.      * @return table of exported interfaces
  155.      * @see ModuleExports
  156.      */
  157.     public ModuleExports[] getExportsTable() {
  158.         return exportsTable;
  159.     }

  160.     /**
  161.      * Gets flags for this module.
  162.      * @return module flags
  163.      * @since 6.10.0
  164.      */
  165.     public int getModuleFlags() {
  166.         return moduleFlags;
  167.     }

  168.     /**
  169.      * Gets module name.
  170.      * @param cp Array of constants
  171.      * @return module name
  172.      * @since 6.10.0
  173.      */
  174.     public String getModuleName(final ConstantPool cp) {
  175.         return cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module);
  176.     }

  177.     /**
  178.      * @return table of provided interfaces
  179.      * @see ModuleOpens
  180.      */
  181.     public ModuleOpens[] getOpensTable() {
  182.         return opensTable;
  183.     }

  184.     /**
  185.      * @return table of provided interfaces
  186.      * @see ModuleProvides
  187.      */
  188.     public ModuleProvides[] getProvidesTable() {
  189.         return providesTable;
  190.     }

  191.     /**
  192.      * @return table of required modules
  193.      * @see ModuleRequires
  194.      */
  195.     public ModuleRequires[] getRequiresTable() {
  196.         return requiresTable;
  197.     }

  198.     /**
  199.      * Gets the array of class names for this module's uses.
  200.      * @param constantPool Array of constants usually obtained from the ClassFile object
  201.      * @param compactClassName false for original constant pool value, true to replace '/' with '.'
  202.      * @return array of used class names
  203.      * @since 6.10.0
  204.      */
  205.     public String[] getUsedClassNames(final ConstantPool constantPool, final boolean compactClassName) {
  206.         final String[] usedClassNames = new String[usesCount];
  207.         for (int i = 0; i < usesCount; i++) {
  208.             usedClassNames[i] = getClassNameAtIndex(constantPool, usesIndex[i], compactClassName);
  209.         }
  210.         return usedClassNames;
  211.     }

  212.     /**
  213.      * Gets version for this module.
  214.      * @param cp Array of constants
  215.      * @return version from constant pool, "0" if version index is 0
  216.      * @since 6.10.0
  217.      */
  218.     public String getVersion(final ConstantPool cp) {
  219.         return moduleVersionIndex == 0 ? "0" : cp.getConstantString(moduleVersionIndex, Const.CONSTANT_Utf8);
  220.     }

  221.     /**
  222.      * @return String representation, i.e., a list of packages.
  223.      */
  224.     @Override
  225.     public String toString() {
  226.         final ConstantPool cp = super.getConstantPool();
  227.         final StringBuilder buf = new StringBuilder();
  228.         buf.append("Module:\n");
  229.         buf.append("  name:    ").append(Utility.pathToPackage(getModuleName(cp))).append("\n");
  230.         buf.append("  flags:   ").append(String.format("%04x", moduleFlags)).append("\n");
  231.         final String version = getVersion(cp);
  232.         buf.append("  version: ").append(version).append("\n");

  233.         buf.append("  requires(").append(requiresTable.length).append("):\n");
  234.         for (final ModuleRequires module : requiresTable) {
  235.             buf.append("    ").append(module.toString(cp)).append("\n");
  236.         }

  237.         buf.append("  exports(").append(exportsTable.length).append("):\n");
  238.         for (final ModuleExports module : exportsTable) {
  239.             buf.append("    ").append(module.toString(cp)).append("\n");
  240.         }

  241.         buf.append("  opens(").append(opensTable.length).append("):\n");
  242.         for (final ModuleOpens module : opensTable) {
  243.             buf.append("    ").append(module.toString(cp)).append("\n");
  244.         }

  245.         buf.append("  uses(").append(usesIndex.length).append("):\n");
  246.         for (final int index : usesIndex) {
  247.             final String className = getClassNameAtIndex(cp, index, true);
  248.             buf.append("    ").append(className).append("\n");
  249.         }

  250.         buf.append("  provides(").append(providesTable.length).append("):\n");
  251.         for (final ModuleProvides module : providesTable) {
  252.             buf.append("    ").append(module.toString(cp)).append("\n");
  253.         }

  254.         return buf.substring(0, buf.length() - 1); // remove the last newline
  255.     }
  256. }