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.commons.lang3.ArrayUtils; 029 030/** 031 * This class represents a bootstrap method attribute, i.e., the bootstrap method ref, the number of bootstrap arguments 032 * and an array of the bootstrap arguments. 033 * 034 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format : 035 * The BootstrapMethods Attribute</a> 036 * @since 6.0 037 */ 038public class BootstrapMethod implements Cloneable { 039 040 static final BootstrapMethod[] EMPTY_ARRAY = {}; 041 042 /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */ 043 private int bootstrapMethodRef; 044 045 /** Array of references to the constant_pool table */ 046 private int[] bootstrapArguments; 047 048 /** 049 * Initialize from another object. 050 * 051 * @param c Source to copy. 052 */ 053 public BootstrapMethod(final BootstrapMethod c) { 054 this(c.getBootstrapMethodRef(), c.getBootstrapArguments()); 055 } 056 057 /** 058 * Constructs object from input stream. 059 * 060 * @param input Input stream 061 * @throws IOException if an I/O error occurs. 062 */ 063 BootstrapMethod(final DataInput input) throws IOException { 064 this(input.readUnsignedShort(), input.readUnsignedShort()); 065 066 for (int i = 0; i < bootstrapArguments.length; i++) { 067 bootstrapArguments[i] = input.readUnsignedShort(); 068 } 069 } 070 071 // helper method 072 private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) { 073 this(bootstrapMethodRef, new int[numBootstrapArguments]); 074 } 075 076 /** 077 * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle 078 * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info 079 */ 080 public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) { 081 this.bootstrapMethodRef = bootstrapMethodRef; 082 setBootstrapArguments(bootstrapArguments); 083 } 084 085 /** 086 * @return deep copy of this object 087 */ 088 public BootstrapMethod copy() { 089 try { 090 return (BootstrapMethod) clone(); 091 } catch (final CloneNotSupportedException ignore) { 092 // TODO should this throw? 093 } 094 return null; 095 } 096 097 /** 098 * Dump object to file stream in binary format. 099 * 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}