BootstrapMethod.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.commons.lang3.ArrayUtils;

  24. /**
  25.  * This class represents a bootstrap method attribute, i.e., the bootstrap method ref, the number of bootstrap arguments
  26.  * and an array of the bootstrap arguments.
  27.  *
  28.  * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
  29.  *      The BootstrapMethods Attribute</a>
  30.  * @since 6.0
  31.  */
  32. public class BootstrapMethod implements Cloneable {

  33.     static final BootstrapMethod[] EMPTY_ARRAY = {};

  34.     /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */
  35.     private int bootstrapMethodRef;

  36.     /** Array of references to the constant_pool table */
  37.     private int[] bootstrapArguments;

  38.     /**
  39.      * Initialize from another object.
  40.      *
  41.      * @param c Source to copy.
  42.      */
  43.     public BootstrapMethod(final BootstrapMethod c) {
  44.         this(c.getBootstrapMethodRef(), c.getBootstrapArguments());
  45.     }

  46.     /**
  47.      * Constructs object from input stream.
  48.      *
  49.      * @param input Input stream
  50.      * @throws IOException if an I/O error occurs.
  51.      */
  52.     BootstrapMethod(final DataInput input) throws IOException {
  53.         this(input.readUnsignedShort(), input.readUnsignedShort());

  54.         for (int i = 0; i < bootstrapArguments.length; i++) {
  55.             bootstrapArguments[i] = input.readUnsignedShort();
  56.         }
  57.     }

  58.     // helper method
  59.     private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) {
  60.         this(bootstrapMethodRef, new int[numBootstrapArguments]);
  61.     }

  62.     /**
  63.      * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
  64.      * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
  65.      */
  66.     public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) {
  67.         this.bootstrapMethodRef = bootstrapMethodRef;
  68.         setBootstrapArguments(bootstrapArguments);
  69.     }

  70.     /**
  71.      * @return deep copy of this object
  72.      */
  73.     public BootstrapMethod copy() {
  74.         try {
  75.             return (BootstrapMethod) clone();
  76.         } catch (final CloneNotSupportedException ignore) {
  77.             // TODO should this throw?
  78.         }
  79.         return null;
  80.     }

  81.     /**
  82.      * Dump object to file stream in binary format.
  83.      *
  84.      * @param file Output file stream
  85.      * @throws IOException if an I/O error occurs.
  86.      */
  87.     public final void dump(final DataOutputStream file) throws IOException {
  88.         file.writeShort(bootstrapMethodRef);
  89.         file.writeShort(bootstrapArguments.length);
  90.         for (final int bootstrapArgument : bootstrapArguments) {
  91.             file.writeShort(bootstrapArgument);
  92.         }
  93.     }

  94.     /**
  95.      * @return int[] of bootstrap_method indices into constant_pool of CONSTANT_[type]_info
  96.      */
  97.     public int[] getBootstrapArguments() {
  98.         return bootstrapArguments;
  99.     }

  100.     /**
  101.      * @return index into constant_pool of bootstrap_method
  102.      */
  103.     public int getBootstrapMethodRef() {
  104.         return bootstrapMethodRef;
  105.     }

  106.     /**
  107.      * @return count of number of boostrap arguments
  108.      */
  109.     public int getNumBootstrapArguments() {
  110.         return bootstrapArguments.length;
  111.     }

  112.     /**
  113.      * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
  114.      */
  115.     public void setBootstrapArguments(final int[] bootstrapArguments) {
  116.         this.bootstrapArguments = ArrayUtils.nullToEmpty(bootstrapArguments);
  117.     }

  118.     /**
  119.      * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
  120.      */
  121.     public void setBootstrapMethodRef(final int bootstrapMethodRef) {
  122.         this.bootstrapMethodRef = bootstrapMethodRef;
  123.     }

  124.     /**
  125.      * @return String representation.
  126.      */
  127.     @Override
  128.     public final String toString() {
  129.         return "BootstrapMethod(" + bootstrapMethodRef + ", " + bootstrapArguments.length + ", " + Arrays.toString(bootstrapArguments) + ")";
  130.     }

  131.     /**
  132.      * @return Resolved string representation
  133.      */
  134.     public final String toString(final ConstantPool constantPool) {
  135.         final StringBuilder buf = new StringBuilder();
  136.         final String bootstrapMethodName = constantPool.constantToString(bootstrapMethodRef, Const.CONSTANT_MethodHandle);
  137.         buf.append(Utility.compactClassName(bootstrapMethodName, false));
  138.         final int bootstrapArgumentsLen = bootstrapArguments.length;
  139.         if (bootstrapArgumentsLen > 0) {
  140.             buf.append("\nMethod Arguments:");
  141.             for (int i = 0; i < bootstrapArgumentsLen; i++) {
  142.                 buf.append("\n  ").append(i).append(": ");
  143.                 buf.append(constantPool.constantToString(constantPool.getConstant(bootstrapArguments[i])));
  144.             }
  145.         }
  146.         return buf.toString();
  147.     }
  148. }