001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.bcel.classfile; 021 022import java.io.DataInput; 023import java.io.DataOutputStream; 024import java.io.IOException; 025import java.util.Arrays; 026 027import org.apache.bcel.Const; 028import org.apache.bcel.util.Args; 029import org.apache.commons.lang3.ArrayUtils; 030 031/** 032 * This class represents a bootstrap method attribute, that is, the bootstrap method ref, the number of bootstrap arguments 033 * and an array of the bootstrap arguments. 034 * 035 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format : 036 * The BootstrapMethods Attribute</a> 037 * @since 6.0 038 */ 039public class BootstrapMethod implements Cloneable { 040 041 static final BootstrapMethod[] EMPTY_ARRAY = {}; 042 043 /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */ 044 private int bootstrapMethodRef; 045 046 /** Array of references to the constant_pool table */ 047 private int[] bootstrapArguments; 048 049 /** 050 * Initialize from another object. 051 * 052 * @param c Source to copy. 053 */ 054 public BootstrapMethod(final BootstrapMethod c) { 055 this(c.getBootstrapMethodRef(), c.getBootstrapArguments().clone()); 056 } 057 058 /** 059 * Constructs object from input stream. 060 * 061 * @param input Input stream. 062 * @throws IOException Thrown if an I/O error occurs. 063 */ 064 BootstrapMethod(final DataInput input) throws IOException { 065 this(input.readUnsignedShort(), input.readUnsignedShort()); 066 067 for (int i = 0; i < bootstrapArguments.length; i++) { 068 bootstrapArguments[i] = input.readUnsignedShort(); 069 } 070 } 071 072 // helper method 073 private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) { 074 this(bootstrapMethodRef, new int[numBootstrapArguments]); 075 } 076 077 /** 078 * Constructs a BootstrapMethod. 079 * 080 * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle. 081 * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info. 082 */ 083 public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) { 084 this.bootstrapMethodRef = bootstrapMethodRef; 085 setBootstrapArguments(bootstrapArguments); 086 } 087 088 /** 089 * Creates a deep copy of this object. 090 * 091 * @return deep copy of this object. 092 */ 093 public BootstrapMethod copy() { 094 try { 095 final BootstrapMethod c = (BootstrapMethod) clone(); 096 c.bootstrapArguments = bootstrapArguments.clone(); 097 return c; 098 } catch (final CloneNotSupportedException ignore) { 099 // 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}