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       * @param nameIndex Index in constant pool to CONSTANT_Utf8
53       * @param length Content length in bytes
54       * @param bootstrapMethods array of bootstrap methods
55       * @param constantPool Array of constants
56       */
57      public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) {
58          super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool);
59          setBootstrapMethods(bootstrapMethods);
60      }
61  
62      /**
63       * Constructs object from Input stream.
64       *
65       * @param nameIndex Index in constant pool to CONSTANT_Utf8
66       * @param length Content length in bytes
67       * @param input Input stream
68       * @param constantPool Array of constants
69       * @throws IOException if an I/O error occurs.
70       */
71      BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
72          this(nameIndex, length, (BootstrapMethod[]) null, constantPool);
73  
74          final int numBootstrapMethods = input.readUnsignedShort();
75          bootstrapMethods = new BootstrapMethod[numBootstrapMethods];
76          for (int i = 0; i < numBootstrapMethods; i++) {
77              bootstrapMethods[i] = new BootstrapMethod(input);
78          }
79      }
80  
81      /**
82       * @param v Visitor object
83       */
84      @Override
85      public void accept(final Visitor v) {
86          v.visitBootstrapMethods(this);
87      }
88  
89      /**
90       * @return deep copy of this attribute
91       */
92      @Override
93      public BootstrapMethods copy(final ConstantPool constantPool) {
94          final BootstrapMethods c = (BootstrapMethods) clone();
95          c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length];
96  
97          for (int i = 0; i < bootstrapMethods.length; i++) {
98              c.bootstrapMethods[i] = bootstrapMethods[i].copy();
99          }
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 }