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 }