ModulePackages.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. import org.apache.bcel.util.Args;
  24. import org.apache.commons.lang3.ArrayUtils;

  25. /**
  26.  * This class is derived from <em>Attribute</em> and represents the list of packages that are exported or opened by the
  27.  * Module attribute. There may be at most one ModulePackages attribute in a ClassFile structure.
  28.  *
  29.  * @see Attribute
  30.  */
  31. public final class ModulePackages extends Attribute {

  32.     private int[] packageIndexTable;

  33.     /**
  34.      * Constructs object from input stream.
  35.      *
  36.      * @param nameIndex Index in constant pool
  37.      * @param length Content length in bytes
  38.      * @param input Input stream
  39.      * @param constantPool Array of constants
  40.      * @throws IOException if an I/O error occurs.
  41.      */
  42.     ModulePackages(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
  43.         this(nameIndex, length, (int[]) null, constantPool);
  44.         final int packageCount = input.readUnsignedShort();
  45.         packageIndexTable = new int[packageCount];
  46.         for (int i = 0; i < packageCount; i++) {
  47.             packageIndexTable[i] = input.readUnsignedShort();
  48.         }
  49.     }

  50.     /**
  51.      * @param nameIndex Index in constant pool
  52.      * @param length Content length in bytes
  53.      * @param packageIndexTable Table of indices in constant pool
  54.      * @param constantPool Array of constants
  55.      */
  56.     public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) {
  57.         super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool);
  58.         this.packageIndexTable = ArrayUtils.nullToEmpty(packageIndexTable);
  59.         Args.requireU2(this.packageIndexTable.length, "packageIndexTable.length");
  60.     }

  61.     /**
  62.      * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
  63.      * physical copy.
  64.      *
  65.      * @param c Source to copy.
  66.      */
  67.     public ModulePackages(final ModulePackages c) {
  68.         this(c.getNameIndex(), c.getLength(), c.getPackageIndexTable(), c.getConstantPool());
  69.     }

  70.     /**
  71.      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
  72.      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
  73.      *
  74.      * @param v Visitor object
  75.      */
  76.     @Override
  77.     public void accept(final Visitor v) {
  78.         v.visitModulePackages(this);
  79.     }

  80.     /**
  81.      * @return deep copy of this attribute
  82.      */
  83.     @Override
  84.     public Attribute copy(final ConstantPool constantPool) {
  85.         final ModulePackages c = (ModulePackages) clone();
  86.         if (packageIndexTable != null) {
  87.             c.packageIndexTable = packageIndexTable.clone();
  88.         }
  89.         c.setConstantPool(constantPool);
  90.         return c;
  91.     }

  92.     /**
  93.      * Dump ModulePackages attribute to file stream in binary format.
  94.      *
  95.      * @param file Output file stream
  96.      * @throws IOException if an I/O error occurs.
  97.      */
  98.     @Override
  99.     public void dump(final DataOutputStream file) throws IOException {
  100.         super.dump(file);
  101.         file.writeShort(packageIndexTable.length);
  102.         for (final int index : packageIndexTable) {
  103.             file.writeShort(index);
  104.         }
  105.     }

  106.     /**
  107.      * @return Length of package table.
  108.      */
  109.     public int getNumberOfPackages() {
  110.         return packageIndexTable == null ? 0 : packageIndexTable.length;
  111.     }

  112.     /**
  113.      * @return array of indices into constant pool of package names.
  114.      */
  115.     public int[] getPackageIndexTable() {
  116.         return packageIndexTable;
  117.     }

  118.     /**
  119.      * @return string array of package names
  120.      */
  121.     public String[] getPackageNames() {
  122.         final String[] names = new String[packageIndexTable.length];
  123.         Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(packageIndexTable[i], Const.CONSTANT_Package)));
  124.         return names;
  125.     }

  126.     /**
  127.      * @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length.
  128.      */
  129.     public void setPackageIndexTable(final int[] packageIndexTable) {
  130.         this.packageIndexTable = ArrayUtils.nullToEmpty(packageIndexTable);
  131.     }

  132.     /**
  133.      * @return String representation, i.e., a list of packages.
  134.      */
  135.     @Override
  136.     public String toString() {
  137.         final StringBuilder buf = new StringBuilder();
  138.         buf.append("ModulePackages(");
  139.         buf.append(packageIndexTable.length);
  140.         buf.append("):\n");
  141.         for (final int index : packageIndexTable) {
  142.             final String packageName = super.getConstantPool().getConstantString(index, Const.CONSTANT_Package);
  143.             buf.append("  ").append(Utility.compactClassName(packageName, false)).append("\n");
  144.         }
  145.         return buf.substring(0, buf.length() - 1); // remove the last newline
  146.     }
  147. }