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.commons.lang3.ArrayUtils;
29  
30  /**
31   * This class represents a bootstrap method attribute, that is, the bootstrap method ref, the number of bootstrap arguments
32   * and an array of the bootstrap arguments.
33   *
34   * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
35   *      The BootstrapMethods Attribute</a>
36   * @since 6.0
37   */
38  public class BootstrapMethod implements Cloneable {
39  
40      static final BootstrapMethod[] EMPTY_ARRAY = {};
41  
42      /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */
43      private int bootstrapMethodRef;
44  
45      /** Array of references to the constant_pool table */
46      private int[] bootstrapArguments;
47  
48      /**
49       * Initialize from another object.
50       *
51       * @param c Source to copy.
52       */
53      public BootstrapMethod(final BootstrapMethod c) {
54          this(c.getBootstrapMethodRef(), c.getBootstrapArguments());
55      }
56  
57      /**
58       * Constructs object from input stream.
59       *
60       * @param input Input stream.
61       * @throws IOException if an I/O error occurs.
62       */
63      BootstrapMethod(final DataInput input) throws IOException {
64          this(input.readUnsignedShort(), input.readUnsignedShort());
65  
66          for (int i = 0; i < bootstrapArguments.length; i++) {
67              bootstrapArguments[i] = input.readUnsignedShort();
68          }
69      }
70  
71      // helper method
72      private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) {
73          this(bootstrapMethodRef, new int[numBootstrapArguments]);
74      }
75  
76      /**
77       * Constructs a BootstrapMethod.
78       *
79       * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle.
80       * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info.
81       */
82      public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) {
83          this.bootstrapMethodRef = bootstrapMethodRef;
84          setBootstrapArguments(bootstrapArguments);
85      }
86  
87      /**
88       * Creates a deep copy of this object.
89       *
90       * @return deep copy of this object.
91       */
92      public BootstrapMethod copy() {
93          try {
94              return (BootstrapMethod) clone();
95          } catch (final CloneNotSupportedException ignore) {
96              // TODO should this throw?
97          }
98          return null;
99      }
100 
101     /**
102      * Dumps object to file stream in binary format.
103      *
104      * @param file Output file stream.
105      * @throws IOException if an I/O error occurs.
106      */
107     public final void dump(final DataOutputStream file) throws IOException {
108         file.writeShort(bootstrapMethodRef);
109         file.writeShort(bootstrapArguments.length);
110         for (final int bootstrapArgument : bootstrapArguments) {
111             file.writeShort(bootstrapArgument);
112         }
113     }
114 
115     /**
116      * Gets the bootstrap arguments.
117      *
118      * @return int[] of bootstrap_method indices into constant_pool of CONSTANT_[type]_info.
119      */
120     public int[] getBootstrapArguments() {
121         return bootstrapArguments;
122     }
123 
124     /**
125      * Gets the bootstrap method reference.
126      *
127      * @return index into constant_pool of bootstrap_method.
128      */
129     public int getBootstrapMethodRef() {
130         return bootstrapMethodRef;
131     }
132 
133     /**
134      * Gets the count of number of bootstrap arguments.
135      *
136      * @return count of number of bootstrap arguments.
137      */
138     public int getNumBootstrapArguments() {
139         return bootstrapArguments.length;
140     }
141 
142     /**
143      * Sets the bootstrap arguments.
144      *
145      * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info.
146      */
147     public void setBootstrapArguments(final int[] bootstrapArguments) {
148         this.bootstrapArguments = ArrayUtils.nullToEmpty(bootstrapArguments);
149     }
150 
151     /**
152      * Sets the bootstrap method reference.
153      *
154      * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle.
155      */
156     public void setBootstrapMethodRef(final int bootstrapMethodRef) {
157         this.bootstrapMethodRef = bootstrapMethodRef;
158     }
159 
160     /**
161      * Gets a string representation.
162      *
163      * @return String representation.
164      */
165     @Override
166     public final String toString() {
167         return "BootstrapMethod(" + bootstrapMethodRef + ", " + bootstrapArguments.length + ", " + Arrays.toString(bootstrapArguments) + ")";
168     }
169 
170     /**
171      * Gets a resolved string representation.
172      *
173      * @param constantPool the constant pool.
174      * @return Resolved string representation.
175      */
176     public final String toString(final ConstantPool constantPool) {
177         final StringBuilder buf = new StringBuilder();
178         final String bootstrapMethodName = constantPool.constantToString(bootstrapMethodRef, Const.CONSTANT_MethodHandle);
179         buf.append(Utility.compactClassName(bootstrapMethodName, false));
180         final int bootstrapArgumentsLen = bootstrapArguments.length;
181         if (bootstrapArgumentsLen > 0) {
182             buf.append("\nMethod Arguments:");
183             for (int i = 0; i < bootstrapArgumentsLen; i++) {
184                 buf.append("\n  ").append(i).append(": ");
185                 buf.append(constantPool.constantToString(constantPool.getConstant(bootstrapArguments[i])));
186             }
187         }
188         return buf.toString();
189     }
190 }