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 }