ExceptionTable.java

  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. package org.apache.bcel.classfile;

  18. import java.io.DataInput;
  19. import java.io.DataOutputStream;
  20. import java.io.IOException;
  21. import java.util.Arrays;

  22. import org.apache.bcel.Const;
  23. import org.apache.bcel.util.Args;
  24. import org.apache.commons.lang3.ArrayUtils;

  25. /**
  26.  * This class represents the table of exceptions that are thrown by a method. This attribute may be used once per
  27.  * method. The name of this class is <em>ExceptionTable</em> for historical reasons; The Java Virtual Machine
  28.  * Specification, Second Edition defines this attribute using the name <em>Exceptions</em> (which is inconsistent with
  29.  * the other classes).
  30.  *
  31.  * <pre>
  32.  * Exceptions_attribute {
  33.  *   u2 attribute_name_index;
  34.  *   u4 attribute_length;
  35.  *   u2 number_of_exceptions;
  36.  *   u2 exception_index_table[number_of_exceptions];
  37.  * }
  38.  * </pre>
  39.  * @see Code
  40.  */
  41. public final class ExceptionTable extends Attribute {

  42.     private int[] exceptionIndexTable; // constant pool

  43.     /**
  44.      * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
  45.      * physical copy.
  46.      *
  47.      * @param c Source to copy.
  48.      */
  49.     public ExceptionTable(final ExceptionTable c) {
  50.         this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool());
  51.     }

  52.     /**
  53.      * Constructs object from input stream.
  54.      *
  55.      * @param nameIndex Index in constant pool
  56.      * @param length Content length in bytes
  57.      * @param input Input stream
  58.      * @param constantPool Array of constants
  59.      * @throws IOException if an I/O error occurs.
  60.      */
  61.     ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
  62.         this(nameIndex, length, (int[]) null, constantPool);
  63.         final int exceptionCount = input.readUnsignedShort();
  64.         exceptionIndexTable = new int[exceptionCount];
  65.         for (int i = 0; i < exceptionCount; i++) {
  66.             exceptionIndexTable[i] = input.readUnsignedShort();
  67.         }
  68.     }

  69.     /**
  70.      * @param nameIndex Index in constant pool
  71.      * @param length Content length in bytes
  72.      * @param exceptionIndexTable Table of indices in constant pool
  73.      * @param constantPool Array of constants
  74.      */
  75.     public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) {
  76.         super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool);
  77.         this.exceptionIndexTable = ArrayUtils.nullToEmpty(exceptionIndexTable);
  78.         Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length");
  79.     }

  80.     /**
  81.      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
  82.      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
  83.      *
  84.      * @param v Visitor object
  85.      */
  86.     @Override
  87.     public void accept(final Visitor v) {
  88.         v.visitExceptionTable(this);
  89.     }

  90.     /**
  91.      * @return deep copy of this attribute
  92.      */
  93.     @Override
  94.     public Attribute copy(final ConstantPool constantPool) {
  95.         final ExceptionTable c = (ExceptionTable) clone();
  96.         if (exceptionIndexTable != null) {
  97.             c.exceptionIndexTable = exceptionIndexTable.clone();
  98.         }
  99.         c.setConstantPool(constantPool);
  100.         return c;
  101.     }

  102.     /**
  103.      * Dump exceptions attribute to file stream in binary format.
  104.      *
  105.      * @param file Output file stream
  106.      * @throws IOException if an I/O error occurs.
  107.      */
  108.     @Override
  109.     public void dump(final DataOutputStream file) throws IOException {
  110.         super.dump(file);
  111.         file.writeShort(exceptionIndexTable.length);
  112.         for (final int index : exceptionIndexTable) {
  113.             file.writeShort(index);
  114.         }
  115.     }

  116.     /**
  117.      * @return Array of indices into constant pool of thrown exceptions.
  118.      */
  119.     public int[] getExceptionIndexTable() {
  120.         return exceptionIndexTable;
  121.     }

  122.     /**
  123.      * @return class names of thrown exceptions
  124.      */
  125.     public String[] getExceptionNames() {
  126.         final String[] names = new String[exceptionIndexTable.length];
  127.         Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class)));
  128.         return names;
  129.     }

  130.     /**
  131.      * @return Length of exception table.
  132.      */
  133.     public int getNumberOfExceptions() {
  134.         return exceptionIndexTable == null ? 0 : exceptionIndexTable.length;
  135.     }

  136.     /**
  137.      * @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table
  138.      *        length.
  139.      */
  140.     public void setExceptionIndexTable(final int[] exceptionIndexTable) {
  141.         this.exceptionIndexTable = ArrayUtils.nullToEmpty(exceptionIndexTable);
  142.     }

  143.     /**
  144.      * @return String representation, i.e., a list of thrown exceptions.
  145.      */
  146.     @Override
  147.     public String toString() {
  148.         final StringBuilder buf = new StringBuilder();
  149.         String str;
  150.         buf.append("Exceptions: ");
  151.         for (int i = 0; i < exceptionIndexTable.length; i++) {
  152.             str = super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class);
  153.             buf.append(Utility.compactClassName(str, false));
  154.             if (i < exceptionIndexTable.length - 1) {
  155.                 buf.append(", ");
  156.             }
  157.         }
  158.         return buf.toString();
  159.     }
  160. }