View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package org.apache.bcel.classfile;
19  
20  import java.io.DataInput;
21  import java.io.DataOutputStream;
22  import java.io.IOException;
23  import java.util.Arrays;
24  
25  import org.apache.bcel.Const;
26  import org.apache.bcel.util.Args;
27  import org.apache.commons.lang3.ArrayUtils;
28  
29  /**
30   * This class represents the table of exceptions that are thrown by a method. This attribute may be used once per
31   * method. The name of this class is <em>ExceptionTable</em> for historical reasons; The Java Virtual Machine
32   * Specification, Second Edition defines this attribute using the name <em>Exceptions</em> (which is inconsistent with
33   * the other classes).
34   *
35   * <pre>
36   * Exceptions_attribute {
37   *   u2 attribute_name_index;
38   *   u4 attribute_length;
39   *   u2 number_of_exceptions;
40   *   u2 exception_index_table[number_of_exceptions];
41   * }
42   * </pre>
43   * @see Code
44   */
45  public final class ExceptionTable extends Attribute {
46  
47      private int[] exceptionIndexTable; // constant pool
48  
49      /**
50       * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
51       * physical copy.
52       *
53       * @param c Source to copy.
54       */
55      public ExceptionTable(final ExceptionTable c) {
56          this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool());
57      }
58  
59      /**
60       * Constructs object from input stream.
61       *
62       * @param nameIndex Index in constant pool
63       * @param length Content length in bytes
64       * @param input Input stream
65       * @param constantPool Array of constants
66       * @throws IOException if an I/O error occurs.
67       */
68      ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
69          this(nameIndex, length, (int[]) null, constantPool);
70          final int exceptionCount = input.readUnsignedShort();
71          exceptionIndexTable = new int[exceptionCount];
72          for (int i = 0; i < exceptionCount; i++) {
73              exceptionIndexTable[i] = input.readUnsignedShort();
74          }
75      }
76  
77      /**
78       * @param nameIndex Index in constant pool
79       * @param length Content length in bytes
80       * @param exceptionIndexTable Table of indices in constant pool
81       * @param constantPool Array of constants
82       */
83      public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) {
84          super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool);
85          this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : ArrayUtils.EMPTY_INT_ARRAY;
86          Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length");
87      }
88  
89      /**
90       * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
91       * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
92       *
93       * @param v Visitor object
94       */
95      @Override
96      public void accept(final Visitor v) {
97          v.visitExceptionTable(this);
98      }
99  
100     /**
101      * @return deep copy of this attribute
102      */
103     @Override
104     public Attribute copy(final ConstantPool constantPool) {
105         final ExceptionTable c = (ExceptionTable) clone();
106         if (exceptionIndexTable != null) {
107             c.exceptionIndexTable = exceptionIndexTable.clone();
108         }
109         c.setConstantPool(constantPool);
110         return c;
111     }
112 
113     /**
114      * Dump exceptions attribute to file stream in binary format.
115      *
116      * @param file Output file stream
117      * @throws IOException if an I/O error occurs.
118      */
119     @Override
120     public void dump(final DataOutputStream file) throws IOException {
121         super.dump(file);
122         file.writeShort(exceptionIndexTable.length);
123         for (final int index : exceptionIndexTable) {
124             file.writeShort(index);
125         }
126     }
127 
128     /**
129      * @return Array of indices into constant pool of thrown exceptions.
130      */
131     public int[] getExceptionIndexTable() {
132         return exceptionIndexTable;
133     }
134 
135     /**
136      * @return class names of thrown exceptions
137      */
138     public String[] getExceptionNames() {
139         final String[] names = new String[exceptionIndexTable.length];
140         Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class)));
141         return names;
142     }
143 
144     /**
145      * @return Length of exception table.
146      */
147     public int getNumberOfExceptions() {
148         return exceptionIndexTable == null ? 0 : exceptionIndexTable.length;
149     }
150 
151     /**
152      * @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table
153      *        length.
154      */
155     public void setExceptionIndexTable(final int[] exceptionIndexTable) {
156         this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : ArrayUtils.EMPTY_INT_ARRAY;
157     }
158 
159     /**
160      * @return String representation, i.e., a list of thrown exceptions.
161      */
162     @Override
163     public String toString() {
164         final StringBuilder buf = new StringBuilder();
165         String str;
166         buf.append("Exceptions: ");
167         for (int i = 0; i < exceptionIndexTable.length; i++) {
168             str = super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class);
169             buf.append(Utility.compactClassName(str, false));
170             if (i < exceptionIndexTable.length - 1) {
171                 buf.append(", ");
172             }
173         }
174         return buf.toString();
175     }
176 }