View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.bcel.classfile;
21  
22  import java.io.DataInput;
23  import java.io.DataOutputStream;
24  import java.io.IOException;
25  import java.util.Iterator;
26  import java.util.stream.Stream;
27  
28  import org.apache.bcel.Const;
29  
30  /**
31   * This class represents a BootstrapMethods attribute.
32   *
33   * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
34   *      The BootstrapMethods Attribute</a>
35   * @since 6.0
36   */
37  public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> {
38  
39      private BootstrapMethod[] bootstrapMethods; // TODO this could be made final (setter is not used)
40  
41      /**
42       * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
43       * physical copy.
44       *
45       * @param c Source to copy.
46       */
47      public BootstrapMethods(final BootstrapMethods c) {
48          this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool());
49      }
50  
51      /**
52       * Constructs a BootstrapMethods attribute.
53       *
54       * @param nameIndex Index in constant pool to CONSTANT_Utf8.
55       * @param length Content length in bytes.
56       * @param bootstrapMethods array of bootstrap methods.
57       * @param constantPool Array of constants.
58       */
59      public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) {
60          super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool);
61          setBootstrapMethods(bootstrapMethods);
62      }
63  
64      /**
65       * Constructs object from Input stream.
66       *
67       * @param nameIndex Index in constant pool to CONSTANT_Utf8.
68       * @param length Content length in bytes.
69       * @param input Input stream.
70       * @param constantPool Array of constants.
71       * @throws IOException if an I/O error occurs.
72       */
73      BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
74          this(nameIndex, length, (BootstrapMethod[]) null, constantPool);
75  
76          final int numBootstrapMethods = input.readUnsignedShort();
77          bootstrapMethods = new BootstrapMethod[numBootstrapMethods];
78          for (int i = 0; i < numBootstrapMethods; i++) {
79              bootstrapMethods[i] = new BootstrapMethod(input);
80          }
81      }
82  
83      /**
84       * Accepts a visitor.
85       *
86       * @param v Visitor object.
87       */
88      @Override
89      public void accept(final Visitor v) {
90          v.visitBootstrapMethods(this);
91      }
92  
93      /**
94       * Creates a deep copy of this attribute.
95       *
96       * @param constantPool the constant pool.
97       * @return deep copy of this attribute.
98       */
99      @Override
100     public BootstrapMethods copy(final ConstantPool constantPool) {
101         final BootstrapMethods c = (BootstrapMethods) clone();
102         c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length];
103 
104         for (int i = 0; i < bootstrapMethods.length; i++) {
105             c.bootstrapMethods[i] = bootstrapMethods[i].copy();
106         }
107         c.setConstantPool(constantPool);
108         return c;
109     }
110 
111     /**
112      * Dumps bootstrap methods attribute to file stream in binary format.
113      *
114      * @param file Output file stream.
115      * @throws IOException if an I/O error occurs.
116      */
117     @Override
118     public final void dump(final DataOutputStream file) throws IOException {
119         super.dump(file);
120 
121         file.writeShort(bootstrapMethods.length);
122         for (final BootstrapMethod bootstrapMethod : bootstrapMethods) {
123             bootstrapMethod.dump(file);
124         }
125     }
126 
127     /**
128      * Gets the array of bootstrap method records.
129      *
130      * @return array of bootstrap method records.
131      */
132     public final BootstrapMethod[] getBootstrapMethods() {
133         return bootstrapMethods;
134     }
135 
136     @Override
137     public Iterator<BootstrapMethod> iterator() {
138         return Stream.of(bootstrapMethods).iterator();
139     }
140 
141     /**
142      * Sets the bootstrap methods.
143      *
144      * @param bootstrapMethods the array of bootstrap methods.
145      */
146     public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) {
147         this.bootstrapMethods = bootstrapMethods != null ? bootstrapMethods : BootstrapMethod.EMPTY_ARRAY;
148     }
149 
150     /**
151      * @return String representation.
152      */
153     @Override
154     public final String toString() {
155         final StringBuilder buf = new StringBuilder();
156         buf.append("BootstrapMethods(");
157         buf.append(bootstrapMethods.length);
158         buf.append("):");
159         for (int i = 0; i < bootstrapMethods.length; i++) {
160             buf.append("\n");
161             final int start = buf.length();
162             buf.append("  ").append(i).append(": ");
163             final int indentCount = buf.length() - start;
164             final String[] lines = bootstrapMethods[i].toString(super.getConstantPool()).split("\\r?\\n");
165             buf.append(lines[0]);
166             for (int j = 1; j < lines.length; j++) {
167                 buf.append("\n").append("          ", 0, indentCount).append(lines[j]);
168             }
169         }
170         return buf.toString();
171     }
172 }