View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.bcel.classfile;
21  
22  import java.io.DataInput;
23  import java.io.DataOutputStream;
24  import java.io.IOException;
25  import java.util.Arrays;
26  
27  import org.apache.bcel.Const;
28  import org.apache.bcel.util.Args;
29  import org.apache.commons.lang3.ArrayUtils;
30  
31  /**
32   * This class represents a bootstrap method attribute, that is, the bootstrap method ref, the number of bootstrap arguments
33   * and an array of the bootstrap arguments.
34   *
35   * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
36   *      The BootstrapMethods Attribute</a>
37   * @since 6.0
38   */
39  public class BootstrapMethod implements Cloneable {
40  
41      static final BootstrapMethod[] EMPTY_ARRAY = {};
42  
43      /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */
44      private int bootstrapMethodRef;
45  
46      /** Array of references to the constant_pool table */
47      private int[] bootstrapArguments;
48  
49      /**
50       * Initialize from another object.
51       *
52       * @param c Source to copy.
53       */
54      public BootstrapMethod(final BootstrapMethod c) {
55          this(c.getBootstrapMethodRef(), c.getBootstrapArguments().clone());
56      }
57  
58      /**
59       * Constructs object from input stream.
60       *
61       * @param input Input stream.
62       * @throws IOException Thrown if an I/O error occurs.
63       */
64      BootstrapMethod(final DataInput input) throws IOException {
65          this(input.readUnsignedShort(), input.readUnsignedShort());
66  
67          for (int i = 0; i < bootstrapArguments.length; i++) {
68              bootstrapArguments[i] = input.readUnsignedShort();
69          }
70      }
71  
72      // helper method
73      private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) {
74          this(bootstrapMethodRef, new int[numBootstrapArguments]);
75      }
76  
77      /**
78       * Constructs a BootstrapMethod.
79       *
80       * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle.
81       * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info.
82       */
83      public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) {
84          this.bootstrapMethodRef = bootstrapMethodRef;
85          setBootstrapArguments(bootstrapArguments);
86      }
87  
88      /**
89       * Creates a deep copy of this object.
90       *
91       * @return deep copy of this object.
92       */
93      public BootstrapMethod copy() {
94          try {
95              final BootstrapMethod c = (BootstrapMethod) clone();
96              c.bootstrapArguments = bootstrapArguments.clone();
97              return c;
98          } catch (final CloneNotSupportedException ignore) {
99              // TODO should this throw?
100         }
101         return null;
102     }
103 
104     /**
105      * Dumps object to file stream in binary format.
106      *
107      * @param file Output file stream.
108      * @throws IOException Thrown if an I/O error occurs.
109      */
110     public final void dump(final DataOutputStream file) throws IOException {
111         file.writeShort(bootstrapMethodRef);
112         file.writeShort(Args.requireU2(bootstrapArguments.length, "bootstrapArguments.length"));
113         for (final int bootstrapArgument : bootstrapArguments) {
114             file.writeShort(bootstrapArgument);
115         }
116     }
117 
118     /**
119      * Gets the bootstrap arguments.
120      *
121      * @return int[] of bootstrap_method indices into constant_pool of CONSTANT_[type]_info.
122      */
123     public int[] getBootstrapArguments() {
124         return bootstrapArguments;
125     }
126 
127     /**
128      * Gets the bootstrap method reference.
129      *
130      * @return index into constant_pool of bootstrap_method.
131      */
132     public int getBootstrapMethodRef() {
133         return bootstrapMethodRef;
134     }
135 
136     /**
137      * Gets the count of number of bootstrap arguments.
138      *
139      * @return count of number of bootstrap arguments.
140      */
141     public int getNumBootstrapArguments() {
142         return bootstrapArguments.length;
143     }
144 
145     /**
146      * Sets the bootstrap arguments.
147      *
148      * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info.
149      */
150     public void setBootstrapArguments(final int[] bootstrapArguments) {
151         this.bootstrapArguments = ArrayUtils.nullToEmpty(bootstrapArguments);
152     }
153 
154     /**
155      * Sets the bootstrap method reference.
156      *
157      * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle.
158      */
159     public void setBootstrapMethodRef(final int bootstrapMethodRef) {
160         this.bootstrapMethodRef = bootstrapMethodRef;
161     }
162 
163     /**
164      * Gets a string representation.
165      *
166      * @return String representation.
167      */
168     @Override
169     public final String toString() {
170         return "BootstrapMethod(" + bootstrapMethodRef + ", " + bootstrapArguments.length + ", " + Arrays.toString(bootstrapArguments) + ")";
171     }
172 
173     /**
174      * Gets a resolved string representation.
175      *
176      * @param constantPool The constant pool.
177      * @return Resolved string representation.
178      */
179     public final String toString(final ConstantPool constantPool) {
180         final StringBuilder buf = new StringBuilder();
181         final String bootstrapMethodName = constantPool.constantToString(bootstrapMethodRef, Const.CONSTANT_MethodHandle);
182         buf.append(Utility.compactClassName(bootstrapMethodName, false));
183         final int bootstrapArgumentsLen = bootstrapArguments.length;
184         if (bootstrapArgumentsLen > 0) {
185             buf.append("\nMethod Arguments:");
186             for (int i = 0; i < bootstrapArgumentsLen; i++) {
187                 buf.append("\n  ").append(i).append(": ");
188                 buf.append(constantPool.constantToString(constantPool.getConstant(bootstrapArguments[i])));
189             }
190         }
191         return buf.toString();
192     }
193 }