View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package org.apache.bcel.classfile;
19  
20  import java.io.DataInput;
21  import java.io.DataOutputStream;
22  import java.io.IOException;
23  import java.util.Iterator;
24  import java.util.stream.Stream;
25  
26  import org.apache.bcel.Const;
27  
28  /**
29   * This class represents a BootstrapMethods attribute.
30   *
31   * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
32   *      The BootstrapMethods Attribute</a>
33   * @since 6.0
34   */
35  public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> {
36  
37      private BootstrapMethod[] bootstrapMethods; // TODO this could be made final (setter is not used)
38  
39      /**
40       * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
41       * physical copy.
42       *
43       * @param c Source to copy.
44       */
45      public BootstrapMethods(final BootstrapMethods c) {
46          this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool());
47      }
48  
49      /**
50       * @param nameIndex Index in constant pool to CONSTANT_Utf8
51       * @param length Content length in bytes
52       * @param bootstrapMethods array of bootstrap methods
53       * @param constantPool Array of constants
54       */
55      public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) {
56          super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool);
57          setBootstrapMethods(bootstrapMethods);
58      }
59  
60      /**
61       * Constructs object from Input stream.
62       *
63       * @param nameIndex Index in constant pool to CONSTANT_Utf8
64       * @param length Content length in bytes
65       * @param input Input stream
66       * @param constantPool Array of constants
67       * @throws IOException if an I/O error occurs.
68       */
69      BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
70          this(nameIndex, length, (BootstrapMethod[]) null, constantPool);
71  
72          final int numBootstrapMethods = input.readUnsignedShort();
73          bootstrapMethods = new BootstrapMethod[numBootstrapMethods];
74          for (int i = 0; i < numBootstrapMethods; i++) {
75              bootstrapMethods[i] = new BootstrapMethod(input);
76          }
77      }
78  
79      /**
80       * @param v Visitor object
81       */
82      @Override
83      public void accept(final Visitor v) {
84          v.visitBootstrapMethods(this);
85      }
86  
87      /**
88       * @return deep copy of this attribute
89       */
90      @Override
91      public BootstrapMethods copy(final ConstantPool constantPool) {
92          final BootstrapMethods c = (BootstrapMethods) clone();
93          c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length];
94  
95          for (int i = 0; i < bootstrapMethods.length; i++) {
96              c.bootstrapMethods[i] = bootstrapMethods[i].copy();
97          }
98          c.setConstantPool(constantPool);
99          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 }