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, i.e., 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       * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
78       * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
79       */
80      public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) {
81          this.bootstrapMethodRef = bootstrapMethodRef;
82          setBootstrapArguments(bootstrapArguments);
83      }
84  
85      /**
86       * @return deep copy of this object
87       */
88      public BootstrapMethod copy() {
89          try {
90              return (BootstrapMethod) clone();
91          } catch (final CloneNotSupportedException ignore) {
92              // TODO should this throw?
93          }
94          return null;
95      }
96  
97      /**
98       * Dump object to file stream in binary format.
99       *
100      * @param file Output file stream
101      * @throws IOException if an I/O error occurs.
102      */
103     public final void dump(final DataOutputStream file) throws IOException {
104         file.writeShort(bootstrapMethodRef);
105         file.writeShort(bootstrapArguments.length);
106         for (final int bootstrapArgument : bootstrapArguments) {
107             file.writeShort(bootstrapArgument);
108         }
109     }
110 
111     /**
112      * @return int[] of bootstrap_method indices into constant_pool of CONSTANT_[type]_info
113      */
114     public int[] getBootstrapArguments() {
115         return bootstrapArguments;
116     }
117 
118     /**
119      * @return index into constant_pool of bootstrap_method
120      */
121     public int getBootstrapMethodRef() {
122         return bootstrapMethodRef;
123     }
124 
125     /**
126      * @return count of number of boostrap arguments
127      */
128     public int getNumBootstrapArguments() {
129         return bootstrapArguments.length;
130     }
131 
132     /**
133      * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
134      */
135     public void setBootstrapArguments(final int[] bootstrapArguments) {
136         this.bootstrapArguments = ArrayUtils.nullToEmpty(bootstrapArguments);
137     }
138 
139     /**
140      * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
141      */
142     public void setBootstrapMethodRef(final int bootstrapMethodRef) {
143         this.bootstrapMethodRef = bootstrapMethodRef;
144     }
145 
146     /**
147      * @return String representation.
148      */
149     @Override
150     public final String toString() {
151         return "BootstrapMethod(" + bootstrapMethodRef + ", " + bootstrapArguments.length + ", " + Arrays.toString(bootstrapArguments) + ")";
152     }
153 
154     /**
155      * @return Resolved string representation
156      */
157     public final String toString(final ConstantPool constantPool) {
158         final StringBuilder buf = new StringBuilder();
159         final String bootstrapMethodName = constantPool.constantToString(bootstrapMethodRef, Const.CONSTANT_MethodHandle);
160         buf.append(Utility.compactClassName(bootstrapMethodName, false));
161         final int bootstrapArgumentsLen = bootstrapArguments.length;
162         if (bootstrapArgumentsLen > 0) {
163             buf.append("\nMethod Arguments:");
164             for (int i = 0; i < bootstrapArgumentsLen; i++) {
165                 buf.append("\n  ").append(i).append(": ");
166                 buf.append(constantPool.constantToString(constantPool.getConstant(bootstrapArguments[i])));
167             }
168         }
169         return buf.toString();
170     }
171 }