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.Arrays;
26  
27  import org.apache.bcel.Const;
28  import org.apache.bcel.util.Args;
29  import org.apache.commons.lang3.ArrayUtils;
30  
31  /**
32   * This class represents the table of exceptions that are thrown by a method. This attribute may be used once per
33   * method. The name of this class is <em>ExceptionTable</em> for historical reasons; The Java Virtual Machine
34   * Specification, Second Edition defines this attribute using the name <em>Exceptions</em> (which is inconsistent with
35   * the other classes).
36   *
37   * <pre>
38   * Exceptions_attribute {
39   *   u2 attribute_name_index;
40   *   u4 attribute_length;
41   *   u2 number_of_exceptions;
42   *   u2 exception_index_table[number_of_exceptions];
43   * }
44   * </pre>
45   *
46   * @see Code
47   */
48  public final class ExceptionTable extends Attribute {
49  
50      private int[] exceptionIndexTable; // constant pool
51  
52      /**
53       * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
54       * physical copy.
55       *
56       * @param c Source to copy.
57       */
58      public ExceptionTable(final ExceptionTable c) {
59          this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool());
60      }
61  
62      /**
63       * Constructs object from input stream.
64       *
65       * @param nameIndex Index in constant pool.
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      ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
72          this(nameIndex, length, (int[]) null, constantPool);
73          exceptionIndexTable = ClassParser.readU2U2Table(input);
74      }
75  
76      /**
77       * Constructs an ExceptionTable.
78       *
79       * @param nameIndex Index in constant pool.
80       * @param length Content length in bytes.
81       * @param exceptionIndexTable Table of indices in constant pool.
82       * @param constantPool Array of constants.
83       */
84      public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) {
85          super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool);
86          this.exceptionIndexTable = ArrayUtils.nullToEmpty(exceptionIndexTable);
87          Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length");
88      }
89  
90      /**
91       * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
92       * That is, the hierarchy of methods, fields, attributes, and so on spawns a tree of objects.
93       *
94       * @param v Visitor object.
95       */
96      @Override
97      public void accept(final Visitor v) {
98          v.visitExceptionTable(this);
99      }
100 
101     /**
102      * Creates a deep copy of this attribute.
103      *
104      * @return deep copy of this attribute.
105      */
106     @Override
107     public Attribute copy(final ConstantPool constantPool) {
108         final ExceptionTable c = (ExceptionTable) clone();
109         if (exceptionIndexTable != null) {
110             c.exceptionIndexTable = exceptionIndexTable.clone();
111         }
112         c.setConstantPool(constantPool);
113         return c;
114     }
115 
116     /**
117      * Dumps exceptions attribute to file stream in binary format.
118      *
119      * @param file Output file stream.
120      * @throws IOException if an I/O error occurs.
121      */
122     @Override
123     public void dump(final DataOutputStream file) throws IOException {
124         super.dump(file);
125         file.writeShort(exceptionIndexTable.length);
126         for (final int index : exceptionIndexTable) {
127             file.writeShort(index);
128         }
129     }
130 
131     /**
132      * Gets the array of indices into constant pool of thrown exceptions.
133      *
134      * @return Array of indices into constant pool of thrown exceptions.
135      */
136     public int[] getExceptionIndexTable() {
137         return exceptionIndexTable;
138     }
139 
140     /**
141      * Gets the class names of thrown exceptions.
142      *
143      * @return class names of thrown exceptions.
144      */
145     public String[] getExceptionNames() {
146         final String[] names = new String[exceptionIndexTable.length];
147         Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class)));
148         return names;
149     }
150 
151     /**
152      * Gets the length of exception table.
153      *
154      * @return Length of exception table.
155      */
156     public int getNumberOfExceptions() {
157         return exceptionIndexTable == null ? 0 : exceptionIndexTable.length;
158     }
159 
160     /**
161      * Sets the exception index table.
162      *
163      * @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table
164      *        length.
165      */
166     public void setExceptionIndexTable(final int[] exceptionIndexTable) {
167         this.exceptionIndexTable = ArrayUtils.nullToEmpty(exceptionIndexTable);
168     }
169 
170     /**
171      * @return String representation, that is, a list of thrown exceptions.
172      */
173     @Override
174     public String toString() {
175         final StringBuilder buf = new StringBuilder();
176         String str;
177         buf.append("Exceptions: ");
178         for (int i = 0; i < exceptionIndexTable.length; i++) {
179             str = super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class);
180             buf.append(Utility.compactClassName(str, false));
181             if (i < exceptionIndexTable.length - 1) {
182                 buf.append(", ");
183             }
184         }
185         return buf.toString();
186     }
187 }