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   * @see Code
46   */
47  public final class ExceptionTable extends Attribute {
48  
49      private int[] exceptionIndexTable; // constant pool
50  
51      /**
52       * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
53       * physical copy.
54       *
55       * @param c Source to copy.
56       */
57      public ExceptionTable(final ExceptionTable c) {
58          this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool());
59      }
60  
61      /**
62       * Constructs object from input stream.
63       *
64       * @param nameIndex Index in constant pool
65       * @param length Content length in bytes
66       * @param input Input stream
67       * @param constantPool Array of constants
68       * @throws IOException if an I/O error occurs.
69       */
70      ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
71          this(nameIndex, length, (int[]) null, constantPool);
72          final int exceptionCount = input.readUnsignedShort();
73          exceptionIndexTable = new int[exceptionCount];
74          for (int i = 0; i < exceptionCount; i++) {
75              exceptionIndexTable[i] = input.readUnsignedShort();
76          }
77      }
78  
79      /**
80       * @param nameIndex Index in constant pool
81       * @param length Content length in bytes
82       * @param exceptionIndexTable Table of indices in constant pool
83       * @param constantPool Array of constants
84       */
85      public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) {
86          super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool);
87          this.exceptionIndexTable = ArrayUtils.nullToEmpty(exceptionIndexTable);
88          Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length");
89      }
90  
91      /**
92       * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
93       * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
94       *
95       * @param v Visitor object
96       */
97      @Override
98      public void accept(final Visitor v) {
99          v.visitExceptionTable(this);
100     }
101 
102     /**
103      * @return deep copy of this attribute
104      */
105     @Override
106     public Attribute copy(final ConstantPool constantPool) {
107         final ExceptionTable c = (ExceptionTable) clone();
108         if (exceptionIndexTable != null) {
109             c.exceptionIndexTable = exceptionIndexTable.clone();
110         }
111         c.setConstantPool(constantPool);
112         return c;
113     }
114 
115     /**
116      * Dump exceptions attribute to file stream in binary format.
117      *
118      * @param file Output file stream
119      * @throws IOException if an I/O error occurs.
120      */
121     @Override
122     public void dump(final DataOutputStream file) throws IOException {
123         super.dump(file);
124         file.writeShort(exceptionIndexTable.length);
125         for (final int index : exceptionIndexTable) {
126             file.writeShort(index);
127         }
128     }
129 
130     /**
131      * @return Array of indices into constant pool of thrown exceptions.
132      */
133     public int[] getExceptionIndexTable() {
134         return exceptionIndexTable;
135     }
136 
137     /**
138      * @return class names of thrown exceptions
139      */
140     public String[] getExceptionNames() {
141         final String[] names = new String[exceptionIndexTable.length];
142         Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class)));
143         return names;
144     }
145 
146     /**
147      * @return Length of exception table.
148      */
149     public int getNumberOfExceptions() {
150         return exceptionIndexTable == null ? 0 : exceptionIndexTable.length;
151     }
152 
153     /**
154      * @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table
155      *        length.
156      */
157     public void setExceptionIndexTable(final int[] exceptionIndexTable) {
158         this.exceptionIndexTable = ArrayUtils.nullToEmpty(exceptionIndexTable);
159     }
160 
161     /**
162      * @return String representation, i.e., a list of thrown exceptions.
163      */
164     @Override
165     public String toString() {
166         final StringBuilder buf = new StringBuilder();
167         String str;
168         buf.append("Exceptions: ");
169         for (int i = 0; i < exceptionIndexTable.length; i++) {
170             str = super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class);
171             buf.append(Utility.compactClassName(str, false));
172             if (i < exceptionIndexTable.length - 1) {
173                 buf.append(", ");
174             }
175         }
176         return buf.toString();
177     }
178 }