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 }