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 * @see Code 046 */ 047public final class ExceptionTable extends Attribute { 048 049 private int[] exceptionIndexTable; // constant pool 050 051 /** 052 * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a 053 * physical copy. 054 * 055 * @param c Source to copy. 056 */ 057 public ExceptionTable(final ExceptionTable c) { 058 this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool()); 059 } 060 061 /** 062 * Constructs object from input stream. 063 * 064 * @param nameIndex Index in constant pool 065 * @param length Content length in bytes 066 * @param input Input stream 067 * @param constantPool Array of constants 068 * @throws IOException if an I/O error occurs. 069 */ 070 ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException { 071 this(nameIndex, length, (int[]) null, constantPool); 072 final int exceptionCount = input.readUnsignedShort(); 073 exceptionIndexTable = new int[exceptionCount]; 074 for (int i = 0; i < exceptionCount; i++) { 075 exceptionIndexTable[i] = input.readUnsignedShort(); 076 } 077 } 078 079 /** 080 * @param nameIndex Index in constant pool 081 * @param length Content length in bytes 082 * @param exceptionIndexTable Table of indices in constant pool 083 * @param constantPool Array of constants 084 */ 085 public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) { 086 super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool); 087 this.exceptionIndexTable = ArrayUtils.nullToEmpty(exceptionIndexTable); 088 Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length"); 089 } 090 091 /** 092 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 093 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 094 * 095 * @param v Visitor object 096 */ 097 @Override 098 public void accept(final Visitor v) { 099 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}