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.Iterator; 024import java.util.stream.Stream; 025 026import org.apache.bcel.Const; 027 028/** 029 * This class represents a BootstrapMethods attribute. 030 * 031 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format : 032 * The BootstrapMethods Attribute</a> 033 * @since 6.0 034 */ 035public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> { 036 037 private BootstrapMethod[] bootstrapMethods; // TODO this could be made final (setter is not used) 038 039 /** 040 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 041 * physical copy. 042 * 043 * @param c Source to copy. 044 */ 045 public BootstrapMethods(final BootstrapMethods c) { 046 this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool()); 047 } 048 049 /** 050 * @param nameIndex Index in constant pool to CONSTANT_Utf8 051 * @param length Content length in bytes 052 * @param bootstrapMethods array of bootstrap methods 053 * @param constantPool Array of constants 054 */ 055 public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) { 056 super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool); 057 setBootstrapMethods(bootstrapMethods); 058 } 059 060 /** 061 * Constructs object from Input stream. 062 * 063 * @param nameIndex Index in constant pool to CONSTANT_Utf8 064 * @param length Content length in bytes 065 * @param input Input stream 066 * @param constantPool Array of constants 067 * @throws IOException if an I/O error occurs. 068 */ 069 BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { 070 this(nameIndex, length, (BootstrapMethod[]) null, constantPool); 071 072 final int numBootstrapMethods = input.readUnsignedShort(); 073 bootstrapMethods = new BootstrapMethod[numBootstrapMethods]; 074 for (int i = 0; i < numBootstrapMethods; i++) { 075 bootstrapMethods[i] = new BootstrapMethod(input); 076 } 077 } 078 079 /** 080 * @param v Visitor object 081 */ 082 @Override 083 public void accept(final Visitor v) { 084 v.visitBootstrapMethods(this); 085 } 086 087 /** 088 * @return deep copy of this attribute 089 */ 090 @Override 091 public BootstrapMethods copy(final ConstantPool constantPool) { 092 final BootstrapMethods c = (BootstrapMethods) clone(); 093 c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length]; 094 095 for (int i = 0; i < bootstrapMethods.length; i++) { 096 c.bootstrapMethods[i] = bootstrapMethods[i].copy(); 097 } 098 c.setConstantPool(constantPool); 099 return c; 100 } 101 102 /** 103 * Dump bootstrap methods attribute to file stream in binary format. 104 * 105 * @param file Output file stream 106 * @throws IOException if an I/O error occurs. 107 */ 108 @Override 109 public final void dump(final DataOutputStream file) throws IOException { 110 super.dump(file); 111 112 file.writeShort(bootstrapMethods.length); 113 for (final BootstrapMethod bootstrapMethod : bootstrapMethods) { 114 bootstrapMethod.dump(file); 115 } 116 } 117 118 /** 119 * @return array of bootstrap method "records" 120 */ 121 public final BootstrapMethod[] getBootstrapMethods() { 122 return bootstrapMethods; 123 } 124 125 @Override 126 public Iterator<BootstrapMethod> iterator() { 127 return Stream.of(bootstrapMethods).iterator(); 128 } 129 130 /** 131 * @param bootstrapMethods the array of bootstrap methods 132 */ 133 public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) { 134 this.bootstrapMethods = bootstrapMethods != null ? bootstrapMethods : BootstrapMethod.EMPTY_ARRAY; 135 } 136 137 /** 138 * @return String representation. 139 */ 140 @Override 141 public final String toString() { 142 final StringBuilder buf = new StringBuilder(); 143 buf.append("BootstrapMethods("); 144 buf.append(bootstrapMethods.length); 145 buf.append("):"); 146 for (int i = 0; i < bootstrapMethods.length; i++) { 147 buf.append("\n"); 148 final int start = buf.length(); 149 buf.append(" ").append(i).append(": "); 150 final int indentCount = buf.length() - start; 151 final String[] lines = bootstrapMethods[i].toString(super.getConstantPool()).split("\\r?\\n"); 152 buf.append(lines[0]); 153 for (int j = 1; j < lines.length; j++) { 154 buf.append("\n").append(" ", 0, indentCount).append(lines[j]); 155 } 156 } 157 return buf.toString(); 158 } 159}