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