NestMembers.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 records the classes and interfaces that are authorized to claim
  27.  * membership in the nest hosted by the current class or interface. There may be at most one NestMembers attribute in a
  28.  * ClassFile structure.
  29.  *
  30.  * @see Attribute
  31.  */
  32. public final class NestMembers extends Attribute {

  33.     private int[] classes;

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

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

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

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

  81.     /**
  82.      * @return deep copy of this attribute
  83.      */
  84.     @Override
  85.     public Attribute copy(final ConstantPool constantPool) {
  86.         final NestMembers c = (NestMembers) clone();
  87.         if (classes.length > 0) {
  88.             c.classes = classes.clone();
  89.         }
  90.         c.setConstantPool(constantPool);
  91.         return c;
  92.     }

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

  107.     /**
  108.      * @return array of indices into constant pool of class names.
  109.      */
  110.     public int[] getClasses() {
  111.         return classes;
  112.     }

  113.     /**
  114.      * @return string array of class names
  115.      */
  116.     public String[] getClassNames() {
  117.         final String[] names = new String[classes.length];
  118.         Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(classes[i], Const.CONSTANT_Class)));
  119.         return names;
  120.     }

  121.     /**
  122.      * @return Length of classes table.
  123.      */
  124.     public int getNumberClasses() {
  125.         return classes.length;
  126.     }

  127.     /**
  128.      * @param classes the list of class indexes Also redefines number_of_classes according to table length.
  129.      */
  130.     public void setClasses(final int[] classes) {
  131.         this.classes = ArrayUtils.nullToEmpty(classes);
  132.     }

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