001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.bcel.classfile; 019 020import java.io.DataInput; 021import java.io.DataOutputStream; 022import java.io.IOException; 023import java.util.Arrays; 024 025import org.apache.bcel.Const; 026import org.apache.commons.lang3.ArrayUtils; 027 028/** 029 * This class represents a bootstrap method attribute, i.e., the bootstrap method ref, the number of bootstrap arguments 030 * and an array of the bootstrap arguments. 031 * 032 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format : 033 * The BootstrapMethods Attribute</a> 034 * @since 6.0 035 */ 036public class BootstrapMethod implements Cloneable { 037 038 static final BootstrapMethod[] EMPTY_ARRAY = {}; 039 040 /** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */ 041 private int bootstrapMethodRef; 042 043 /** Array of references to the constant_pool table */ 044 private int[] bootstrapArguments; 045 046 /** 047 * Initialize from another object. 048 * 049 * @param c Source to copy. 050 */ 051 public BootstrapMethod(final BootstrapMethod c) { 052 this(c.getBootstrapMethodRef(), c.getBootstrapArguments()); 053 } 054 055 /** 056 * Constructs object from input stream. 057 * 058 * @param input Input stream 059 * @throws IOException if an I/O error occurs. 060 */ 061 BootstrapMethod(final DataInput input) throws IOException { 062 this(input.readUnsignedShort(), input.readUnsignedShort()); 063 064 for (int i = 0; i < bootstrapArguments.length; i++) { 065 bootstrapArguments[i] = input.readUnsignedShort(); 066 } 067 } 068 069 // helper method 070 private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) { 071 this(bootstrapMethodRef, new int[numBootstrapArguments]); 072 } 073 074 /** 075 * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle 076 * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info 077 */ 078 public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) { 079 this.bootstrapMethodRef = bootstrapMethodRef; 080 setBootstrapArguments(bootstrapArguments); 081 } 082 083 /** 084 * @return deep copy of this object 085 */ 086 public BootstrapMethod copy() { 087 try { 088 return (BootstrapMethod) clone(); 089 } catch (final CloneNotSupportedException ignore) { 090 // TODO should this throw? 091 } 092 return null; 093 } 094 095 /** 096 * Dump object to file stream in binary format. 097 * 098 * @param file Output file stream 099 * @throws IOException if an I/O error occurs. 100 */ 101 public final void dump(final DataOutputStream file) throws IOException { 102 file.writeShort(bootstrapMethodRef); 103 file.writeShort(bootstrapArguments.length); 104 for (final int bootstrapArgument : bootstrapArguments) { 105 file.writeShort(bootstrapArgument); 106 } 107 } 108 109 /** 110 * @return int[] of bootstrap_method indices into constant_pool of CONSTANT_[type]_info 111 */ 112 public int[] getBootstrapArguments() { 113 return bootstrapArguments; 114 } 115 116 /** 117 * @return index into constant_pool of bootstrap_method 118 */ 119 public int getBootstrapMethodRef() { 120 return bootstrapMethodRef; 121 } 122 123 /** 124 * @return count of number of boostrap arguments 125 */ 126 public int getNumBootstrapArguments() { 127 return bootstrapArguments.length; 128 } 129 130 /** 131 * @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info 132 */ 133 public void setBootstrapArguments(final int[] bootstrapArguments) { 134 this.bootstrapArguments = ArrayUtils.nullToEmpty(bootstrapArguments); 135 } 136 137 /** 138 * @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle 139 */ 140 public void setBootstrapMethodRef(final int bootstrapMethodRef) { 141 this.bootstrapMethodRef = bootstrapMethodRef; 142 } 143 144 /** 145 * @return String representation. 146 */ 147 @Override 148 public final String toString() { 149 return "BootstrapMethod(" + bootstrapMethodRef + ", " + bootstrapArguments.length + ", " + Arrays.toString(bootstrapArguments) + ")"; 150 } 151 152 /** 153 * @return Resolved string representation 154 */ 155 public final String toString(final ConstantPool constantPool) { 156 final StringBuilder buf = new StringBuilder(); 157 final String bootstrapMethodName = constantPool.constantToString(bootstrapMethodRef, Const.CONSTANT_MethodHandle); 158 buf.append(Utility.compactClassName(bootstrapMethodName, false)); 159 final int bootstrapArgumentsLen = bootstrapArguments.length; 160 if (bootstrapArgumentsLen > 0) { 161 buf.append("\nMethod Arguments:"); 162 for (int i = 0; i < bootstrapArgumentsLen; i++) { 163 buf.append("\n ").append(i).append(": "); 164 buf.append(constantPool.constantToString(constantPool.getConstant(bootstrapArguments[i]))); 165 } 166 } 167 return buf.toString(); 168 } 169}