BootstrapMethods.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.Iterator;
  22. import java.util.stream.Stream;

  23. import org.apache.bcel.Const;

  24. /**
  25.  * This class represents a BootstrapMethods attribute.
  26.  *
  27.  * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
  28.  *      The BootstrapMethods Attribute</a>
  29.  * @since 6.0
  30.  */
  31. public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> {

  32.     private BootstrapMethod[] bootstrapMethods; // TODO this could be made final (setter is not used)

  33.     /**
  34.      * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
  35.      * physical copy.
  36.      *
  37.      * @param c Source to copy.
  38.      */
  39.     public BootstrapMethods(final BootstrapMethods c) {
  40.         this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool());
  41.     }

  42.     /**
  43.      * @param nameIndex Index in constant pool to CONSTANT_Utf8
  44.      * @param length Content length in bytes
  45.      * @param bootstrapMethods array of bootstrap methods
  46.      * @param constantPool Array of constants
  47.      */
  48.     public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) {
  49.         super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool);
  50.         setBootstrapMethods(bootstrapMethods);
  51.     }

  52.     /**
  53.      * Constructs object from Input stream.
  54.      *
  55.      * @param nameIndex Index in constant pool to CONSTANT_Utf8
  56.      * @param length Content length in bytes
  57.      * @param input Input stream
  58.      * @param constantPool Array of constants
  59.      * @throws IOException if an I/O error occurs.
  60.      */
  61.     BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
  62.         this(nameIndex, length, (BootstrapMethod[]) null, constantPool);

  63.         final int numBootstrapMethods = input.readUnsignedShort();
  64.         bootstrapMethods = new BootstrapMethod[numBootstrapMethods];
  65.         for (int i = 0; i < numBootstrapMethods; i++) {
  66.             bootstrapMethods[i] = new BootstrapMethod(input);
  67.         }
  68.     }

  69.     /**
  70.      * @param v Visitor object
  71.      */
  72.     @Override
  73.     public void accept(final Visitor v) {
  74.         v.visitBootstrapMethods(this);
  75.     }

  76.     /**
  77.      * @return deep copy of this attribute
  78.      */
  79.     @Override
  80.     public BootstrapMethods copy(final ConstantPool constantPool) {
  81.         final BootstrapMethods c = (BootstrapMethods) clone();
  82.         c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length];

  83.         for (int i = 0; i < bootstrapMethods.length; i++) {
  84.             c.bootstrapMethods[i] = bootstrapMethods[i].copy();
  85.         }
  86.         c.setConstantPool(constantPool);
  87.         return c;
  88.     }

  89.     /**
  90.      * Dump bootstrap methods attribute to file stream in binary format.
  91.      *
  92.      * @param file Output file stream
  93.      * @throws IOException if an I/O error occurs.
  94.      */
  95.     @Override
  96.     public final void dump(final DataOutputStream file) throws IOException {
  97.         super.dump(file);

  98.         file.writeShort(bootstrapMethods.length);
  99.         for (final BootstrapMethod bootstrapMethod : bootstrapMethods) {
  100.             bootstrapMethod.dump(file);
  101.         }
  102.     }

  103.     /**
  104.      * @return array of bootstrap method "records"
  105.      */
  106.     public final BootstrapMethod[] getBootstrapMethods() {
  107.         return bootstrapMethods;
  108.     }

  109.     @Override
  110.     public Iterator<BootstrapMethod> iterator() {
  111.         return Stream.of(bootstrapMethods).iterator();
  112.     }

  113.     /**
  114.      * @param bootstrapMethods the array of bootstrap methods
  115.      */
  116.     public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) {
  117.         this.bootstrapMethods = bootstrapMethods != null ? bootstrapMethods : BootstrapMethod.EMPTY_ARRAY;
  118.     }

  119.     /**
  120.      * @return String representation.
  121.      */
  122.     @Override
  123.     public final String toString() {
  124.         final StringBuilder buf = new StringBuilder();
  125.         buf.append("BootstrapMethods(");
  126.         buf.append(bootstrapMethods.length);
  127.         buf.append("):");
  128.         for (int i = 0; i < bootstrapMethods.length; i++) {
  129.             buf.append("\n");
  130.             final int start = buf.length();
  131.             buf.append("  ").append(i).append(": ");
  132.             final int indentCount = buf.length() - start;
  133.             final String[] lines = bootstrapMethods[i].toString(super.getConstantPool()).split("\\r?\\n");
  134.             buf.append(lines[0]);
  135.             for (int j = 1; j < lines.length; j++) {
  136.                 buf.append("\n").append("          ", 0, indentCount).append(lines[j]);
  137.             }
  138.         }
  139.         return buf.toString();
  140.     }
  141. }