001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.bcel.classfile; 021 022import java.io.DataInput; 023import java.io.DataOutputStream; 024import java.io.IOException; 025import java.util.Arrays; 026 027import org.apache.bcel.Const; 028import org.apache.bcel.util.Args; 029import org.apache.commons.lang3.ArrayUtils; 030 031/** 032 * This class represents the table of exceptions that are thrown by a method. This attribute may be used once per 033 * method. The name of this class is <em>ExceptionTable</em> for historical reasons; The Java Virtual Machine 034 * Specification, Second Edition defines this attribute using the name <em>Exceptions</em> (which is inconsistent with 035 * the other classes). 036 * 037 * <pre> 038 * Exceptions_attribute { 039 * u2 attribute_name_index; 040 * u4 attribute_length; 041 * u2 number_of_exceptions; 042 * u2 exception_index_table[number_of_exceptions]; 043 * } 044 * </pre> 045 * 046 * @see Code 047 */ 048public final class ExceptionTable extends Attribute { 049 050 private int[] exceptionIndexTable; // constant pool 051 052 /** 053 * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a 054 * physical copy. 055 * 056 * @param c Source to copy. 057 */ 058 public ExceptionTable(final ExceptionTable c) { 059 this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool()); 060 } 061 062 /** 063 * Constructs object from input stream. 064 * 065 * @param nameIndex Index in constant pool. 066 * @param length Content length in bytes. 067 * @param input Input stream. 068 * @param constantPool Array of constants. 069 * @throws IOException if an I/O error occurs. 070 */ 071 ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { 072 this(nameIndex, length, (int[]) null, constantPool); 073 exceptionIndexTable = ClassParser.readU2U2Table(input); 074 } 075 076 /** 077 * Constructs an ExceptionTable. 078 * 079 * @param nameIndex Index in constant pool. 080 * @param length Content length in bytes. 081 * @param exceptionIndexTable Table of indices in constant pool. 082 * @param constantPool Array of constants. 083 */ 084 public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) { 085 super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool); 086 this.exceptionIndexTable = ArrayUtils.nullToEmpty(exceptionIndexTable); 087 Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length"); 088 } 089 090 /** 091 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 092 * That is, the hierarchy of methods, fields, attributes, and so on spawns a tree of objects. 093 * 094 * @param v Visitor object. 095 */ 096 @Override 097 public void accept(final Visitor v) { 098 v.visitExceptionTable(this); 099 } 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}