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 public BootstrapMethods(final BootstrapMethods c) { 044 this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool()); 045 } 046 047 /** 048 * @param nameIndex Index in constant pool to CONSTANT_Utf8 049 * @param length Content length in bytes 050 * @param bootstrapMethods array of bootstrap methods 051 * @param constantPool Array of constants 052 */ 053 public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) { 054 super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool); 055 this.bootstrapMethods = bootstrapMethods; 056 } 057 058 /** 059 * Construct object from Input stream. 060 * 061 * @param nameIndex Index in constant pool to CONSTANT_Utf8 062 * @param length Content length in bytes 063 * @param input Input stream 064 * @param constantPool Array of constants 065 * @throws IOException if an I/O error occurs. 066 */ 067 BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { 068 this(nameIndex, length, (BootstrapMethod[]) null, constantPool); 069 070 final int numBootstrapMethods = input.readUnsignedShort(); 071 bootstrapMethods = new BootstrapMethod[numBootstrapMethods]; 072 for (int i = 0; i < numBootstrapMethods; i++) { 073 bootstrapMethods[i] = new BootstrapMethod(input); 074 } 075 } 076 077 /** 078 * @param v Visitor object 079 */ 080 @Override 081 public void accept(final Visitor v) { 082 v.visitBootstrapMethods(this); 083 } 084 085 /** 086 * @return deep copy of this attribute 087 */ 088 @Override 089 public BootstrapMethods copy(final ConstantPool constantPool) { 090 final BootstrapMethods c = (BootstrapMethods) clone(); 091 c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length]; 092 093 for (int i = 0; i < bootstrapMethods.length; i++) { 094 c.bootstrapMethods[i] = bootstrapMethods[i].copy(); 095 } 096 c.setConstantPool(constantPool); 097 return c; 098 } 099 100 /** 101 * Dump bootstrap methods attribute to file stream in binary format. 102 * 103 * @param file Output file stream 104 * @throws IOException if an I/O error occurs. 105 */ 106 @Override 107 public final void dump(final DataOutputStream file) throws IOException { 108 super.dump(file); 109 110 file.writeShort(bootstrapMethods.length); 111 for (final BootstrapMethod bootstrapMethod : bootstrapMethods) { 112 bootstrapMethod.dump(file); 113 } 114 } 115 116 /** 117 * @return array of bootstrap method "records" 118 */ 119 public final BootstrapMethod[] getBootstrapMethods() { 120 return bootstrapMethods; 121 } 122 123 @Override 124 public Iterator<BootstrapMethod> iterator() { 125 return Stream.of(bootstrapMethods).iterator(); 126 } 127 128 /** 129 * @param bootstrapMethods the array of bootstrap methods 130 */ 131 public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) { 132 this.bootstrapMethods = bootstrapMethods; 133 } 134 135 /** 136 * @return String representation. 137 */ 138 @Override 139 public final String toString() { 140 final StringBuilder buf = new StringBuilder(); 141 buf.append("BootstrapMethods("); 142 buf.append(bootstrapMethods.length); 143 buf.append("):"); 144 for (int i = 0; i < bootstrapMethods.length; i++) { 145 buf.append("\n"); 146 final int start = buf.length(); 147 buf.append(" ").append(i).append(": "); 148 final int indentCount = buf.length() - start; 149 final String[] lines = bootstrapMethods[i].toString(super.getConstantPool()).split("\\r?\\n"); 150 buf.append(lines[0]); 151 for (int j = 1; j < lines.length; j++) { 152 buf.append("\n").append(" ", 0, indentCount).append(lines[j]); 153 } 154 } 155 return buf.toString(); 156 } 157}