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  import org.apache.bcel.util.Args;
30  
31  /**
32   * This class represents a BootstrapMethods attribute.
33   *
34   * @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
35   *      The BootstrapMethods Attribute</a>
36   * @since 6.0
37   */
38  public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> {
39  
40      private BootstrapMethod[] bootstrapMethods; // TODO this could be made final (setter is not used)
41  
42      /**
43       * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
44       * physical copy.
45       *
46       * @param c Source to copy.
47       */
48      public BootstrapMethods(final BootstrapMethods c) {
49          this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool());
50      }
51  
52      /**
53       * Constructs a BootstrapMethods attribute.
54       *
55       * @param nameIndex Index in constant pool to CONSTANT_Utf8.
56       * @param length Content length in bytes.
57       * @param bootstrapMethods array of bootstrap methods.
58       * @param constantPool Array of constants.
59       */
60      public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) {
61          super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool);
62          setBootstrapMethods(bootstrapMethods);
63      }
64  
65      /**
66       * Constructs object from Input stream.
67       *
68       * @param nameIndex Index in constant pool to CONSTANT_Utf8.
69       * @param length Content length in bytes.
70       * @param input Input stream.
71       * @param constantPool Array of constants.
72       * @throws IOException Thrown if an I/O error occurs.
73       */
74      BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
75          this(nameIndex, length, (BootstrapMethod[]) null, constantPool);
76  
77          final int numBootstrapMethods = input.readUnsignedShort();
78          bootstrapMethods = new BootstrapMethod[numBootstrapMethods];
79          for (int i = 0; i < numBootstrapMethods; i++) {
80              bootstrapMethods[i] = new BootstrapMethod(input);
81          }
82      }
83  
84      /**
85       * Accepts a visitor.
86       *
87       * @param v Visitor object.
88       */
89      @Override
90      public void accept(final Visitor v) {
91          v.visitBootstrapMethods(this);
92      }
93  
94      /**
95       * Creates a deep copy of this attribute.
96       *
97       * @param constantPool The constant pool.
98       * @return deep copy of this attribute.
99       */
100     @Override
101     public BootstrapMethods copy(final ConstantPool constantPool) {
102         final BootstrapMethods c = (BootstrapMethods) clone();
103         c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length];
104 
105         for (int i = 0; i < bootstrapMethods.length; i++) {
106             c.bootstrapMethods[i] = bootstrapMethods[i].copy();
107         }
108         c.setConstantPool(constantPool);
109         return c;
110     }
111 
112     /**
113      * Dumps bootstrap methods attribute to file stream in binary format.
114      *
115      * @param file Output file stream.
116      * @throws IOException Thrown if an I/O error occurs.
117      */
118     @Override
119     public final void dump(final DataOutputStream file) throws IOException {
120         super.dump(file);
121 
122         file.writeShort(Args.requireU2(bootstrapMethods.length, "bootstrapMethods.length"));
123         for (final BootstrapMethod bootstrapMethod : bootstrapMethods) {
124             bootstrapMethod.dump(file);
125         }
126     }
127 
128     /**
129      * Gets the array of bootstrap method records.
130      *
131      * @return array of bootstrap method records.
132      */
133     public final BootstrapMethod[] getBootstrapMethods() {
134         return bootstrapMethods;
135     }
136 
137     @Override
138     public Iterator<BootstrapMethod> iterator() {
139         return Stream.of(bootstrapMethods).iterator();
140     }
141 
142     /**
143      * Sets the bootstrap methods.
144      *
145      * @param bootstrapMethods The array of bootstrap methods.
146      */
147     public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) {
148         this.bootstrapMethods = bootstrapMethods != null ? bootstrapMethods : BootstrapMethod.EMPTY_ARRAY;
149     }
150 
151     /**
152      * @return String representation.
153      */
154     @Override
155     public final String toString() {
156         final StringBuilder buf = new StringBuilder();
157         buf.append("BootstrapMethods(");
158         buf.append(bootstrapMethods.length);
159         buf.append("):");
160         for (int i = 0; i < bootstrapMethods.length; i++) {
161             buf.append("\n");
162             final int start = buf.length();
163             buf.append("  ").append(i).append(": ");
164             final int indentCount = buf.length() - start;
165             final String[] lines = bootstrapMethods[i].toString(super.getConstantPool()).split("\\r?\\n");
166             buf.append(lines[0]);
167             for (int j = 1; j < lines.length; j++) {
168                 buf.append("\n").append("          ", 0, indentCount).append(lines[j]);
169             }
170         }
171         return buf.toString();
172     }
173 }