undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.java_cup.internal.runtime;
/**
* Defines the Scanner interface, which CUP uses in the default
* implementation of <code>lr_parser.scan()</code>. Integration
* of scanners implementing <code>Scanner</code> is facilitated.
*
* @author David MacMahon <davidm@smartsc.com>
*/
/* *************************************************
Interface Scanner
Declares the next_token() method that should be
implemented by scanners. This method is typically
called by lr_parser.scan().
***************************************************/
public interface Scanner {
public Symbol next_token() throws java.lang.Exception;
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.java_cup.internal.runtime;
/**
* Defines the Symbol class, which is used to represent all terminals
* and nonterminals while parsing. The lexer should pass CUP Symbols
* and CUP returns a Symbol.
*
* @author Frank Flannery
*/
/* ****************************************************************
Class Symbol
what the parser expects to receive from the lexer.
the token is identified as follows:
sym: the symbol type
parse_state: the parse state.
value: is the lexical value of type Object
left : is the left position in the original input file
right: is the right position in the original input file
******************************************************************/
public class Symbol {
/*******************************
Constructor for l,r values
*******************************/
public Symbol(int id, int l, int r, Object o) {
this(id);
left = l;
right = r;
value = o;
}
/*******************************
Constructor for no l,r values
********************************/
public Symbol(int id, Object o) {
this(id);
left = -1;
right = -1;
value = o;
}
/*****************************
Constructor for no value
***************************/
public Symbol(int sym_num, int l, int r) {
sym = sym_num;
left = l;
right = r;
value = null;
}
/***********************************
Constructor for no value or l,r
***********************************/
public Symbol(int sym_num) {
this(sym_num, -1);
left = -1;
right = -1;
value = null;
}
/***********************************
Constructor to give a start state
***********************************/
public Symbol(int sym_num, int state)
{
sym = sym_num;
parse_state = state;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The symbol number of the terminal or non terminal being represented */
public int sym;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The parse state to be recorded on the parse stack with this symbol.
* This field is for the convenience of the parser and shouldn't be
* modified except by the parser.
*/
public int parse_state;
/** This allows us to catch some errors caused by scanners recycling
* symbols. For the use of the parser only. [CSA, 23-Jul-1999] */
boolean used_by_parser = false;
/*******************************
The data passed to parser
*******************************/
public int left, right;
public Object value;
/*****************************
Printing this token out. (Override for pretty-print).
****************************/
public String toString() { return "#"+sym; }
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,169 @@
/*
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.java_cup.internal.runtime;
import java.util.Stack;
/** This class implements a temporary or "virtual" parse stack that
* replaces the top portion of the actual parse stack (the part that
* has been changed by some set of operations) while maintaining its
* original contents. This data structure is used when the parse needs
* to "parse ahead" to determine if a given error recovery attempt will
* allow the parse to continue far enough to consider it successful. Once
* success or failure of parse ahead is determined the system then
* reverts to the original parse stack (which has not actually been
* modified). Since parse ahead does not execute actions, only parse
* state is maintained on the virtual stack, not full Symbol objects.
*
* @see com.sun.java_cup.internal.runtime.lr_parser
* @author Frank Flannery
*/
public class virtual_parse_stack {
/*-----------------------------------------------------------*/
/*--- Constructor(s) ----------------------------------------*/
/*-----------------------------------------------------------*/
/** Constructor to build a virtual stack out of a real stack. */
public virtual_parse_stack(Stack<Symbol> shadowing_stack) throws java.lang.Exception
{
/* sanity check */
if (shadowing_stack == null)
throw new Exception(
"Internal parser error: attempt to create null virtual stack");
/* set up our internals */
real_stack = shadowing_stack;
vstack = new Stack<>();
real_next = 0;
/* get one element onto the virtual portion of the stack */
get_from_real();
}
/*-----------------------------------------------------------*/
/*--- (Access to) Instance Variables ------------------------*/
/*-----------------------------------------------------------*/
/** The real stack that we shadow. This is accessed when we move off
* the bottom of the virtual portion of the stack, but is always left
* unmodified.
*/
protected Stack<Symbol> real_stack;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Top of stack indicator for where we leave off in the real stack.
* This is measured from top of stack, so 0 would indicate that no
* elements have been "moved" from the real to virtual stack.
*/
protected int real_next;
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** The virtual top portion of the stack. This stack contains Integer
* objects with state numbers. This stack shadows the top portion
* of the real stack within the area that has been modified (via operations
* on the virtual stack). When this portion of the stack becomes empty we
* transfer elements from the underlying stack onto this stack.
*/
protected Stack<Integer> vstack;
/*-----------------------------------------------------------*/
/*--- General Methods ---------------------------------------*/
/*-----------------------------------------------------------*/
/** Transfer an element from the real to the virtual stack. This assumes
* that the virtual stack is currently empty.
*/
protected void get_from_real()
{
Symbol stack_sym;
/* don't transfer if the real stack is empty */
if (real_next >= real_stack.size()) return;
/* get a copy of the first Symbol we have not transferred */
stack_sym = real_stack.get(real_stack.size()-1-real_next);
/* record the transfer */
real_next++;
/* put the state number from the Symbol onto the virtual stack */
vstack.push(stack_sym.parse_state);
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Indicate whether the stack is empty. */
public boolean empty()
{
/* if vstack is empty then we were unable to transfer onto it and
the whole thing is empty. */
return vstack.empty();
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Return value on the top of the stack (without popping it). */
public int top() throws java.lang.Exception
{
if (vstack.empty())
throw new Exception(
"Internal parser error: top() called on empty virtual stack");
return (vstack.peek());
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Pop the stack. */
public void pop() throws java.lang.Exception
{
if (vstack.empty())
throw new Exception(
"Internal parser error: pop from empty virtual stack");
/* pop it */
vstack.pop();
/* if we are now empty transfer an element (if there is one) */
if (vstack.empty())
get_from_real();
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Push a state number onto the stack. */
public void push(int state_num)
{
vstack.push(state_num);
}
/*-----------------------------------------------------------*/
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,132 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal;
import jdk.xml.internal.Utils;
/**
* Exception constants.
*
* @since 6.0 (intended to replace the InstructionConstant interface)
* @LastModified: Sept 2025
*/
public final class ExceptionConst {
/**
* Enum corresponding to the various Exception Class arrays, used by
* {@link ExceptionConst#createExceptions(EXCS, Class...)}
*/
public enum EXCS {
EXCS_CLASS_AND_INTERFACE_RESOLUTION, EXCS_FIELD_AND_METHOD_RESOLUTION, EXCS_INTERFACE_METHOD_RESOLUTION, EXCS_STRING_RESOLUTION, EXCS_ARRAY_EXCEPTION,
}
/**
* The mother of all exceptions
*/
public static final Class<Throwable> THROWABLE = Throwable.class;
/**
* Super class of any run-time exception
*/
public static final Class<RuntimeException> RUNTIME_EXCEPTION = RuntimeException.class;
/**
* Super class of any linking exception (aka Linkage Error)
*/
public static final Class<LinkageError> LINKING_EXCEPTION = LinkageError.class;
/**
* Linking Exceptions
*/
public static final Class<ClassCircularityError> CLASS_CIRCULARITY_ERROR = ClassCircularityError.class;
public static final Class<ClassFormatError> CLASS_FORMAT_ERROR = ClassFormatError.class;
public static final Class<ExceptionInInitializerError> EXCEPTION_IN_INITIALIZER_ERROR = ExceptionInInitializerError.class;
public static final Class<IncompatibleClassChangeError> INCOMPATIBLE_CLASS_CHANGE_ERROR = IncompatibleClassChangeError.class;
public static final Class<AbstractMethodError> ABSTRACT_METHOD_ERROR = AbstractMethodError.class;
public static final Class<IllegalAccessError> ILLEGAL_ACCESS_ERROR = IllegalAccessError.class;
public static final Class<InstantiationError> INSTANTIATION_ERROR = InstantiationError.class;
public static final Class<NoSuchFieldError> NO_SUCH_FIELD_ERROR = NoSuchFieldError.class;
public static final Class<NoSuchMethodError> NO_SUCH_METHOD_ERROR = NoSuchMethodError.class;
public static final Class<NoClassDefFoundError> NO_CLASS_DEF_FOUND_ERROR = NoClassDefFoundError.class;
public static final Class<UnsatisfiedLinkError> UNSATISFIED_LINK_ERROR = UnsatisfiedLinkError.class;
public static final Class<VerifyError> VERIFY_ERROR = VerifyError.class;
/* UnsupportedClassVersionError is new in JDK 1.2 */
// public static final Class UnsupportedClassVersionError = UnsupportedClassVersionError.class;
/**
* Run-Time Exceptions
*/
public static final Class<NullPointerException> NULL_POINTER_EXCEPTION = NullPointerException.class;
public static final Class<ArrayIndexOutOfBoundsException> ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION = ArrayIndexOutOfBoundsException.class;
public static final Class<ArithmeticException> ARITHMETIC_EXCEPTION = ArithmeticException.class;
public static final Class<NegativeArraySizeException> NEGATIVE_ARRAY_SIZE_EXCEPTION = NegativeArraySizeException.class;
public static final Class<ClassCastException> CLASS_CAST_EXCEPTION = ClassCastException.class;
public static final Class<IllegalMonitorStateException> ILLEGAL_MONITOR_STATE = IllegalMonitorStateException.class;
/**
* Pre-defined exception arrays according to chapters 5.1-5.4 of the Java Virtual Machine Specification
*/
private static final Class<?>[] EXCS_CLASS_AND_INTERFACE_RESOLUTION = {NO_CLASS_DEF_FOUND_ERROR, CLASS_FORMAT_ERROR, VERIFY_ERROR, ABSTRACT_METHOD_ERROR,
EXCEPTION_IN_INITIALIZER_ERROR, ILLEGAL_ACCESS_ERROR}; // Chapter 5.1
private static final Class<?>[] EXCS_FIELD_AND_METHOD_RESOLUTION = {NO_SUCH_FIELD_ERROR, ILLEGAL_ACCESS_ERROR, NO_SUCH_METHOD_ERROR}; // Chapter 5.2
/**
* Empty array.
*/
private static final Class<?>[] EXCS_INTERFACE_METHOD_RESOLUTION = new Class<?>[0]; // Chapter 5.3 (as below)
/**
* Empty array.
*/
private static final Class<?>[] EXCS_STRING_RESOLUTION = new Class<?>[0];
// Chapter 5.4 (no errors but the ones that _always_ could happen! How stupid.)
private static final Class<?>[] EXCS_ARRAY_EXCEPTION = {NULL_POINTER_EXCEPTION, ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION};
/**
* Creates a copy of the specified Exception Class array combined with any additional Exception classes.
*
* @param type the basic array type
* @param extraClasses additional classes, if any
* @return the merged array
*/
public static Class<?>[] createExceptions(final EXCS type, final Class<?>... extraClasses) {
switch (type) {
case EXCS_CLASS_AND_INTERFACE_RESOLUTION:
return mergeExceptions(EXCS_CLASS_AND_INTERFACE_RESOLUTION, extraClasses);
case EXCS_ARRAY_EXCEPTION:
return mergeExceptions(EXCS_ARRAY_EXCEPTION, extraClasses);
case EXCS_FIELD_AND_METHOD_RESOLUTION:
return mergeExceptions(EXCS_FIELD_AND_METHOD_RESOLUTION, extraClasses);
case EXCS_INTERFACE_METHOD_RESOLUTION:
return mergeExceptions(EXCS_INTERFACE_METHOD_RESOLUTION, extraClasses);
case EXCS_STRING_RESOLUTION:
return mergeExceptions(EXCS_STRING_RESOLUTION, extraClasses);
default:
throw new AssertionError("Cannot happen; unexpected enum value: " + type);
}
}
// helper method to merge exception class arrays
private static Class<?>[] mergeExceptions(final Class<?>[] input, final Class<?>... extraClasses) {
return Utils.arraysAppend(input, extraClasses);
}
}

View file

@ -0,0 +1,206 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.util.SyntheticRepository;
/**
* The repository maintains informations about class interdependencies, e.g., whether a class is a sub-class of another.
* Delegates actual class loading to SyntheticRepository with current class path by default.
*
* @see com.sun.org.apache.bcel.internal.util.Repository
* @see SyntheticRepository
*
* @LastModified: Sept 2025
*/
public abstract class Repository {
private static com.sun.org.apache.bcel.internal.util.Repository repository = SyntheticRepository.getInstance();
/**
* Adds clazz to repository if there isn't an equally named class already in there.
*
* @return old entry in repository
*/
public static JavaClass addClass(final JavaClass clazz) {
final JavaClass old = repository.findClass(clazz.getClassName());
repository.storeClass(clazz);
return old;
}
/**
* Clears the repository.
*/
public static void clearCache() {
repository.clear();
}
/**
* @return all interfaces implemented by class and its super classes and the interfaces that those interfaces extend,
* and so on. (Some people call this a transitive hull).
* @throws ClassNotFoundException if any of the class's superclasses or superinterfaces can't be found
*/
public static JavaClass[] getInterfaces(final JavaClass clazz) throws ClassNotFoundException {
return clazz.getAllInterfaces();
}
/**
* @return all interfaces implemented by class and its super classes and the interfaces that extend those interfaces,
* and so on
* @throws ClassNotFoundException if the named class can't be found, or if any of its superclasses or superinterfaces
* can't be found
*/
public static JavaClass[] getInterfaces(final String className) throws ClassNotFoundException {
return getInterfaces(lookupClass(className));
}
/**
* @return currently used repository instance
*/
public static com.sun.org.apache.bcel.internal.util.Repository getRepository() {
return repository;
}
/**
* @return list of super classes of clazz in ascending order, i.e., Object is always the last element
* @throws ClassNotFoundException if any of the superclasses can't be found
*/
public static JavaClass[] getSuperClasses(final JavaClass clazz) throws ClassNotFoundException {
return clazz.getSuperClasses();
}
/**
* @return list of super classes of clazz in ascending order, i.e., Object is always the last element.
* @throws ClassNotFoundException if the named class or any of its superclasses can't be found
*/
public static JavaClass[] getSuperClasses(final String className) throws ClassNotFoundException {
return getSuperClasses(lookupClass(className));
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if any superclasses or superinterfaces of clazz can't be found
*/
public static boolean implementationOf(final JavaClass clazz, final JavaClass inter) throws ClassNotFoundException {
return clazz.implementationOf(inter);
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if inter or any superclasses or superinterfaces of clazz can't be found
*/
public static boolean implementationOf(final JavaClass clazz, final String inter) throws ClassNotFoundException {
return implementationOf(clazz, lookupClass(inter));
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if clazz or any superclasses or superinterfaces of clazz can't be found
*/
public static boolean implementationOf(final String clazz, final JavaClass inter) throws ClassNotFoundException {
return implementationOf(lookupClass(clazz), inter);
}
/**
* @return true, if clazz is an implementation of interface inter
* @throws ClassNotFoundException if clazz, inter, or any superclasses or superinterfaces of clazz can't be found
*/
public static boolean implementationOf(final String clazz, final String inter) throws ClassNotFoundException {
return implementationOf(lookupClass(clazz), lookupClass(inter));
}
/**
* Equivalent to runtime "instanceof" operator.
*
* @return true, if clazz is an instance of superclass
* @throws ClassNotFoundException if any superclasses or superinterfaces of clazz can't be found
*/
public static boolean instanceOf(final JavaClass clazz, final JavaClass superclass) throws ClassNotFoundException {
return clazz.instanceOf(superclass);
}
/**
* @return true, if clazz is an instance of superclass
* @throws ClassNotFoundException if superclass can't be found
*/
public static boolean instanceOf(final JavaClass clazz, final String superclass) throws ClassNotFoundException {
return instanceOf(clazz, lookupClass(superclass));
}
/**
* @return true, if clazz is an instance of superclass
* @throws ClassNotFoundException if clazz can't be found
*/
public static boolean instanceOf(final String clazz, final JavaClass superclass) throws ClassNotFoundException {
return instanceOf(lookupClass(clazz), superclass);
}
/**
* @return true, if clazz is an instance of superclass
* @throws ClassNotFoundException if either clazz or superclass can't be found
*/
public static boolean instanceOf(final String clazz, final String superclass) throws ClassNotFoundException {
return instanceOf(lookupClass(clazz), lookupClass(superclass));
}
/**
* Tries to find class source using the internal repository instance.
*
* @see Class
* @return JavaClass object for given runtime class
* @throws ClassNotFoundException if the class could not be found or parsed correctly
*/
public static JavaClass lookupClass(final Class<?> clazz) throws ClassNotFoundException {
return repository.loadClass(clazz);
}
/**
* Lookups class somewhere found on your CLASSPATH, or whereever the repository instance looks for it.
*
* @return class object for given fully qualified class name
* @throws ClassNotFoundException if the class could not be found or parsed correctly
*/
public static JavaClass lookupClass(final String className) throws ClassNotFoundException {
return repository.loadClass(className);
}
/**
* Removes given class from repository.
*/
public static void removeClass(final JavaClass clazz) {
repository.removeClass(clazz);
}
/**
* Removes class with given (fully qualified) name from repository.
*/
public static void removeClass(final String clazz) {
repository.removeClass(repository.findClass(clazz));
}
/**
* Sets repository instance to be used for class loading
*/
public static void setRepository(final com.sun.org.apache.bcel.internal.util.Repository rep) {
repository = rep;
}
}

View file

@ -0,0 +1,397 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import com.sun.org.apache.bcel.internal.Const;
/**
* Super class for all objects that have modifiers like private, final, ... I.e.
* classes, fields, and methods.
*
* @LastModified: Sept 2025
*/
public abstract class AccessFlags {
/**
* Access flags.
*
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter.
*/
@java.lang.Deprecated
protected int access_flags; // TODO not used externally at present
/**
* Constructs a new instance.
*/
public AccessFlags() {
}
/**
* Constructs a new instance.
*
* @param accessFlags initial access flags.
*/
public AccessFlags(final int accessFlags) {
access_flags = accessFlags;
}
/**
* Gets access flags.
*
* @return Access flags of the object aka. "modifiers".
*/
public final int getAccessFlags() {
return access_flags;
}
/**
* Gets access flags.
*
* @return Access flags of the object also known as modifiers.
*/
public final int getModifiers() {
return access_flags;
}
/**
* Tests whether the abstract bit is on.
*
* @return whether the abstract bit is on.
*/
public final boolean isAbstract() {
return test(Const.ACC_ABSTRACT);
}
/**
* Sets the abstract bit.
*
* @param flag The new value.
*/
public final void isAbstract(final boolean flag) {
setFlag(Const.ACC_ABSTRACT, flag);
}
/**
* Tests whether the annotation bit is on.
*
* @return whether the annotation bit is on.
*/
public final boolean isAnnotation() {
return test(Const.ACC_ANNOTATION);
}
/**
* Sets the annotation bit.
*
* @param flag The new value.
*/
public final void isAnnotation(final boolean flag) {
setFlag(Const.ACC_ANNOTATION, flag);
}
/**
* Tests whether the enum bit is on.
*
* @return whether the enum bit is on.
*/
public final boolean isEnum() {
return test(Const.ACC_ENUM);
}
/**
* Sets the enum bit.
*
* @param flag The new value.
*/
public final void isEnum(final boolean flag) {
setFlag(Const.ACC_ENUM, flag);
}
/**
* Tests whether the final bit is on.
*
* @return whether the final bit is on.
*/
public final boolean isFinal() {
return test(Const.ACC_FINAL);
}
/**
* Sets the final bit.
*
* @param flag The new value.
*/
public final void isFinal(final boolean flag) {
setFlag(Const.ACC_FINAL, flag);
}
/**
* Tests whether the interface bit is on.
*
* @return whether the interface bit is on.
*/
public final boolean isInterface() {
return test(Const.ACC_INTERFACE);
}
/**
* Sets the interface bit.
*
* @param flag The new value.
*/
public final void isInterface(final boolean flag) {
setFlag(Const.ACC_INTERFACE, flag);
}
/**
* Tests whether the native bit is on.
*
* @return whether the native bit is on.
*/
public final boolean isNative() {
return test(Const.ACC_NATIVE);
}
/**
* Sets the native bit.
*
* @param flag The new value.
*/
public final void isNative(final boolean flag) {
setFlag(Const.ACC_NATIVE, flag);
}
/**
* Tests whether the private bit is on.
*
* @return whether the private bit is on.
*/
public final boolean isPrivate() {
return test(Const.ACC_PRIVATE);
}
/**
* Sets the private bit.
*
* @param flag The new value.
*/
public final void isPrivate(final boolean flag) {
setFlag(Const.ACC_PRIVATE, flag);
}
/**
* Tests whether the protected bit is on.
*
* @return whether the protected bit is on.
*/
public final boolean isProtected() {
return test(Const.ACC_PROTECTED);
}
/**
* Sets the protected bit.
*
* @param flag The new value.
*/
public final void isProtected(final boolean flag) {
setFlag(Const.ACC_PROTECTED, flag);
}
/**
* Tests whether the public bit is on.
*
* @return whether the public bit is on.
*/
public final boolean isPublic() {
return test(Const.ACC_PUBLIC);
}
/**
* Sets the public bit.
*
* @param flag The new value.
*/
public final void isPublic(final boolean flag) {
setFlag(Const.ACC_PUBLIC, flag);
}
/**
* Tests whether the static bit is on.
*
* @return whether the static bit is on.
*/
public final boolean isStatic() {
return test(Const.ACC_STATIC);
}
/**
* Sets the static bit.
*
* @param flag The new value.
*/
public final void isStatic(final boolean flag) {
setFlag(Const.ACC_STATIC, flag);
}
/**
* Tests whether the strict bit is on.
*
* @return whether the strict bit is on.
*/
public final boolean isStrictfp() {
return test(Const.ACC_STRICT);
}
/**
* Sets the strict bit.
*
* @param flag The new value.
*/
public final void isStrictfp(final boolean flag) {
setFlag(Const.ACC_STRICT, flag);
}
/**
* Tests whether the synchronized bit is on.
*
* @return whether the synchronized bit is on.
*/
public final boolean isSynchronized() {
return test(Const.ACC_SYNCHRONIZED);
}
/**
* Sets the synchronized bit.
*
* @param flag The new value.
*/
public final void isSynchronized(final boolean flag) {
setFlag(Const.ACC_SYNCHRONIZED, flag);
}
/**
* Tests whether the synthetic bit is on.
*
* @return whether the synthetic bit is on.
*/
public final boolean isSynthetic() {
return test(Const.ACC_SYNTHETIC);
}
/**
* Sets the synthetic bit.
*
* @param flag The new value.
*/
public final void isSynthetic(final boolean flag) {
setFlag(Const.ACC_SYNTHETIC, flag);
}
/**
* Tests whether the transient bit is on.
*
* @return whether the varargs bit is on.
*/
public final boolean isTransient() {
return test(Const.ACC_TRANSIENT);
}
/**
* Sets the varargs bit.
*
* @param flag The new value.
*/
public final void isTransient(final boolean flag) {
setFlag(Const.ACC_TRANSIENT, flag);
}
/**
* Tests whether the varargs bit is on.
*
* @return whether the varargs bit is on.
*/
public final boolean isVarArgs() {
return test(Const.ACC_VARARGS);
}
/**
* Sets the varargs bit.
*
* @param flag The new value.
*/
public final void isVarArgs(final boolean flag) {
setFlag(Const.ACC_VARARGS, flag);
}
/**
* Tests whether the volatile bit is on.
*
* @return whether the volatile bit is on.
*/
public final boolean isVolatile() {
return test(Const.ACC_VOLATILE);
}
/**
* Sets the volatile bit.
*
* @param flag The new value.
*/
public final void isVolatile(final boolean flag) {
setFlag(Const.ACC_VOLATILE, flag);
}
/**
* Sets access flags also known as modifiers.
*
* @param accessFlags Access flags of the object.
*/
public final void setAccessFlags(final int accessFlags) {
this.access_flags = accessFlags;
}
private void setFlag(final int flag, final boolean set) {
if ((access_flags & flag) != 0) { // Flag is set already
if (!set) {
access_flags ^= flag;
}
} else if (set) {
access_flags |= flag;
}
}
/**
* Sets access flags aka "modifiers".
*
* @param accessFlags Access flags of the object.
*/
public final void setModifiers(final int accessFlags) {
setAccessFlags(accessFlags);
}
/**
* Tests whether the bit is on.
*
* @param test the bit to test.
* @return whether the bit is on.
*/
private boolean test(final short test) {
return (access_flags & test) != 0;
}
}

View file

@ -0,0 +1,96 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Represents the default value of a annotation for a method info.
*
* @since 6.0
*/
public class AnnotationDefault extends Attribute {
private ElementValue defaultValue;
/**
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
*/
AnnotationDefault(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (ElementValue) null, constantPool);
defaultValue = ElementValue.readElementValue(input, constantPool);
}
/**
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param defaultValue the annotation's default value
* @param constantPool Array of constants
*/
public AnnotationDefault(final int nameIndex, final int length, final ElementValue defaultValue, final ConstantPool constantPool) {
super(Const.ATTR_ANNOTATION_DEFAULT, nameIndex, length, constantPool);
this.defaultValue = defaultValue;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitAnnotationDefault(this);
}
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public final void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
defaultValue.dump(dos);
}
/**
* @return the default value
*/
public final ElementValue getDefaultValue() {
return defaultValue;
}
/**
* @param defaultValue the default value of this methodinfo's annotation
*/
public final void setDefaultValue(final ElementValue defaultValue) {
this.defaultValue = defaultValue;
}
}

View file

@ -0,0 +1,61 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* @since 6.0
*/
public class AnnotationElementValue extends ElementValue {
// For annotation element values, this is the annotation
private final AnnotationEntry annotationEntry;
public AnnotationElementValue(final int type, final AnnotationEntry annotationEntry, final ConstantPool cpool) {
super(type, cpool);
if (type != ANNOTATION) {
throw new ClassFormatException("Only element values of type annotation can be built with this ctor - type specified: " + type);
}
this.annotationEntry = annotationEntry;
}
@Override
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getType()); // u1 type of value (ANNOTATION == '@')
annotationEntry.dump(dos);
}
public AnnotationEntry getAnnotationEntry() {
return annotationEntry;
}
@Override
public String stringifyValue() {
return annotationEntry.toString();
}
@Override
public String toString() {
return stringifyValue();
}
}

View file

@ -0,0 +1,168 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import jdk.xml.internal.Utils;
/**
* Represents one annotation in the annotation table
*
* @since 6.0
* @LastModified: Sept 2025
*/
public class AnnotationEntry implements Node {
public static final AnnotationEntry[] EMPTY_ARRAY = {};
public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attributes) {
// Find attributes that contain annotation data
return Utils.streamOfIfNonNull(attributes).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries()))
.toArray(AnnotationEntry[]::new);
}
/**
* Factory method to create an AnnotionEntry from a DataInput
*
* @param input
* @param constantPool
* @param isRuntimeVisible
* @return the entry
* @throws IOException if an I/O error occurs.
*/
public static AnnotationEntry read(final DataInput input, final ConstantPool constantPool, final boolean isRuntimeVisible) throws IOException {
final AnnotationEntry annotationEntry = new AnnotationEntry(input.readUnsignedShort(), constantPool, isRuntimeVisible);
final int numElementValuePairs = input.readUnsignedShort();
for (int i = 0; i < numElementValuePairs; i++) {
annotationEntry.elementValuePairs
.add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool));
}
return annotationEntry;
}
private final int typeIndex;
private final ConstantPool constantPool;
private final boolean isRuntimeVisible;
private final List<ElementValuePair> elementValuePairs;
public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) {
this.typeIndex = typeIndex;
this.constantPool = constantPool;
this.isRuntimeVisible = isRuntimeVisible;
this.elementValuePairs = new ArrayList<>();
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitAnnotationEntry(this);
}
public void addElementNameValuePair(final ElementValuePair elementNameValuePair) {
elementValuePairs.add(elementNameValuePair);
}
public void dump(final DataOutputStream dos) throws IOException {
dos.writeShort(typeIndex); // u2 index of type name in cpool
dos.writeShort(elementValuePairs.size()); // u2 element_value pair
// count
for (final ElementValuePair envp : elementValuePairs) {
envp.dump(dos);
}
}
/**
* @return the annotation type name
*/
public String getAnnotationType() {
return constantPool.getConstantUtf8(typeIndex).getBytes();
}
/**
* @return the annotation type index
*/
public int getAnnotationTypeIndex() {
return typeIndex;
}
public ConstantPool getConstantPool() {
return constantPool;
}
/**
* @return the element value pairs in this annotation entry
*/
public ElementValuePair[] getElementValuePairs() {
// TODO return List
return elementValuePairs.toArray(ElementValuePair.EMPTY_ARRAY);
}
/**
* @return the number of element value pairs in this annotation entry
*/
public final int getNumElementValuePairs() {
return elementValuePairs.size();
}
public int getTypeIndex() {
return typeIndex;
}
public boolean isRuntimeVisible() {
return isRuntimeVisible;
}
public String toShortString() {
final StringBuilder result = new StringBuilder();
result.append("@");
result.append(getAnnotationType());
final ElementValuePair[] evPairs = getElementValuePairs();
if (evPairs.length > 0) {
result.append("(");
for (final ElementValuePair element : evPairs) {
result.append(element.toShortString());
result.append(", ");
}
// remove last ", "
result.setLength(result.length() - 2);
result.append(")");
}
return result.toString();
}
@Override
public String toString() {
return toShortString();
}
}

View file

@ -0,0 +1,157 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
/**
* base class for annotations
*
* @since 6.0
*/
public abstract class Annotations extends Attribute implements Iterable<AnnotationEntry> {
private AnnotationEntry[] annotationTable;
private final boolean isRuntimeVisible;
/**
* Constructs an instance.
*
* @param annotationType the subclass type of the annotation
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param annotationTable the actual annotations
* @param constantPool Array of constants
* @param isRuntimeVisible whether this Annotation visible at runtime
*/
public Annotations(final byte annotationType, final int nameIndex, final int length, final AnnotationEntry[] annotationTable,
final ConstantPool constantPool, final boolean isRuntimeVisible) {
super(annotationType, nameIndex, length, constantPool);
setAnnotationTable(annotationTable);
this.isRuntimeVisible = isRuntimeVisible;
}
/**
* Constructs an instance.
*
* @param annotationType the subclass type of the annotation
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @param isRuntimeVisible whether this Annotation visible at runtime
* @throws IOException if an I/O error occurs.
*/
Annotations(final byte annotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool,
final boolean isRuntimeVisible) throws IOException {
this(annotationType, nameIndex, length, (AnnotationEntry[]) null, constantPool, isRuntimeVisible);
final int annotationTableLength = input.readUnsignedShort();
annotationTable = new AnnotationEntry[annotationTableLength];
for (int i = 0; i < annotationTableLength; i++) {
annotationTable[i] = AnnotationEntry.read(input, constantPool, isRuntimeVisible);
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly
* defined by the contents of a Java class. I.e., the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitAnnotation(this);
}
@Override
public Attribute copy(final ConstantPool constantPool) {
// TODO Auto-generated method stub
return null;
}
/**
* Gets the array of annotation entries in this annotation
*/
public AnnotationEntry[] getAnnotationEntries() {
return annotationTable;
}
/**
* Gets the number of annotation entries in this annotation.
*
* @return the number of annotation entries in this annotation
*/
public final int getNumAnnotations() {
return annotationTable.length;
}
public boolean isRuntimeVisible() {
return isRuntimeVisible;
}
@Override
public Iterator<AnnotationEntry> iterator() {
return Stream.of(annotationTable).iterator();
}
/**
* Sets the entries to set in this annotation.
*
* @param annotationTable the entries to set in this annotation
*/
public final void setAnnotationTable(final AnnotationEntry[] annotationTable) {
this.annotationTable = annotationTable != null ? annotationTable : AnnotationEntry.EMPTY_ARRAY;
}
/**
* Converts to a String representation.
*
* @return String representation
*/
@Override
public final String toString() {
final StringBuilder buf = new StringBuilder(Const.getAttributeName(getTag()));
buf.append(":\n");
for (int i = 0; i < annotationTable.length; i++) {
buf.append(" ").append(annotationTable[i]);
if (i < annotationTable.length - 1) {
buf.append('\n');
}
}
return buf.toString();
}
protected void writeAnnotations(final DataOutputStream dos) throws IOException {
dos.writeShort(annotationTable.length);
for (final AnnotationEntry element : annotationTable) {
element.dump(dos);
}
}
}

View file

@ -0,0 +1,86 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* @since 6.0
*/
public class ArrayElementValue extends ElementValue {
// For array types, this is the array
private final ElementValue[] elementValues;
public ArrayElementValue(final int type, final ElementValue[] elementValues, final ConstantPool cpool) {
super(type, cpool);
if (type != ARRAY) {
throw new ClassFormatException("Only element values of type array can be built with this ctor - type specified: " + type);
}
this.elementValues = elementValues != null ? elementValues : EMPTY_ARRAY;
}
@Override
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getType()); // u1 type of value (ARRAY == '[')
dos.writeShort(elementValues.length);
for (final ElementValue evalue : elementValues) {
evalue.dump(dos);
}
}
public ElementValue[] getElementValuesArray() {
return elementValues;
}
public int getElementValuesArraySize() {
return elementValues.length;
}
@Override
public String stringifyValue() {
final StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < elementValues.length; i++) {
sb.append(elementValues[i].stringifyValue());
if (i + 1 < elementValues.length) {
sb.append(",");
}
}
sb.append("]");
return sb.toString();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("{");
for (int i = 0; i < elementValues.length; i++) {
sb.append(elementValues[i]);
if (i + 1 < elementValues.length) {
sb.append(",");
}
}
sb.append("}");
return sb.toString();
}
}

View file

@ -0,0 +1,372 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* Abstract super class for <em>Attribute</em> objects. Currently the <em>ConstantValue</em>, <em>SourceFile</em>, <em>Code</em>, <em>Exceptiontable</em>,
* <em>LineNumberTable</em>, <em>LocalVariableTable</em>, <em>InnerClasses</em> and <em>Synthetic</em> attributes are supported. The <em>Unknown</em> attribute
* stands for non-standard-attributes.
*
* <pre>
* attribute_info {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 info[attribute_length];
* }
* </pre>
*
* @see ConstantValue
* @see SourceFile
* @see Code
* @see Unknown
* @see ExceptionTable
* @see LineNumberTable
* @see LocalVariableTable
* @see InnerClasses
* @see Synthetic
* @see Deprecated
* @see Signature
* @LastModified: Sept 2025
*/
public abstract class Attribute implements Cloneable, Node {
private static final boolean debug = false;
private static final Map<String, Object> READERS = new HashMap<>();
/**
* Empty array.
*
* @since 6.6.0
*/
public static final Attribute[] EMPTY_ARRAY = {};
/**
* Add an Attribute reader capable of parsing (user-defined) attributes named "name". You should not add readers for the
* standard attributes such as "LineNumberTable", because those are handled internally.
*
* @param name the name of the attribute as stored in the class file
* @param unknownAttributeReader the reader object
*/
public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) {
READERS.put(name, unknownAttributeReader);
}
protected static void println(final String msg) {
if (debug) {
System.err.println(msg);
}
}
/**
* Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It
* is called by the Field and Method constructor methods.
*
* @see Field
* @see Method
*
* @param dataInput Input stream
* @param constantPool Array of constants
* @return Attribute
* @throws IOException if an I/O error occurs.
* @since 6.0
*/
public static Attribute readAttribute(final DataInput dataInput, final ConstantPool constantPool) throws IOException {
byte tag = Const.ATTR_UNKNOWN; // Unknown attribute
// Get class name from constant pool via 'name_index' indirection
final int nameIndex = dataInput.readUnsignedShort();
final String name = constantPool.getConstantUtf8(nameIndex).getBytes();
// Length of data in bytes
final int length = dataInput.readInt();
// Compare strings to find known attribute
for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++) {
if (name.equals(Const.getAttributeName(i))) {
tag = i; // found!
break;
}
}
// Call proper constructor, depending on 'tag'
switch (tag) {
case Const.ATTR_UNKNOWN:
final Object r = READERS.get(name);
if (r instanceof UnknownAttributeReader) {
return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, dataInput, constantPool);
}
return new Unknown(nameIndex, length, dataInput, constantPool);
case Const.ATTR_CONSTANT_VALUE:
return new ConstantValue(nameIndex, length, dataInput, constantPool);
case Const.ATTR_SOURCE_FILE:
return new SourceFile(nameIndex, length, dataInput, constantPool);
case Const.ATTR_CODE:
return new Code(nameIndex, length, dataInput, constantPool);
case Const.ATTR_EXCEPTIONS:
return new ExceptionTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_LINE_NUMBER_TABLE:
return new LineNumberTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_LOCAL_VARIABLE_TABLE:
return new LocalVariableTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_INNER_CLASSES:
return new InnerClasses(nameIndex, length, dataInput, constantPool);
case Const.ATTR_SYNTHETIC:
return new Synthetic(nameIndex, length, dataInput, constantPool);
case Const.ATTR_DEPRECATED:
return new Deprecated(nameIndex, length, dataInput, constantPool);
case Const.ATTR_PMG:
return new PMGClass(nameIndex, length, dataInput, constantPool);
case Const.ATTR_SIGNATURE:
return new Signature(nameIndex, length, dataInput, constantPool);
case Const.ATTR_STACK_MAP:
// old style stack map: unneeded for JDK5 and below;
// illegal(?) for JDK6 and above. So just delete with a warning.
println("Warning: Obsolete StackMap attribute ignored.");
return new Unknown(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
return new RuntimeVisibleAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
return new RuntimeInvisibleAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
return new RuntimeVisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
return new RuntimeInvisibleParameterAnnotations(nameIndex, length, dataInput, constantPool);
case Const.ATTR_ANNOTATION_DEFAULT:
return new AnnotationDefault(nameIndex, length, dataInput, constantPool);
case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
return new LocalVariableTypeTable(nameIndex, length, dataInput, constantPool);
case Const.ATTR_ENCLOSING_METHOD:
return new EnclosingMethod(nameIndex, length, dataInput, constantPool);
case Const.ATTR_STACK_MAP_TABLE:
// read new style stack map: StackMapTable. The rest of the code
// calls this a StackMap for historical reasons.
return new StackMap(nameIndex, length, dataInput, constantPool);
case Const.ATTR_BOOTSTRAP_METHODS:
return new BootstrapMethods(nameIndex, length, dataInput, constantPool);
case Const.ATTR_METHOD_PARAMETERS:
return new MethodParameters(nameIndex, length, dataInput, constantPool);
case Const.ATTR_MODULE:
return new Module(nameIndex, length, dataInput, constantPool);
case Const.ATTR_MODULE_PACKAGES:
return new ModulePackages(nameIndex, length, dataInput, constantPool);
case Const.ATTR_MODULE_MAIN_CLASS:
return new ModuleMainClass(nameIndex, length, dataInput, constantPool);
case Const.ATTR_NEST_HOST:
return new NestHost(nameIndex, length, dataInput, constantPool);
case Const.ATTR_NEST_MEMBERS:
return new NestMembers(nameIndex, length, dataInput, constantPool);
case Const.ATTR_RECORD:
return new Record(nameIndex, length, dataInput, constantPool);
default:
// Never reached
throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
}
}
/**
* Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It
* is called by the Field and Method constructor methods.
*
* @see Field
* @see Method
*
* @param dataInputStream Input stream
* @param constantPool Array of constants
* @return Attribute
* @throws IOException if an I/O error occurs.
*/
public static Attribute readAttribute(final DataInputStream dataInputStream, final ConstantPool constantPool) throws IOException {
return readAttribute((DataInput) dataInputStream, constantPool);
}
/**
* Remove attribute reader
*
* @param name the name of the attribute as stored in the class file
*/
public static void removeAttributeReader(final String name) {
READERS.remove(name);
}
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int name_index; // Points to attribute name in constant pool TODO make private (has getter & setter)
/**
* @deprecated (since 6.0) (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int length; // Content length of attribute field TODO make private (has getter & setter)
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected byte tag; // Tag to distinguish subclasses TODO make private & final; supposed to be immutable
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected ConstantPool constant_pool; // TODO make private (has getter & setter)
/**
* Constructs an instance.
*
* <pre>
* attribute_info {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 info[attribute_length];
* }
* </pre>
*
* @param tag tag.
* @param nameIndex u2 name index.
* @param length u4 length.
* @param constantPool constant pool.
*/
protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) {
this.tag = tag;
this.name_index = Args.requireU2(nameIndex, 0, constantPool.getLength(), getClass().getSimpleName() + " name index");
this.length = Args.requireU4(length, getClass().getSimpleName() + " attribute length");
this.constant_pool = constantPool;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public abstract void accept(Visitor v);
/**
* Use copy() if you want to have a deep copy(), i.e., with all references copied correctly.
*
* @return shallow copy of this attribute
*/
@Override
public Object clone() {
Attribute attr = null;
try {
attr = (Attribute) super.clone();
} catch (final CloneNotSupportedException e) {
throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
}
return attr;
}
/**
* @param constantPool constant pool to save.
* @return deep copy of this attribute.
*/
public abstract Attribute copy(ConstantPool constantPool);
/**
* Dumps attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(name_index);
file.writeInt(length);
}
/**
* @return Constant pool used by this object.
* @see ConstantPool
*/
public final ConstantPool getConstantPool() {
return constant_pool;
}
/**
* @return Length of attribute field in bytes.
*/
public final int getLength() {
return length;
}
/**
* @return Name of attribute
* @since 6.0
*/
public String getName() {
return constant_pool.getConstantUtf8(name_index).getBytes();
}
/**
* @return Name index in constant pool of attribute name.
*/
public final int getNameIndex() {
return name_index;
}
/**
* @return Tag of attribute, i.e., its type. Value may not be altered, thus there is no setTag() method.
*/
public final byte getTag() {
return tag;
}
/**
* @param constantPool Constant pool to be used for this object.
* @see ConstantPool
*/
public final void setConstantPool(final ConstantPool constantPool) {
this.constant_pool = constantPool;
}
/**
* @param length length in bytes.
*/
public final void setLength(final int length) {
this.length = length;
}
/**
* @param nameIndex of attribute.
*/
public final void setNameIndex(final int nameIndex) {
this.name_index = nameIndex;
}
/**
* @return attribute name.
*/
@Override
public String toString() {
return Const.getAttributeName(tag);
}
}

View file

@ -0,0 +1,55 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
/**
* Unknown (non-standard) attributes may be read via user-defined factory objects that can be registered with the
* Attribute.addAttributeReader method. These factory objects should implement this interface.
*
* @see Attribute
*
* @deprecated Use UnknownAttributeReader instead
*/
@java.lang.Deprecated
public interface AttributeReader {
/**
* When this attribute reader is added via the static method Attribute.addAttributeReader, an attribute name is
* associated with it. As the class file parser parses attributes, it will call various AttributeReaders based on the
* name of the attributes it is constructing.
*
* @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute.
*
* @param length The length of the data contained in the attribute. This is written into the constant pool and should
* agree with what the factory expects the length to be.
*
* @param file This is the data input stream that the factory needs to read its data from.
*
* @param constantPool This is the constant pool associated with the Attribute that we are constructing.
*
* @return The user-defined AttributeReader should take this data and use it to construct an attribute. In the case of
* errors, a null can be returned which will cause the parsing of the class file to fail.
*
* @see Attribute#addAttributeReader( String, AttributeReader )
*/
Attribute createAttribute(int nameIndex, int length, java.io.DataInputStream file, ConstantPool constantPool);
}

View file

@ -0,0 +1,173 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import jdk.xml.internal.Utils;
/**
* This class represents a bootstrap method attribute, i.e., the bootstrap method ref, the number of bootstrap arguments
* and an array of the bootstrap arguments.
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
* The BootstrapMethods Attribute</a>
* @since 6.0
* @LastModified: Sept 2025
*/
public class BootstrapMethod implements Cloneable {
static final BootstrapMethod[] EMPTY_ARRAY = {};
/** Index of the CONSTANT_MethodHandle_info structure in the constant_pool table */
private int bootstrapMethodRef;
/** Array of references to the constant_pool table */
private int[] bootstrapArguments;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public BootstrapMethod(final BootstrapMethod c) {
this(c.getBootstrapMethodRef(), c.getBootstrapArguments());
}
/**
* Constructs object from input stream.
*
* @param input Input stream
* @throws IOException if an I/O error occurs.
*/
BootstrapMethod(final DataInput input) throws IOException {
this(input.readUnsignedShort(), input.readUnsignedShort());
for (int i = 0; i < bootstrapArguments.length; i++) {
bootstrapArguments[i] = input.readUnsignedShort();
}
}
// helper method
private BootstrapMethod(final int bootstrapMethodRef, final int numBootstrapArguments) {
this(bootstrapMethodRef, new int[numBootstrapArguments]);
}
/**
* @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
* @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
*/
public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) {
this.bootstrapMethodRef = bootstrapMethodRef;
setBootstrapArguments(bootstrapArguments);
}
/**
* @return deep copy of this object
*/
public BootstrapMethod copy() {
try {
return (BootstrapMethod) clone();
} catch (final CloneNotSupportedException ignore) {
// TODO should this throw?
}
return null;
}
/**
* Dump object to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public final void dump(final DataOutputStream file) throws IOException {
file.writeShort(bootstrapMethodRef);
file.writeShort(bootstrapArguments.length);
for (final int bootstrapArgument : bootstrapArguments) {
file.writeShort(bootstrapArgument);
}
}
/**
* @return int[] of bootstrap_method indices into constant_pool of CONSTANT_[type]_info
*/
public int[] getBootstrapArguments() {
return bootstrapArguments;
}
/**
* @return index into constant_pool of bootstrap_method
*/
public int getBootstrapMethodRef() {
return bootstrapMethodRef;
}
/**
* @return count of number of boostrap arguments
*/
public int getNumBootstrapArguments() {
return bootstrapArguments.length;
}
/**
* @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
*/
public void setBootstrapArguments(final int[] bootstrapArguments) {
this.bootstrapArguments = Utils.createEmptyArrayIfNull(bootstrapArguments);
}
/**
* @param bootstrapMethodRef int index into constant_pool of CONSTANT_MethodHandle
*/
public void setBootstrapMethodRef(final int bootstrapMethodRef) {
this.bootstrapMethodRef = bootstrapMethodRef;
}
/**
* @return String representation.
*/
@Override
public final String toString() {
return "BootstrapMethod(" + bootstrapMethodRef + ", " + bootstrapArguments.length + ", " + Arrays.toString(bootstrapArguments) + ")";
}
/**
* @return Resolved string representation
*/
public final String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String bootstrapMethodName = constantPool.constantToString(bootstrapMethodRef, Const.CONSTANT_MethodHandle);
buf.append(Utility.compactClassName(bootstrapMethodName, false));
final int bootstrapArgumentsLen = bootstrapArguments.length;
if (bootstrapArgumentsLen > 0) {
buf.append("\nMethod Arguments:");
for (int i = 0; i < bootstrapArgumentsLen; i++) {
buf.append("\n ").append(i).append(": ");
buf.append(constantPool.constantToString(constantPool.getConstant(bootstrapArguments[i])));
}
}
return buf.toString();
}
}

View file

@ -0,0 +1,163 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a BootstrapMethods attribute.
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23"> The class File Format :
* The BootstrapMethods Attribute</a>
* @since 6.0
*/
public class BootstrapMethods extends Attribute implements Iterable<BootstrapMethod> {
private BootstrapMethod[] bootstrapMethods; // TODO this could be made final (setter is not used)
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public BootstrapMethods(final BootstrapMethods c) {
this(c.getNameIndex(), c.getLength(), c.getBootstrapMethods(), c.getConstantPool());
}
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param bootstrapMethods array of bootstrap methods
* @param constantPool Array of constants
*/
public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) {
super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool);
setBootstrapMethods(bootstrapMethods);
}
/**
* Constructs object from Input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
BootstrapMethods(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (BootstrapMethod[]) null, constantPool);
final int numBootstrapMethods = input.readUnsignedShort();
bootstrapMethods = new BootstrapMethod[numBootstrapMethods];
for (int i = 0; i < numBootstrapMethods; i++) {
bootstrapMethods[i] = new BootstrapMethod(input);
}
}
/**
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitBootstrapMethods(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public BootstrapMethods copy(final ConstantPool constantPool) {
final BootstrapMethods c = (BootstrapMethods) clone();
c.bootstrapMethods = new BootstrapMethod[bootstrapMethods.length];
for (int i = 0; i < bootstrapMethods.length; i++) {
c.bootstrapMethods[i] = bootstrapMethods[i].copy();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump bootstrap methods attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(bootstrapMethods.length);
for (final BootstrapMethod bootstrapMethod : bootstrapMethods) {
bootstrapMethod.dump(file);
}
}
/**
* @return array of bootstrap method "records"
*/
public final BootstrapMethod[] getBootstrapMethods() {
return bootstrapMethods;
}
@Override
public Iterator<BootstrapMethod> iterator() {
return Stream.of(bootstrapMethods).iterator();
}
/**
* @param bootstrapMethods the array of bootstrap methods
*/
public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) {
this.bootstrapMethods = bootstrapMethods != null ? bootstrapMethods : BootstrapMethod.EMPTY_ARRAY;
}
/**
* @return String representation.
*/
@Override
public final String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("BootstrapMethods(");
buf.append(bootstrapMethods.length);
buf.append("):");
for (int i = 0; i < bootstrapMethods.length; i++) {
buf.append("\n");
final int start = buf.length();
buf.append(" ").append(i).append(": ");
final int indentCount = buf.length() - start;
final String[] lines = bootstrapMethods[i].toString(super.getConstantPool()).split("\\r?\\n");
buf.append(lines[0]);
for (int j = 1; j < lines.length; j++) {
buf.append("\n").append(" ", 0, indentCount).append(lines[j]);
}
}
return buf.toString();
}
}

View file

@ -0,0 +1,59 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* @since 6.0
*/
public class ClassElementValue extends ElementValue {
// For primitive types and string type, this points to the value entry in
// the cpool
// For 'class' this points to the class entry in the cpool
private final int idx;
public ClassElementValue(final int type, final int idx, final ConstantPool cpool) {
super(type, cpool);
this.idx = idx;
}
@Override
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getType()); // u1 kind of value
dos.writeShort(idx);
}
public String getClassString() {
return super.getConstantPool().getConstantUtf8(idx).getBytes();
}
public int getIndex() {
return idx;
}
@Override
public String stringifyValue() {
return super.getConstantPool().getConstantUtf8(idx).getBytes();
}
}

View file

@ -0,0 +1,71 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
/**
* Thrown when the BCEL attempts to read a class file and determines that a class is malformed or otherwise cannot be interpreted as a class file.
*/
public class ClassFormatException extends RuntimeException {
private static final long serialVersionUID = -3569097343160139969L;
/**
* Constructs a new instance with {@code null} as its detail message. The cause is not initialized, and may subsequently be initialized by a call to
* {@link #initCause}.
*/
public ClassFormatException() {
}
/**
* Constructs a new instance with the specified detail message. The cause is not initialized, and may subsequently be initialized by a call to
* {@link #initCause}.
*
* @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method.
*/
public ClassFormatException(final String message) {
super(message);
}
/**
* Constructs a new instance with the specified detail message and cause.
*
* @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). A {@code null} value is permitted, and indicates that
* the cause is nonexistent or unknown.
* @since 6.0
*/
public ClassFormatException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* Constructs a new instance with the specified cause and a detail message of {@code (cause==null ? null : cause.toString())} (which typically contains the
* class and detail message of {@code cause}). This constructor is useful for runtime exceptions that are little more than wrappers for other throwables.
*
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). A {@code null} value is permitted, and indicates that the
* cause is nonexistent or unknown.
* @since 6.7.0
*/
public ClassFormatException(final Throwable cause) {
super(cause);
}
}

View file

@ -0,0 +1,297 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.sun.org.apache.bcel.internal.Const;
/**
* Wrapper class that parses a given Java .class file. The method <a href ="#parse">parse</a> returns a
* <a href ="JavaClass.html"> JavaClass</a> object on success. When an I/O error or an inconsistency occurs an
* appropriate exception is propagated back to the caller.
*
* The structure and the names comply, except for a few conveniences, exactly with the
* <a href="https://docs.oracle.com/javase/specs/"> JVM specification 1.0</a>. See this paper for further details about
* the structure of a bytecode file.
*/
public final class ClassParser {
private static final int BUFSIZE = 8192;
private DataInputStream dataInputStream;
private final boolean fileOwned;
private final String fileName;
private String zipFile;
private int classNameIndex;
private int superclassNameIndex;
private int major; // Compiler version
private int minor; // Compiler version
private int accessFlags; // Access rights of parsed class
private int[] interfaces; // Names of implemented interfaces
private ConstantPool constantPool; // collection of constants
private Field[] fields; // class fields, i.e., its variables
private Method[] methods; // methods defined in the class
private Attribute[] attributes; // attributes defined in the class
private final boolean isZip; // Loaded from ZIP file
/**
* Parses class from the given stream.
*
* @param inputStream Input stream
* @param fileName File name
*/
public ClassParser(final InputStream inputStream, final String fileName) {
this.fileName = fileName;
this.fileOwned = false;
final String clazz = inputStream.getClass().getName(); // Not a very clean solution ...
this.isZip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");
if (inputStream instanceof DataInputStream) {
this.dataInputStream = (DataInputStream) inputStream;
} else {
this.dataInputStream = new DataInputStream(new BufferedInputStream(inputStream, BUFSIZE));
}
}
/**
* Parses class from given .class file.
*
* @param fileName file name
*/
public ClassParser(final String fileName) {
this.isZip = false;
this.fileName = fileName;
this.fileOwned = true;
}
/**
* Parses class from given .class file in a ZIP-archive
*
* @param zipFile ZIP file name
* @param fileName file name
*/
public ClassParser(final String zipFile, final String fileName) {
this.isZip = true;
this.fileOwned = true;
this.zipFile = zipFile;
this.fileName = fileName;
}
/**
* Parses the given Java class file and return an object that represents the contained data, i.e., constants, methods,
* fields and commands. A <em>ClassFormatException</em> is raised, if the file is not a valid .class file. (This does
* not include verification of the byte code as it is performed by the Java interpreter).
*
* @return Class object representing the parsed class file
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
public JavaClass parse() throws IOException, ClassFormatException {
ZipFile zip = null;
try {
if (fileOwned) {
if (isZip) {
zip = new ZipFile(zipFile);
final ZipEntry entry = zip.getEntry(fileName);
if (entry == null) {
throw new IOException("File " + fileName + " not found");
}
dataInputStream = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry), BUFSIZE));
} else {
dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(fileName), BUFSIZE));
}
}
/****************** Read headers ********************************/
// Check magic tag of class file
readID();
// Get compiler version
readVersion();
/****************** Read constant pool and related **************/
// Read constant pool entries
readConstantPool();
// Get class information
readClassInfo();
// Get interface information, i.e., implemented interfaces
readInterfaces();
/****************** Read class fields and methods ***************/
// Read class fields, i.e., the variables of the class
readFields();
// Read class methods, i.e., the functions in the class
readMethods();
// Read class attributes
readAttributes();
// Check for unknown variables
// Unknown[] u = Unknown.getUnknownAttributes();
// for (int i=0; i < u.length; i++)
// System.err.println("WARNING: " + u[i]);
// Everything should have been read now
// if (file.available() > 0) {
// int bytes = file.available();
// byte[] buf = new byte[bytes];
// file.read(buf);
// if (!(isZip && (buf.length == 1))) {
// System.err.println("WARNING: Trailing garbage at end of " + fileName);
// System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf));
// }
// }
} finally {
// Read everything of interest, so close the file
if (fileOwned) {
try {
if (dataInputStream != null) {
dataInputStream.close();
}
} catch (final IOException ignored) {
// ignore close exceptions
}
}
try {
if (zip != null) {
zip.close();
}
} catch (final IOException ignored) {
// ignore close exceptions
}
}
// Return the information we have gathered in a new object
return new JavaClass(classNameIndex, superclassNameIndex, fileName, major, minor, accessFlags, constantPool, interfaces, fields, methods, attributes,
isZip ? JavaClass.ZIP : JavaClass.FILE);
}
/**
* Reads information about the attributes of the class.
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readAttributes() throws IOException, ClassFormatException {
final int attributesCount = dataInputStream.readUnsignedShort();
attributes = new Attribute[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes[i] = Attribute.readAttribute(dataInputStream, constantPool);
}
}
/**
* Reads information about the class and its super class.
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readClassInfo() throws IOException, ClassFormatException {
accessFlags = dataInputStream.readUnsignedShort();
/*
* Interfaces are implicitly abstract, the flag should be set according to the JVM specification.
*/
if ((accessFlags & Const.ACC_INTERFACE) != 0) {
accessFlags |= Const.ACC_ABSTRACT;
}
if ((accessFlags & Const.ACC_ABSTRACT) != 0 && (accessFlags & Const.ACC_FINAL) != 0) {
throw new ClassFormatException("Class " + fileName + " can't be both final and abstract");
}
classNameIndex = dataInputStream.readUnsignedShort();
superclassNameIndex = dataInputStream.readUnsignedShort();
}
/**
* Reads constant pool entries.
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readConstantPool() throws IOException, ClassFormatException {
constantPool = new ConstantPool(dataInputStream);
}
/**
* Reads information about the fields of the class, i.e., its variables.
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readFields() throws IOException, ClassFormatException {
final int fieldsCount = dataInputStream.readUnsignedShort();
fields = new Field[fieldsCount];
for (int i = 0; i < fieldsCount; i++) {
fields[i] = new Field(dataInputStream, constantPool);
}
}
/******************** Private utility methods **********************/
/**
* Checks whether the header of the file is ok. Of course, this has to be the first action on successive file reads.
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readID() throws IOException, ClassFormatException {
if (dataInputStream.readInt() != Const.JVM_CLASSFILE_MAGIC) {
throw new ClassFormatException(fileName + " is not a Java .class file");
}
}
/**
* Reads information about the interfaces implemented by this class.
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readInterfaces() throws IOException, ClassFormatException {
final int interfacesCount = dataInputStream.readUnsignedShort();
interfaces = new int[interfacesCount];
for (int i = 0; i < interfacesCount; i++) {
interfaces[i] = dataInputStream.readUnsignedShort();
}
}
/**
* Reads information about the methods of the class.
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readMethods() throws IOException {
final int methodsCount = dataInputStream.readUnsignedShort();
methods = new Method[methodsCount];
for (int i = 0; i < methodsCount; i++) {
methods[i] = new Method(dataInputStream, constantPool);
}
}
/**
* Reads major and minor version of compiler which created the file.
*
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
private void readVersion() throws IOException, ClassFormatException {
minor = dataInputStream.readUnsignedShort();
major = dataInputStream.readUnsignedShort();
}
}

View file

@ -0,0 +1,380 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
import jdk.xml.internal.Utils;
/**
* This class represents a chunk of Java byte code contained in a method. It is instantiated by the
* <em>Attribute.readAttribute()</em> method. A <em>Code</em> attribute contains informations about operand stack, local
* variables, byte code and the exceptions handled within this method.
*
* This attribute has attributes itself, namely <em>LineNumberTable</em> which is used for debugging purposes and
* <em>LocalVariableTable</em> which contains information about the local variables.
*
* <pre>
* Code_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 max_stack;
* u2 max_locals;
* u4 code_length;
* u1 code[code_length];
* u2 exception_table_length;
* {
* u2 start_pc;
* u2 end_pc;
* u2 handler_pc;
* u2 catch_type;
* } exception_table[exception_table_length];
* u2 attributes_count;
* attribute_info attributes[attributes_count];
* }
* </pre>
* @see Attribute
* @see CodeException
* @see LineNumberTable
* @see LocalVariableTable
* @LastModified: Sept 2025
*/
public final class Code extends Attribute {
private int maxStack; // Maximum size of stack used by this method // TODO this could be made final (setter is not used)
private int maxLocals; // Number of local variables // TODO this could be made final (setter is not used)
private byte[] code; // Actual byte code
private CodeException[] exceptionTable; // Table of handled exceptions
private Attribute[] attributes; // or LocalVariable
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param code The source Code.
*/
public Code(final Code code) {
this(code.getNameIndex(), code.getLength(), code.getMaxStack(), code.getMaxLocals(), code.getCode(), code.getExceptionTable(), code.getAttributes(),
code.getConstantPool());
}
/**
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param file Input stream
* @param constantPool Array of constants
*/
Code(final int nameIndex, final int length, final DataInput file, final ConstantPool constantPool) throws IOException {
// Initialize with some default values which will be overwritten later
this(nameIndex, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null, (CodeException[]) null, (Attribute[]) null, constantPool);
final int codeLength = Args.requireU4(file.readInt(), 1, "Code length attribute");
code = new byte[codeLength]; // Read byte code
file.readFully(code);
/*
* Read exception table that contains all regions where an exception handler is active, i.e., a try { ... } catch ()
* block.
*/
final int exceptionTableLength = file.readUnsignedShort();
exceptionTable = new CodeException[exceptionTableLength];
for (int i = 0; i < exceptionTableLength; i++) {
exceptionTable[i] = new CodeException(file);
}
/*
* Read all attributes, currently 'LineNumberTable' and 'LocalVariableTable'
*/
final int attributesCount = file.readUnsignedShort();
attributes = new Attribute[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes[i] = readAttribute(file, constantPool);
}
/*
* Adjust length, because of setAttributes in this(), s.b. length is incorrect, because it didn't take the internal
* attributes into account yet! Very subtle bug, fixed in 3.1.1.
*/
super.setLength(length);
}
/**
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param maxStack Maximum size of stack
* @param maxLocals Number of local variables
* @param code Actual byte code
* @param exceptionTable of handled exceptions
* @param attributes Attributes of code: LineNumber or LocalVariable
* @param constantPool Array of constants
*/
public Code(final int nameIndex, final int length, final int maxStack, final int maxLocals, final byte[] code, final CodeException[] exceptionTable,
final Attribute[] attributes, final ConstantPool constantPool) {
super(Const.ATTR_CODE, nameIndex, length, constantPool);
this.maxStack = Args.requireU2(maxStack, "maxStack");
this.maxLocals = Args.requireU2(maxLocals, "maxLocals");
this.code = Utils.createEmptyArrayIfNull(code);
this.exceptionTable = Utils.createEmptyArrayIfNull(exceptionTable, CodeException[].class);
Args.requireU2(this.exceptionTable.length, "exceptionTable.length");
this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
super.setLength(calculateLength()); // Adjust length
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitCode(this);
}
/**
* @return the full size of this code attribute, minus its first 6 bytes, including the size of all its contained
* attributes
*/
private int calculateLength() {
int len = 0;
if (attributes != null) {
for (final Attribute attribute : attributes) {
len += attribute.getLength() + 6 /* attribute header size */;
}
}
return len + getInternalLength();
}
/**
* @return deep copy of this attribute
*
* @param constantPool the constant pool to duplicate
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final Code c = (Code) clone();
if (code != null) {
c.code = code.clone();
}
c.setConstantPool(constantPool);
c.exceptionTable = new CodeException[exceptionTable.length];
Arrays.setAll(c.exceptionTable, i -> exceptionTable[i].copy());
c.attributes = new Attribute[attributes.length];
Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
return c;
}
/**
* Dump code attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(maxStack);
file.writeShort(maxLocals);
file.writeInt(code.length);
file.write(code, 0, code.length);
file.writeShort(exceptionTable.length);
for (final CodeException exception : exceptionTable) {
exception.dump(file);
}
file.writeShort(attributes.length);
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
}
/**
* @return Collection of code attributes.
* @see Attribute
*/
public Attribute[] getAttributes() {
return attributes;
}
/**
* @return Actual byte code of the method.
*/
public byte[] getCode() {
return code;
}
/**
* @return Table of handled exceptions.
* @see CodeException
*/
public CodeException[] getExceptionTable() {
return exceptionTable;
}
/**
* @return the internal length of this code attribute (minus the first 6 bytes) and excluding all its attributes
*/
private int getInternalLength() {
return 2 /* maxStack */ + 2 /* maxLocals */ + 4 /* code length */
+ code.length /* byte-code */
+ 2 /* exception-table length */
+ 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */
+ 2 /* attributes count */;
}
/**
* @return LineNumberTable of Code, if it has one
*/
public LineNumberTable getLineNumberTable() {
for (final Attribute attribute : attributes) {
if (attribute instanceof LineNumberTable) {
return (LineNumberTable) attribute;
}
}
return null;
}
/**
* @return LocalVariableTable of Code, if it has one
*/
public LocalVariableTable getLocalVariableTable() {
for (final Attribute attribute : attributes) {
if (attribute instanceof LocalVariableTable) {
return (LocalVariableTable) attribute;
}
}
return null;
}
/**
* Gets the local variable type table attribute {@link LocalVariableTypeTable}.
* @return LocalVariableTypeTable of Code, if it has one, null otherwise.
* @since 6.10.0
*/
public LocalVariableTypeTable getLocalVariableTypeTable() {
for (final Attribute attribute : attributes) {
if (attribute instanceof LocalVariableTypeTable) {
return (LocalVariableTypeTable) attribute;
}
}
return null;
}
/**
* @return Number of local variables.
*/
public int getMaxLocals() {
return maxLocals;
}
/**
* @return Maximum size of stack used by this method.
*/
public int getMaxStack() {
return maxStack;
}
/**
* Finds the attribute of {@link StackMap} instance.
* @return StackMap of Code, if it has one, else null.
* @since 6.8.0
*/
public StackMap getStackMap() {
for (final Attribute attribute : attributes) {
if (attribute instanceof StackMap) {
return (StackMap) attribute;
}
}
return null;
}
/**
* @param attributes the attributes to set for this Code
*/
public void setAttributes(final Attribute[] attributes) {
this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
super.setLength(calculateLength()); // Adjust length
}
/**
* @param code byte code
*/
public void setCode(final byte[] code) {
this.code = Utils.createEmptyArrayIfNull(code);
super.setLength(calculateLength()); // Adjust length
}
/**
* @param exceptionTable exception table
*/
public void setExceptionTable(final CodeException[] exceptionTable) {
this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_ARRAY;
super.setLength(calculateLength()); // Adjust length
}
/**
* @param maxLocals maximum number of local variables
*/
public void setMaxLocals(final int maxLocals) {
this.maxLocals = maxLocals;
}
/**
* @param maxStack maximum stack size
*/
public void setMaxStack(final int maxStack) {
this.maxStack = maxStack;
}
/**
* @return String representation of code chunk.
*/
@Override
public String toString() {
return toString(true);
}
/**
* Converts this object to a String.
*
* @param verbose Provides verbose output when true.
* @return String representation of code chunk.
*/
public String toString(final boolean verbose) {
final StringBuilder buf = new StringBuilder(100); // CHECKSTYLE IGNORE MagicNumber
buf.append("Code(maxStack = ").append(maxStack).append(", maxLocals = ").append(maxLocals).append(", code_length = ").append(code.length).append(")\n")
.append(Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose));
if (exceptionTable.length > 0) {
buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n");
for (final CodeException exception : exceptionTable) {
buf.append(exception.toString(super.getConstantPool(), verbose)).append("\n");
}
}
if (attributes.length > 0) {
buf.append("\nAttribute(s) = ");
for (final Attribute attribute : attributes) {
buf.append("\n").append(attribute.getName()).append(":");
buf.append("\n").append(attribute);
}
}
return buf.toString();
}
}

View file

@ -0,0 +1,233 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents an entry in the exception table of the <em>Code</em> attribute and is used only there. It
* contains a range in which a particular exception handler is active.
*
* <pre>
* Code_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 max_stack;
* u2 max_locals;
* u4 code_length;
* u1 code[code_length];
* u2 exception_table_length;
* {
* u2 start_pc;
* u2 end_pc;
* u2 handler_pc;
* u2 catch_type;
* } exception_table[exception_table_length];
* u2 attributes_count;
* attribute_info attributes[attributes_count];
* }
* </pre>
*
* @see Code
* @LastModified: Sept 2025
*/
public final class CodeException implements Cloneable, Node {
/**
* Empty array.
*/
static final CodeException[] EMPTY_ARRAY = {};
/** Range in the code the exception handler. */
private int startPc;
/** Active. startPc is inclusive, endPc exclusive. */
private int endPc;
/**
* Starting address of exception handler, i.e., an offset from start of code.
*/
private int handlerPc;
/*
* If this is zero the handler catches any exception, otherwise it points to the exception class which is to be caught.
*/
private int catchType;
/**
* Constructs a new instance from another instance.
*
* @param c Source for copying.
*/
public CodeException(final CodeException c) {
this(c.getStartPC(), c.getEndPC(), c.getHandlerPC(), c.getCatchType());
}
/**
* Constructs a new instance from a DataInput.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
CodeException(final DataInput file) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* Constructs a new instance.
*
* @param startPc Range in the code the exception handler is active, startPc is inclusive while
* @param endPc is exclusive
* @param handlerPc Starting address of exception handler, i.e., an offset from start of code.
* @param catchType If zero the handler catches any exception, otherwise it points to the exception class which is to be
* caught.
*/
public CodeException(final int startPc, final int endPc, final int handlerPc, final int catchType) {
this.startPc = Args.requireU2(startPc, "startPc");
this.endPc = Args.requireU2(endPc, "endPc");
this.handlerPc = Args.requireU2(handlerPc, "handlerPc");
this.catchType = Args.requireU2(catchType, "catchType");
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitCodeException(this);
}
/**
* @return deep copy of this object
*/
public CodeException copy() {
try {
return (CodeException) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dumps code exception to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(startPc);
file.writeShort(endPc);
file.writeShort(handlerPc);
file.writeShort(catchType);
}
/**
* @return 0, if the handler catches any exception, otherwise it points to the exception class which is to be caught.
*/
public int getCatchType() {
return catchType;
}
/**
* @return Exclusive end index of the region where the handler is active.
*/
public int getEndPC() {
return endPc;
}
/**
* @return Starting address of exception handler, relative to the code.
*/
public int getHandlerPC() {
return handlerPc;
}
/**
* @return Inclusive start index of the region where the handler is active.
*/
public int getStartPC() {
return startPc;
}
/**
* @param catchType the type of exception that is caught
*/
public void setCatchType(final int catchType) {
this.catchType = catchType;
}
/**
* @param endPc end of handled block
*/
public void setEndPC(final int endPc) {
this.endPc = endPc;
}
/**
* @param handlerPc where the actual code is
*/
public void setHandlerPC(final int handlerPc) { // TODO unused
this.handlerPc = handlerPc;
}
/**
* @param startPc start of handled block
*/
public void setStartPC(final int startPc) { // TODO unused
this.startPc = startPc;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return "CodeException(startPc = " + startPc + ", endPc = " + endPc + ", handlerPc = " + handlerPc + ", catchType = " + catchType + ")";
}
public String toString(final ConstantPool cp) {
return toString(cp, true);
}
/**
* @param cp constant pool source.
* @param verbose Output more if true.
* @return String representation.
*/
public String toString(final ConstantPool cp, final boolean verbose) {
String str;
if (catchType == 0) {
str = "<Any exception>(0)";
} else {
str = Utility.compactClassName(cp.getConstantString(catchType, Const.CONSTANT_Class), false) + (verbose ? "(" + catchType + ")" : "");
}
return startPc + "\t" + endPc + "\t" + handlerPc + "\t" + str;
}
}

View file

@ -0,0 +1,204 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Objects;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.BCELComparator;
/**
* Abstract superclass for classes to represent the different constant types
* in the constant pool of a class file. The classes keep closely to
* the JVM specification.
*
* @LastModified: Sept 2025
*/
public abstract class Constant implements Cloneable, Node {
static final Constant[] EMPTY_ARRAY = {};
private static BCELComparator<Constant> bcelComparator = new BCELComparator<Constant>() {
@Override
public boolean equals(final Constant a, final Constant b) {
return a == b || a != null && b != null && Objects.equals(a.toString(), b.toString());
}
@Override
public int hashCode(final Constant o) {
return o != null ? Objects.hashCode(o.toString()) : 0;
}
};
/**
* @return Comparison strategy object.
*/
public static BCELComparator<Constant> getComparator() {
return bcelComparator;
}
/**
* Reads one constant from the given input, the type depends on a tag byte.
*
* @param dataInput Input stream
* @return Constant object
* @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
* @throws ClassFormatException if the next byte is not recognized
* @since 6.0 made public
*/
public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException {
final byte b = dataInput.readByte(); // Read tag byte
switch (b) {
case Const.CONSTANT_Class:
return new ConstantClass(dataInput);
case Const.CONSTANT_Fieldref:
return new ConstantFieldref(dataInput);
case Const.CONSTANT_Methodref:
return new ConstantMethodref(dataInput);
case Const.CONSTANT_InterfaceMethodref:
return new ConstantInterfaceMethodref(dataInput);
case Const.CONSTANT_String:
return new ConstantString(dataInput);
case Const.CONSTANT_Integer:
return new ConstantInteger(dataInput);
case Const.CONSTANT_Float:
return new ConstantFloat(dataInput);
case Const.CONSTANT_Long:
return new ConstantLong(dataInput);
case Const.CONSTANT_Double:
return new ConstantDouble(dataInput);
case Const.CONSTANT_NameAndType:
return new ConstantNameAndType(dataInput);
case Const.CONSTANT_Utf8:
return ConstantUtf8.getInstance(dataInput);
case Const.CONSTANT_MethodHandle:
return new ConstantMethodHandle(dataInput);
case Const.CONSTANT_MethodType:
return new ConstantMethodType(dataInput);
case Const.CONSTANT_Dynamic:
return new ConstantDynamic(dataInput);
case Const.CONSTANT_InvokeDynamic:
return new ConstantInvokeDynamic(dataInput);
case Const.CONSTANT_Module:
return new ConstantModule(dataInput);
case Const.CONSTANT_Package:
return new ConstantPackage(dataInput);
default:
throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
}
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator<Constant> comparator) {
bcelComparator = comparator;
}
/*
* In fact this tag is redundant since we can distinguish different 'Constant' objects by their type, i.e., via
* 'instanceof'. In some places we will use the tag for switch()es anyway.
*
* First, we want match the specification as closely as possible. Second we need the tag as an index to select the
* corresponding class name from the 'CONSTANT_NAMES' array.
*/
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected byte tag; // TODO should be private & final
Constant(final byte tag) {
this.tag = tag;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public abstract void accept(Visitor v);
@Override
public Object clone() {
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
}
}
/**
* @return deep copy of this constant
*/
public Constant copy() {
try {
return (Constant) super.clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
public abstract void dump(DataOutputStream file) throws IOException;
/**
* Returns value as defined by given BCELComparator strategy. By default two Constant objects are said to be equal when
* the result of toString() is equal.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(final Object obj) {
return obj instanceof Constant && bcelComparator.equals(this, (Constant) obj);
}
/**
* @return Tag of constant, i.e., its type. No setTag() method to avoid confusion.
*/
public final byte getTag() {
return tag;
}
/**
* Returns value as defined by given BCELComparator strategy. By default return the hash code of the result of
* toString().
*
* @see Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
/**
* @return String representation.
*/
@Override
public String toString() {
return Const.getConstantName(tag) + "[" + tag + "]";
}
}

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Abstract super class for Fieldref, Methodref, InterfaceMethodref and InvokeDynamic constants.
*
* @see ConstantFieldref
* @see ConstantMethodref
* @see ConstantInterfaceMethodref
* @see ConstantInvokeDynamic
* @LastModified: Sept 2025
*/
public abstract class ConstantCP extends Constant {
/**
* References to the constants containing the class and the field signature
*/
// Note that this field is used to store the
// bootstrap_method_attr_index of a ConstantInvokeDynamic.
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int class_index; // TODO make private (has getter & setter)
// This field has the same meaning for all subclasses.
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int name_and_type_index; // TODO make private (has getter & setter)
/**
* Initialize instance from file data.
*
* @param tag Constant type tag
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantCP(final byte tag, final DataInput file) throws IOException {
this(tag, file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* @param classIndex Reference to the class containing the field
* @param nameAndTypeIndex and the field signature
*/
protected ConstantCP(final byte tag, final int classIndex, final int nameAndTypeIndex) {
super(tag);
this.class_index = classIndex;
this.name_and_type_index = nameAndTypeIndex;
}
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantCP(final ConstantCP c) {
this(c.getTag(), c.getClassIndex(), c.getNameAndTypeIndex());
}
/**
* Dump constant field reference to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public final void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(class_index);
file.writeShort(name_and_type_index);
}
/**
* @return Class this field belongs to.
*/
public String getClass(final ConstantPool cp) {
return cp.constantToString(class_index, Const.CONSTANT_Class);
}
/**
* @return Reference (index) to class this constant refers to.
*/
public final int getClassIndex() {
return class_index;
}
/**
* @return Reference (index) to signature of the field.
*/
public final int getNameAndTypeIndex() {
return name_and_type_index;
}
/**
* @param classIndex points to Constant_class
*/
public final void setClassIndex(final int classIndex) {
this.class_index = classIndex;
}
/**
* @param nameAndTypeIndex points to Constant_NameAndType
*/
public final void setNameAndTypeIndex(final int nameAndTypeIndex) {
this.name_and_type_index = nameAndTypeIndex;
}
/**
* @return String representation.
*
* not final as ConstantInvokeDynamic needs to modify
*/
@Override
public String toString() {
return super.toString() + "(class_index = " + class_index + ", name_and_type_index = " + name_and_type_index + ")";
}
}

View file

@ -0,0 +1,125 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a (external) class.
*
* @see Constant
*/
public final class ConstantClass extends Constant implements ConstantObject {
private int nameIndex; // Identical to ConstantString except for the name
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantClass(final ConstantClass c) {
this(c.getNameIndex());
}
/**
* Constructs an instance from file data.
*
* @param dataInput Input stream
* @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
*/
ConstantClass(final DataInput dataInput) throws IOException {
this(dataInput.readUnsignedShort());
}
/**
* @param nameIndex Name index in constant pool. Should refer to a ConstantUtf8.
*/
public ConstantClass(final int nameIndex) {
super(Const.CONSTANT_Class);
this.nameIndex = nameIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantClass(this);
}
/**
* Dumps constant class to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs writing to the DataOutputStream.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(nameIndex);
}
/**
* @return dereferenced string
*/
public String getBytes(final ConstantPool cp) {
return (String) getConstantValue(cp);
}
/**
* @return String object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return cp.getConstantUtf8(nameIndex).getBytes();
}
/**
* @return Name index in constant pool of class name.
*/
public int getNameIndex() {
return nameIndex;
}
/**
* @param nameIndex the name index in the constant pool of this Constant Class
*/
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return super.toString() + "(nameIndex = " + nameIndex + ")";
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a Double object.
*
* @see Constant
* @LastModified: Sept 2025
*/
public final class ConstantDouble extends Constant implements ConstantObject {
private double bytes;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantDouble(final ConstantDouble c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantDouble(final DataInput file) throws IOException {
this(file.readDouble());
}
/**
* @param bytes Data
*/
public ConstantDouble(final double bytes) {
super(Const.CONSTANT_Double);
this.bytes = bytes;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantDouble(this);
}
/**
* Dump constant double to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeDouble(bytes);
}
/**
* @return data, i.e., 8 bytes.
*/
public double getBytes() {
return bytes;
}
/**
* @return Double object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return Double.valueOf(bytes);
}
/**
* @param bytes the raw bytes that represent the double value
*/
public void setBytes(final double bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return super.toString() + "(bytes = " + bytes + ")";
}
}

View file

@ -0,0 +1,91 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a dynamically computed
* constant.
*
* @see Constant
* @see <a href="https://bugs.openjdk.java.net/secure/attachment/74618/constant-dynamic.html"> Change request for JEP
* 309</a>
* @since 6.3
*/
public final class ConstantDynamic extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantDynamic(final ConstantDynamic c) {
this(c.getBootstrapMethodAttrIndex(), c.getNameAndTypeIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantDynamic(final DataInput file) throws IOException {
this(file.readShort(), file.readShort());
}
public ConstantDynamic(final int bootstrapMethodAttrIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_Dynamic, bootstrapMethodAttrIndex, nameAndTypeIndex);
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e.,
* the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantDynamic(this);
}
/**
* @return Reference (index) to bootstrap method this constant refers to.
*
* Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic.
* @since 6.0
*/
public int getBootstrapMethodAttrIndex() {
return super.getClassIndex(); // AKA bootstrap_method_attr_index
}
/**
* @return String representation
*/
@Override
public String toString() {
return super.toString().replace("class_index", "bootstrap_method_attr_index");
}
}

View file

@ -0,0 +1,71 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a constant pool reference to a field.
*/
public final class ConstantFieldref extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantFieldref(final ConstantFieldref c) {
super(Const.CONSTANT_Fieldref, c.getClassIndex(), c.getNameAndTypeIndex());
}
/**
* Initialize instance from input data.
*
* @param input input stream
* @throws IOException if an I/O error occurs.
*/
ConstantFieldref(final DataInput input) throws IOException {
super(Const.CONSTANT_Fieldref, input);
}
/**
* @param classIndex Reference to the class containing the Field
* @param nameAndTypeIndex and the Field signature
*/
public ConstantFieldref(final int classIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_Fieldref, classIndex, nameAndTypeIndex);
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of Fields, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantFieldref(this);
}
}

View file

@ -0,0 +1,119 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a float object.
*
* @see Constant
* @LastModified: Sept 2025
*/
public final class ConstantFloat extends Constant implements ConstantObject {
private float bytes;
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public ConstantFloat(final ConstantFloat c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantFloat(final DataInput file) throws IOException {
this(file.readFloat());
}
/**
* @param bytes Data
*/
public ConstantFloat(final float bytes) {
super(Const.CONSTANT_Float);
this.bytes = bytes;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantFloat(this);
}
/**
* Dump constant float to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeFloat(bytes);
}
/**
* @return data, i.e., 4 bytes.
*/
public float getBytes() {
return bytes;
}
/**
* @return Float object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return Float.valueOf(bytes);
}
/**
* @param bytes the raw bytes that represent this float
*/
public void setBytes(final float bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return super.toString() + "(bytes = " + bytes + ")";
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to an int object.
*
* @see Constant
* @LastModified: Sept 2025
*/
public final class ConstantInteger extends Constant implements ConstantObject {
private int bytes;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantInteger(final ConstantInteger c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantInteger(final DataInput file) throws IOException {
this(file.readInt());
}
/**
* @param bytes Data
*/
public ConstantInteger(final int bytes) {
super(Const.CONSTANT_Integer);
this.bytes = bytes;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantInteger(this);
}
/**
* Dump constant integer to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeInt(bytes);
}
/**
* @return data, i.e., 4 bytes.
*/
public int getBytes() {
return bytes;
}
/**
* @return Integer object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return Integer.valueOf(bytes);
}
/**
* @param bytes the raw bytes that represent this integer
*/
public void setBytes(final int bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return super.toString() + "(bytes = " + bytes + ")";
}
}

View file

@ -0,0 +1,71 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a constant pool reference to an interface method.
*/
public final class ConstantInterfaceMethodref extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantInterfaceMethodref(final ConstantInterfaceMethodref c) {
super(Const.CONSTANT_InterfaceMethodref, c.getClassIndex(), c.getNameAndTypeIndex());
}
/**
* Initialize instance from input data.
*
* @param input input stream
* @throws IOException if an I/O error occurs.
*/
ConstantInterfaceMethodref(final DataInput input) throws IOException {
super(Const.CONSTANT_InterfaceMethodref, input);
}
/**
* @param classIndex Reference to the class containing the method
* @param nameAndTypeIndex and the method signature
*/
public ConstantInterfaceMethodref(final int classIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_InterfaceMethodref, classIndex, nameAndTypeIndex);
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantInterfaceMethodref(this);
}
}

View file

@ -0,0 +1,90 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a invoke dynamic.
*
* @see Constant
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.10"> The
* CONSTANT_InvokeDynamic_info Structure in The Java Virtual Machine Specification</a>
* @since 6.0
*/
public final class ConstantInvokeDynamic extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantInvokeDynamic(final ConstantInvokeDynamic c) {
this(c.getBootstrapMethodAttrIndex(), c.getNameAndTypeIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantInvokeDynamic(final DataInput file) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort());
}
public ConstantInvokeDynamic(final int bootstrapMethodAttrIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_InvokeDynamic, bootstrapMethodAttrIndex, nameAndTypeIndex);
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e.,
* the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantInvokeDynamic(this);
}
/**
* @return Reference (index) to bootstrap method this constant refers to.
*
* Note that this method is a functional duplicate of getClassIndex for use by ConstantInvokeDynamic.
* @since 6.0
*/
public int getBootstrapMethodAttrIndex() {
return super.getClassIndex(); // AKA bootstrap_method_attr_index
}
/**
* @return String representation
*/
@Override
public String toString() {
return super.toString().replace("class_index", "bootstrap_method_attr_index");
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a long object.
*
* @see Constant
* @LastModified: Sept 2025
*/
public final class ConstantLong extends Constant implements ConstantObject {
private long bytes;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantLong(final ConstantLong c) {
this(c.getBytes());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantLong(final DataInput file) throws IOException {
this(file.readLong());
}
/**
* @param bytes Data
*/
public ConstantLong(final long bytes) {
super(Const.CONSTANT_Long);
this.bytes = bytes;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantLong(this);
}
/**
* Dump constant long to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeLong(bytes);
}
/**
* @return data, i.e., 8 bytes.
*/
public long getBytes() {
return bytes;
}
/**
* @return Long object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return Long.valueOf(bytes);
}
/**
* @param bytes the raw bytes that represent this long
*/
public void setBytes(final long bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return super.toString() + "(bytes = " + bytes + ")";
}
}

View file

@ -0,0 +1,113 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a method handle.
*
* @see Constant
* @since 6.0
*/
public final class ConstantMethodHandle extends Constant {
private int referenceKind;
private int referenceIndex;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantMethodHandle(final ConstantMethodHandle c) {
this(c.getReferenceKind(), c.getReferenceIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantMethodHandle(final DataInput file) throws IOException {
this(file.readUnsignedByte(), file.readUnsignedShort());
}
public ConstantMethodHandle(final int referenceKind, final int referenceIndex) {
super(Const.CONSTANT_MethodHandle);
this.referenceKind = referenceKind;
this.referenceIndex = referenceIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e.,
* the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantMethodHandle(this);
}
/**
* Dump method kind and index to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeByte(referenceKind);
file.writeShort(referenceIndex);
}
public int getReferenceIndex() {
return referenceIndex;
}
public int getReferenceKind() {
return referenceKind;
}
public void setReferenceIndex(final int referenceIndex) {
this.referenceIndex = referenceIndex;
}
public void setReferenceKind(final int referenceKind) {
this.referenceKind = referenceKind;
}
/**
* @return String representation
*/
@Override
public String toString() {
return super.toString() + "(referenceKind = " + referenceKind + ", referenceIndex = " + referenceIndex + ")";
}
}

View file

@ -0,0 +1,102 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a method type.
*
* @see Constant
* @since 6.0
*/
public final class ConstantMethodType extends Constant {
private int descriptorIndex;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantMethodType(final ConstantMethodType c) {
this(c.getDescriptorIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantMethodType(final DataInput file) throws IOException {
this(file.readUnsignedShort());
}
public ConstantMethodType(final int descriptorIndex) {
super(Const.CONSTANT_MethodType);
this.descriptorIndex = descriptorIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e.,
* the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantMethodType(this);
}
/**
* Dump name and signature index to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(descriptorIndex);
}
public int getDescriptorIndex() {
return descriptorIndex;
}
public void setDescriptorIndex(final int descriptorIndex) {
this.descriptorIndex = descriptorIndex;
}
/**
* @return String representation
*/
@Override
public String toString() {
return super.toString() + "(descriptorIndex = " + descriptorIndex + ")";
}
}

View file

@ -0,0 +1,71 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a constant pool reference to a method.
*/
public final class ConstantMethodref extends ConstantCP {
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantMethodref(final ConstantMethodref c) {
super(Const.CONSTANT_Methodref, c.getClassIndex(), c.getNameAndTypeIndex());
}
/**
* Initialize instance from input data.
*
* @param input input stream
* @throws IOException if an I/O error occurs.
*/
ConstantMethodref(final DataInput input) throws IOException {
super(Const.CONSTANT_Methodref, input);
}
/**
* @param classIndex Reference to the class containing the method
* @param nameAndTypeIndex and the method signature
*/
public ConstantMethodref(final int classIndex, final int nameAndTypeIndex) {
super(Const.CONSTANT_Methodref, classIndex, nameAndTypeIndex);
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantMethodref(this);
}
}

View file

@ -0,0 +1,130 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a module.
*
* <p>
* Note: Early access Java 9 support- currently subject to change
* </p>
*
* @see Constant
* @since 6.1
*/
public final class ConstantModule extends Constant implements ConstantObject {
private int nameIndex;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantModule(final ConstantModule c) {
this(c.getNameIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantModule(final DataInput file) throws IOException {
this(file.readUnsignedShort());
}
/**
* @param nameIndex Name index in constant pool. Should refer to a ConstantUtf8.
*/
public ConstantModule(final int nameIndex) {
super(Const.CONSTANT_Module);
this.nameIndex = nameIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e.,
* the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantModule(this);
}
/**
* Dump constant module to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(nameIndex);
}
/**
* @return dereferenced string
*/
public String getBytes(final ConstantPool cp) {
return (String) getConstantValue(cp);
}
/**
* @return String object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return cp.getConstantUtf8(nameIndex).getBytes();
}
/**
* @return Name index in constant pool of module name.
*/
public int getNameIndex() {
return nameIndex;
}
/**
* @param nameIndex the name index in the constant pool of this Constant Module
*/
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return super.toString() + "(nameIndex = " + nameIndex + ")";
}
}

View file

@ -0,0 +1,143 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to the name and signature of a
* field or method.
*
* @see Constant
*/
public final class ConstantNameAndType extends Constant {
private int nameIndex; // Name of field/method
private int signatureIndex; // and its signature.
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantNameAndType(final ConstantNameAndType c) {
this(c.getNameIndex(), c.getSignatureIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantNameAndType(final DataInput file) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* @param nameIndex Name of field/method
* @param signatureIndex and its signature
*/
public ConstantNameAndType(final int nameIndex, final int signatureIndex) {
super(Const.CONSTANT_NameAndType);
this.nameIndex = nameIndex;
this.signatureIndex = signatureIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantNameAndType(this);
}
/**
* Dump name and signature index to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(nameIndex);
file.writeShort(signatureIndex);
}
/**
* @return name
*/
public String getName(final ConstantPool cp) {
return cp.constantToString(getNameIndex(), Const.CONSTANT_Utf8);
}
/**
* @return Name index in constant pool of field/method name.
*/
public int getNameIndex() {
return nameIndex;
}
/**
* @return signature
*/
public String getSignature(final ConstantPool cp) {
return cp.constantToString(getSignatureIndex(), Const.CONSTANT_Utf8);
}
/**
* @return Index in constant pool of field/method signature.
*/
public int getSignatureIndex() {
return signatureIndex;
}
/**
* @param nameIndex the name index of this constant
*/
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/**
* @param signatureIndex the signature index in the constant pool of this type
*/
public void setSignatureIndex(final int signatureIndex) {
this.signatureIndex = signatureIndex;
}
/**
* @return String representation
*/
@Override
public String toString() {
return super.toString() + "(nameIndex = " + nameIndex + ", signatureIndex = " + signatureIndex + ")";
}
}

View file

@ -0,0 +1,38 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
/**
* This interface denotes those constants that have a "natural" value, such as ConstantLong, ConstantString, etc..
*
* @see Constant
*/
public interface ConstantObject {
/**
* Gets the object representing the constant, e.g., Long for ConstantLong.
*
* @param constantPool the constant.
* @return object representing the constant, e.g., Long for ConstantLong.
*/
Object getConstantValue(ConstantPool constantPool);
}

View file

@ -0,0 +1,130 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a package.
*
* <p>
* Note: Early access Java 9 support- currently subject to change
* </p>
*
* @see Constant
* @since 6.1
*/
public final class ConstantPackage extends Constant implements ConstantObject {
private int nameIndex;
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantPackage(final ConstantPackage c) {
this(c.getNameIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantPackage(final DataInput file) throws IOException {
this(file.readUnsignedShort());
}
/**
* @param nameIndex Name index in constant pool. Should refer to a ConstantUtf8.
*/
public ConstantPackage(final int nameIndex) {
super(Const.CONSTANT_Package);
this.nameIndex = nameIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e.,
* the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantPackage(this);
}
/**
* Dump constant package to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(nameIndex);
}
/**
* @return dereferenced string
*/
public String getBytes(final ConstantPool cp) {
return (String) getConstantValue(cp);
}
/**
* @return String object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return cp.getConstantUtf8(nameIndex).getBytes();
}
/**
* @return Name index in constant pool of package name.
*/
public int getNameIndex() {
return nameIndex;
}
/**
* @param nameIndex the name index in the constant pool of this Constant Package
*/
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return super.toString() + "(nameIndex = " + nameIndex + ")";
}
}

View file

@ -0,0 +1,441 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents the constant pool, i.e., a table of constants, of a parsed classfile. It may contain null references, due to the JVM specification that
* skips an entry after an 8-byte constant (double, long) entry. Those interested in generating constant pools programmatically should see
* <a href="../generic/ConstantPoolGen.html"> ConstantPoolGen</a>.
*
* @see Constant
* @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen
* @LastModified: Sept 2025
*/
public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
private static String escape(final String str) {
final int len = str.length();
final StringBuilder buf = new StringBuilder(len + 5);
final char[] ch = str.toCharArray();
for (int i = 0; i < len; i++) {
switch (ch[i]) {
case '\n':
buf.append("\\n");
break;
case '\r':
buf.append("\\r");
break;
case '\t':
buf.append("\\t");
break;
case '\b':
buf.append("\\b");
break;
case '"':
buf.append("\\\"");
break;
default:
buf.append(ch[i]);
}
}
return buf.toString();
}
private Constant[] constantPool;
/**
* @param constantPool Array of constants
*/
public ConstantPool(final Constant[] constantPool) {
setConstantPool(constantPool);
}
/**
* Reads constants from given input stream.
*
* @param input Input stream
* @throws IOException if problem in readUnsignedShort or readConstant
*/
public ConstantPool(final DataInput input) throws IOException {
byte tag;
final int constantPoolCount = input.readUnsignedShort();
constantPool = new Constant[constantPoolCount];
/*
* constantPool[0] is unused by the compiler and may be used freely by the implementation.
* constantPool[0] is currently unused by the implementation.
*/
for (int i = 1; i < constantPoolCount; i++) {
constantPool[i] = Constant.readConstant(input);
/*
* Quote from the JVM specification: "All eight byte constants take up two spots in the constant pool. If this is the n'th byte in the constant
* pool, then the next item will be numbered n+2"
*
* Thus we have to increment the index counter.
*/
tag = constantPool[i].getTag();
if (tag == Const.CONSTANT_Double || tag == Const.CONSTANT_Long) {
i++;
}
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e., the hierarchy of methods, fields,
* attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantPool(this);
}
/**
* Resolves constant to a string representation.
*
* @param c Constant to be printed
* @return String representation
* @throws IllegalArgumentException if c is unknown constant type
*/
public String constantToString(Constant c) throws IllegalArgumentException {
String str;
int i;
final byte tag = c.getTag();
switch (tag) {
case Const.CONSTANT_Class:
i = ((ConstantClass) c).getNameIndex();
c = getConstantUtf8(i);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break;
case Const.CONSTANT_String:
i = ((ConstantString) c).getStringIndex();
c = getConstantUtf8(i);
str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\"";
break;
case Const.CONSTANT_Utf8:
str = ((ConstantUtf8) c).getBytes();
break;
case Const.CONSTANT_Double:
str = String.valueOf(((ConstantDouble) c).getBytes());
break;
case Const.CONSTANT_Float:
str = String.valueOf(((ConstantFloat) c).getBytes());
break;
case Const.CONSTANT_Long:
str = String.valueOf(((ConstantLong) c).getBytes());
break;
case Const.CONSTANT_Integer:
str = String.valueOf(((ConstantInteger) c).getBytes());
break;
case Const.CONSTANT_NameAndType:
str = constantToString(((ConstantNameAndType) c).getNameIndex(), Const.CONSTANT_Utf8) + " "
+ constantToString(((ConstantNameAndType) c).getSignatureIndex(), Const.CONSTANT_Utf8);
break;
case Const.CONSTANT_InterfaceMethodref:
case Const.CONSTANT_Methodref:
case Const.CONSTANT_Fieldref:
str = constantToString(((ConstantCP) c).getClassIndex(), Const.CONSTANT_Class) + "."
+ constantToString(((ConstantCP) c).getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
break;
case Const.CONSTANT_MethodHandle:
// Note that the ReferenceIndex may point to a Fieldref, Methodref or
// InterfaceMethodref - so we need to peek ahead to get the actual type.
final ConstantMethodHandle cmh = (ConstantMethodHandle) c;
str = Const.getMethodHandleName(cmh.getReferenceKind()) + " "
+ constantToString(cmh.getReferenceIndex(), getConstant(cmh.getReferenceIndex()).getTag());
break;
case Const.CONSTANT_MethodType:
final ConstantMethodType cmt = (ConstantMethodType) c;
str = constantToString(cmt.getDescriptorIndex(), Const.CONSTANT_Utf8);
break;
case Const.CONSTANT_InvokeDynamic:
final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) c;
str = cid.getBootstrapMethodAttrIndex() + ":" + constantToString(cid.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
break;
case Const.CONSTANT_Dynamic:
final ConstantDynamic cd = (ConstantDynamic) c;
str = cd.getBootstrapMethodAttrIndex() + ":" + constantToString(cd.getNameAndTypeIndex(), Const.CONSTANT_NameAndType);
break;
case Const.CONSTANT_Module:
i = ((ConstantModule) c).getNameIndex();
c = getConstantUtf8(i);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break;
case Const.CONSTANT_Package:
i = ((ConstantPackage) c).getNameIndex();
c = getConstantUtf8(i);
str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false);
break;
default: // Never reached
throw new IllegalArgumentException("Unknown constant type " + tag);
}
return str;
}
/**
* Retrieves constant at 'index' from constant pool and resolve it to a string representation.
*
* @param index of constant in constant pool
* @param tag expected type
* @return String representation
*/
public String constantToString(final int index, final byte tag) {
return constantToString(getConstant(index, tag));
}
/**
* @return deep copy of this constant pool
*/
public ConstantPool copy() {
ConstantPool c = null;
try {
c = (ConstantPool) clone();
c.constantPool = new Constant[constantPool.length];
for (int i = 1; i < constantPool.length; i++) {
if (constantPool[i] != null) {
c.constantPool[i] = constantPool[i].copy();
}
}
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return c;
}
/**
* Dump constant pool to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if problem in writeShort or dump
*/
public void dump(final DataOutputStream file) throws IOException {
/*
* Constants over the size of the constant pool shall not be written out.
* This is a redundant measure as the ConstantPoolGen should have already
* reported an error back in the situation.
*/
final int size = Math.min(constantPool.length, Const.MAX_CP_ENTRIES);
file.writeShort(size);
for (int i = 1; i < size; i++) {
if (constantPool[i] != null) {
constantPool[i].dump(file);
}
}
}
/**
* Gets constant from constant pool.
*
* @param index Index in constant pool
* @return Constant value
* @see Constant
* @throws ClassFormatException if index is invalid
*/
@SuppressWarnings("unchecked")
public <T extends Constant> T getConstant(final int index) throws ClassFormatException {
return (T) getConstant(index, Constant.class);
}
/**
* Gets constant from constant pool and check whether it has the expected type.
*
* @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type
* @return Constant value
* @see Constant
* @throws ClassFormatException if constant type does not match tag
*/
@SuppressWarnings("unchecked")
public <T extends Constant> T getConstant(final int index, final byte tag) throws ClassFormatException {
return (T) getConstant(index, tag, Constant.class);
}
/**
* Gets constant from constant pool and check whether it has the expected type.
*
* @param index Index in constant pool
* @param tag Tag of expected constant, i.e., its type
* @return Constant value
* @see Constant
* @throws ClassFormatException if constant type does not match tag
* @since 6.6.0
*/
public <T extends Constant> T getConstant(final int index, final byte tag, final Class<T> castTo) throws ClassFormatException {
final T c = getConstant(index);
if (c == null || c.getTag() != tag) {
throw new ClassFormatException("Expected class '" + Const.getConstantName(tag) + "' at index " + index + " and got " + c);
}
return c;
}
/**
* Gets constant from constant pool.
*
* @param <T> A {@link Constant} subclass
* @param index Index in constant pool
* @param castTo The {@link Constant} subclass to cast to.
* @return Constant value
* @see Constant
* @throws ClassFormatException if index is invalid
* @since 6.6.0
*/
public <T extends Constant> T getConstant(final int index, final Class<T> castTo) throws ClassFormatException {
if (index >= constantPool.length || index < 0) {
throw new ClassFormatException("Invalid constant pool reference using index: " + index + ". Constant pool size is: " + constantPool.length);
}
if (constantPool[index] != null && !castTo.isAssignableFrom(constantPool[index].getClass())) {
throw new ClassFormatException("Invalid constant pool reference at index: " + index +
". Expected " + castTo + " but was " + constantPool[index].getClass());
}
if (index > 1) {
final Constant prev = constantPool[index - 1];
if (prev != null && (prev.getTag() == Const.CONSTANT_Double || prev.getTag() == Const.CONSTANT_Long)) {
throw new ClassFormatException("Constant pool at index " + index + " is invalid. The index is unused due to the preceeding "
+ Const.getConstantName(prev.getTag()) + ".");
}
}
// Previous check ensures this won't throw a ClassCastException
final T c = castTo.cast(constantPool[index]);
if (c == null) {
throw new ClassFormatException("Constant pool at index " + index + " is null.");
}
return c;
}
/**
* Gets constant from constant pool and check whether it has the expected type.
*
* @param index Index in constant pool
* @return ConstantInteger value
* @see ConstantInteger
* @throws ClassFormatException if constant type does not match tag
*/
public ConstantInteger getConstantInteger(final int index) {
return getConstant(index, Const.CONSTANT_Integer, ConstantInteger.class);
}
/**
* @return Array of constants.
* @see Constant
*/
public Constant[] getConstantPool() {
return constantPool;
}
/**
* Gets string from constant pool and bypass the indirection of 'ConstantClass' and 'ConstantString' objects. I.e. these classes have an index field that
* points to another entry of the constant pool of type 'ConstantUtf8' which contains the real data.
*
* @param index Index in constant pool
* @param tag Tag of expected constant, either ConstantClass or ConstantString
* @return Contents of string reference
* @see ConstantClass
* @see ConstantString
* @throws IllegalArgumentException if tag is invalid
*/
public String getConstantString(final int index, final byte tag) throws IllegalArgumentException {
int i;
/*
* This switch() is not that elegant, since the four classes have the same contents, they just differ in the name of the index field variable. But we
* want to stick to the JVM naming conventions closely though we could have solved these more elegantly by using the same variable name or by
* subclassing.
*/
switch (tag) {
case Const.CONSTANT_Class:
i = getConstant(index, ConstantClass.class).getNameIndex();
break;
case Const.CONSTANT_String:
i = getConstant(index, ConstantString.class).getStringIndex();
break;
case Const.CONSTANT_Module:
i = getConstant(index, ConstantModule.class).getNameIndex();
break;
case Const.CONSTANT_Package:
i = getConstant(index, ConstantPackage.class).getNameIndex();
break;
case Const.CONSTANT_Utf8:
return getConstantUtf8(index).getBytes();
default:
throw new IllegalArgumentException("getConstantString called with illegal tag " + tag);
}
// Finally get the string from the constant pool
return getConstantUtf8(i).getBytes();
}
/**
* Gets constant from constant pool and check whether it has the expected type.
*
* @param index Index in constant pool
* @return ConstantUtf8 value
* @see ConstantUtf8
* @throws ClassFormatException if constant type does not match tag
*/
public ConstantUtf8 getConstantUtf8(final int index) throws ClassFormatException {
return getConstant(index, Const.CONSTANT_Utf8, ConstantUtf8.class);
}
/**
* @return Length of constant pool.
*/
public int getLength() {
return constantPool.length;
}
@Override
public Iterator<Constant> iterator() {
return Arrays.stream(constantPool).iterator();
}
/**
* @param constant Constant to set
*/
public void setConstant(final int index, final Constant constant) {
constantPool[index] = constant;
}
/**
* @param constantPool
*/
public void setConstantPool(final Constant[] constantPool) {
this.constantPool = constantPool != null ? constantPool : Constant.EMPTY_ARRAY;
}
/**
* @return String representation.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
for (int i = 1; i < constantPool.length; i++) {
buf.append(i).append(")").append(constantPool[i]).append("\n");
}
return buf.toString();
}
}

View file

@ -0,0 +1,125 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from the abstract {@link Constant} and represents a reference to a String object.
*
* @see Constant
*/
public final class ConstantString extends Constant implements ConstantObject {
private int stringIndex; // Identical to ConstantClass except for this name
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public ConstantString(final ConstantString c) {
this(c.getStringIndex());
}
/**
* Initialize instance from file data.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantString(final DataInput file) throws IOException {
this(file.readUnsignedShort());
}
/**
* @param stringIndex Index of Constant_Utf8 in constant pool
*/
public ConstantString(final int stringIndex) {
super(Const.CONSTANT_String);
this.stringIndex = stringIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantString(this);
}
/**
* Dump constant field reference to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeShort(stringIndex);
}
/**
* @return dereferenced string
*/
public String getBytes(final ConstantPool cp) {
return (String) getConstantValue(cp);
}
/**
* @return String object
*/
@Override
public Object getConstantValue(final ConstantPool cp) {
return cp.getConstantUtf8(stringIndex).getBytes();
}
/**
* @return Index in constant pool of the string (ConstantUtf8).
*/
public int getStringIndex() {
return stringIndex;
}
/**
* @param stringIndex the index into the constant of the string value
*/
public void setStringIndex(final int stringIndex) {
this.stringIndex = stringIndex;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return super.toString() + "(stringIndex = " + stringIndex + ")";
}
}

View file

@ -0,0 +1,269 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import com.sun.org.apache.bcel.internal.Const;
/**
* Extends the abstract {@link Constant} to represent a reference to a UTF-8 encoded string.
* <p>
* The following system properties govern caching this class performs.
* </p>
* <ul>
* <li>{@link #SYS_PROP_CACHE_MAX_ENTRIES} (since 6.4): The size of the cache, by default 0, meaning caching is
* disabled.</li>
* <li>{@link #SYS_PROP_CACHE_MAX_ENTRY_SIZE} (since 6.0): The maximum size of the values to cache, by default 200, 0
* disables caching. Values larger than this are <em>not</em> cached.</li>
* <li>{@link #SYS_PROP_STATISTICS} (since 6.0): Prints statistics on the console when the JVM exits.</li>
* </ul>
* <p>
* Here is a sample Maven invocation with caching disabled:
* </p>
*
* <pre>
* mvn test -Dbcel.statistics=true -Dbcel.maxcached.size=0 -Dbcel.maxcached=0
* </pre>
* <p>
* Here is a sample Maven invocation with caching enabled:
* </p>
*
* <pre>
* mvn test -Dbcel.statistics=true -Dbcel.maxcached.size=100000 -Dbcel.maxcached=5000000
* </pre>
*
* @see Constant
* @LastModified: Sept 2025
*/
public final class ConstantUtf8 extends Constant {
private static final class Cache {
private static final boolean BCEL_STATISTICS = false;
private static final int MAX_ENTRIES = 20000;
private static final int INITIAL_CAPACITY = (int) (MAX_ENTRIES / 0.75);
private static final HashMap<String, ConstantUtf8> CACHE = new LinkedHashMap<String, ConstantUtf8>(INITIAL_CAPACITY, 0.75f, true) {
private static final long serialVersionUID = -8506975356158971766L;
@Override
protected boolean removeEldestEntry(final Map.Entry<String, ConstantUtf8> eldest) {
return size() > MAX_ENTRIES;
}
};
// Set the size to 0 or below to skip caching entirely
private static final int MAX_ENTRY_SIZE = 200;
static boolean isEnabled() {
return MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0;
}
}
// TODO these should perhaps be AtomicInt?
private static volatile int considered;
private static volatile int created;
private static volatile int hits;
private static volatile int skipped;
private static final String SYS_PROP_CACHE_MAX_ENTRIES = "bcel.maxcached";
private static final String SYS_PROP_CACHE_MAX_ENTRY_SIZE = "bcel.maxcached.size";
private static final String SYS_PROP_STATISTICS = "bcel.statistics";
static {
if (Cache.BCEL_STATISTICS) {
Runtime.getRuntime().addShutdownHook(new Thread(ConstantUtf8::printStats));
}
}
/**
* Clears the cache.
*
* @since 6.4.0
*/
public static synchronized void clearCache() {
Cache.CACHE.clear();
}
// for access by test code
static synchronized void clearStats() {
hits = considered = skipped = created = 0;
}
// Avoid Spotbugs complaint about Write to static field
private static void countCreated() {
created++;
}
/**
* Gets a new or cached instance of the given value.
* <p>
* See {@link ConstantUtf8} class Javadoc for details.
* </p>
*
* @param value the value.
* @return a new or cached instance of the given value.
* @since 6.0
*/
public static ConstantUtf8 getCachedInstance(final String value) {
if (value.length() > Cache.MAX_ENTRY_SIZE) {
skipped++;
return new ConstantUtf8(value);
}
considered++;
synchronized (ConstantUtf8.class) { // might be better with a specific lock object
ConstantUtf8 result = Cache.CACHE.get(value);
if (result != null) {
hits++;
return result;
}
result = new ConstantUtf8(value);
Cache.CACHE.put(value, result);
return result;
}
}
/**
* Gets a new or cached instance of the given value.
* <p>
* See {@link ConstantUtf8} class Javadoc for details.
* </p>
*
* @param dataInput the value.
* @return a new or cached instance of the given value.
* @throws IOException if an I/O error occurs.
* @since 6.0
*/
public static ConstantUtf8 getInstance(final DataInput dataInput) throws IOException {
return getInstance(dataInput.readUTF());
}
/**
* Gets a new or cached instance of the given value.
* <p>
* See {@link ConstantUtf8} class Javadoc for details.
* </p>
*
* @param value the value.
* @return a new or cached instance of the given value.
* @since 6.0
*/
public static ConstantUtf8 getInstance(final String value) {
return Cache.isEnabled() ? getCachedInstance(value) : new ConstantUtf8(value);
}
// for access by test code
static void printStats() {
final String prefix = "[Apache Commons BCEL]";
System.err.printf("%s Cache hit %,d/%,d, %d skipped.%n", prefix, hits, considered, skipped);
System.err.printf("%s Total of %,d ConstantUtf8 objects created.%n", prefix, created);
System.err.printf("%s Configuration: %s=%,d, %s=%,d.%n", prefix, SYS_PROP_CACHE_MAX_ENTRIES, Cache.MAX_ENTRIES, SYS_PROP_CACHE_MAX_ENTRY_SIZE,
Cache.MAX_ENTRY_SIZE);
}
private final String value;
/**
* Initializes from another object.
*
* @param constantUtf8 the value.
*/
public ConstantUtf8(final ConstantUtf8 constantUtf8) {
this(constantUtf8.getBytes());
}
/**
* Initializes instance from file data.
*
* @param dataInput Input stream
* @throws IOException if an I/O error occurs.
*/
ConstantUtf8(final DataInput dataInput) throws IOException {
super(Const.CONSTANT_Utf8);
value = dataInput.readUTF();
countCreated();
}
/**
* @param value Data
*/
public ConstantUtf8(final String value) {
super(Const.CONSTANT_Utf8);
this.value = Objects.requireNonNull(value, "value");
countCreated();
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantUtf8(this);
}
/**
* Dumps String in Utf8 format to file stream.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(super.getTag());
file.writeUTF(value);
}
/**
* @return Data converted to string.
*/
public String getBytes() {
return value;
}
/**
* @param bytes the raw bytes of this UTF-8
* @deprecated (since 6.0)
*/
@java.lang.Deprecated
public void setBytes(final String bytes) {
throw new UnsupportedOperationException();
}
/**
* @return String representation
*/
@Override
public String toString() {
return super.toString() + "(\"" + Utility.replace(value, "\n", "\\n") + "\")";
}
}

View file

@ -0,0 +1,161 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and represents a constant value, i.e., a default value for initializing
* a class field. This class is instantiated by the <em>Attribute.readAttribute()</em> method.
*
* <pre>
* ConstantValue_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 constantvalue_index;
* }
* </pre>
* @see Attribute
*/
public final class ConstantValue extends Attribute {
private int constantValueIndex;
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public ConstantValue(final ConstantValue c) {
this(c.getNameIndex(), c.getLength(), c.getConstantValueIndex(), c.getConstantPool());
}
/**
* Constructs object from input stream.
*
* @param nameIndex Name index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
ConstantValue(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, input.readUnsignedShort(), constantPool);
}
/**
* @param nameIndex Name index in constant pool
* @param length Content length in bytes
* @param constantValueIndex Index in constant pool
* @param constantPool Array of constants
*/
public ConstantValue(final int nameIndex, final int length, final int constantValueIndex, final ConstantPool constantPool) {
super(Const.ATTR_CONSTANT_VALUE, nameIndex, Args.require(length, 2, "ConstantValue attribute length"), constantPool);
this.constantValueIndex = constantValueIndex;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitConstantValue(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final ConstantValue c = (ConstantValue) clone();
c.setConstantPool(constantPool);
return c;
}
/**
* Dump constant value attribute to file stream on binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(constantValueIndex);
}
/**
* @return Index in constant pool of constant value.
*/
public int getConstantValueIndex() {
return constantValueIndex;
}
/**
* @param constantValueIndex the index info the constant pool of this constant value
*/
public void setConstantValueIndex(final int constantValueIndex) {
this.constantValueIndex = constantValueIndex;
}
/**
* @return String representation of constant value.
*/
@Override
public String toString() {
Constant c = super.getConstantPool().getConstant(constantValueIndex);
String buf;
int i;
// Print constant to string depending on its type
switch (c.getTag()) {
case Const.CONSTANT_Long:
buf = String.valueOf(((ConstantLong) c).getBytes());
break;
case Const.CONSTANT_Float:
buf = String.valueOf(((ConstantFloat) c).getBytes());
break;
case Const.CONSTANT_Double:
buf = String.valueOf(((ConstantDouble) c).getBytes());
break;
case Const.CONSTANT_Integer:
buf = String.valueOf(((ConstantInteger) c).getBytes());
break;
case Const.CONSTANT_String:
i = ((ConstantString) c).getStringIndex();
c = super.getConstantPool().getConstantUtf8(i);
buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\"";
break;
default:
throw new IllegalStateException("Type of ConstValue invalid: " + c);
}
return buf;
}
}

View file

@ -0,0 +1,138 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and denotes that this is a deprecated method. It is instantiated from
* the <em>Attribute.readAttribute()</em> method.
*
* @see Attribute
*/
public final class Deprecated extends Attribute {
private byte[] bytes;
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public Deprecated(final Deprecated c) {
this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
}
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param bytes Attribute contents
* @param constantPool Array of constants
*/
public Deprecated(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
super(Const.ATTR_DEPRECATED, nameIndex, Args.require0(length, "Deprecated attribute length"), constantPool);
this.bytes = bytes;
}
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Deprecated(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (byte[]) null, constantPool);
if (length > 0) {
bytes = new byte[length];
input.readFully(bytes);
println("Deprecated attribute with length > 0");
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitDeprecated(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final Deprecated c = (Deprecated) clone();
if (bytes != null) {
c.bytes = bytes.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
if (super.getLength() > 0) {
file.write(bytes, 0, super.getLength());
}
}
/**
* @return data bytes.
*/
public byte[] getBytes() {
return bytes;
}
/**
* @param bytes the raw bytes that represents this byte array
*/
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/**
* @return attribute name
*/
@Override
public String toString() {
return Const.getAttributeName(Const.ATTR_DEPRECATED) + ": true";
}
}

View file

@ -0,0 +1,583 @@
/*
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.util.Objects;
import java.util.Stack;
import java.util.stream.Stream;
import jdk.xml.internal.Utils;
/**
* Traverses a JavaClass with another Visitor object 'piggy-backed' that is applied to all components of a JavaClass
* object. I.e. this class supplies the traversal strategy, other classes can make use of it.
*
* @LastModified: Sept 2025
*/
public class DescendingVisitor implements Visitor {
private final JavaClass clazz;
private final Visitor visitor;
private final Stack<Object> stack = new Stack<>();
/**
* @param clazz Class to traverse
* @param visitor visitor object to apply to all components
*/
public DescendingVisitor(final JavaClass clazz, final Visitor visitor) {
this.clazz = clazz;
this.visitor = visitor;
}
private <E extends Node> void accept(final E[] node) {
Utils.streamOfIfNonNull(node).forEach(e -> e.accept(this));
}
/**
* @return current object
*/
public Object current() {
return stack.peek();
}
/**
* @return container of current entitity, i.e., predecessor during traversal
*/
public Object predecessor() {
return predecessor(0);
}
/**
* @param level nesting level, i.e., 0 returns the direct predecessor
* @return container of current entitity, i.e., predecessor during traversal
*/
public Object predecessor(final int level) {
final int size = stack.size();
if (size < 2 || level < 0) {
return null;
}
return stack.elementAt(size - (level + 2)); // size - 1 == current
}
/**
* Start traversal.
*/
public void visit() {
clazz.accept(this);
}
/**
* @since 6.0
*/
@Override
public void visitAnnotation(final Annotations annotation) {
stack.push(annotation);
annotation.accept(visitor);
accept(annotation.getAnnotationEntries());
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitAnnotationDefault(final AnnotationDefault obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitAnnotationEntry(final AnnotationEntry annotationEntry) {
stack.push(annotationEntry);
annotationEntry.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitBootstrapMethods(final BootstrapMethods bm) {
stack.push(bm);
bm.accept(visitor);
// BootstrapMethod[] bms = bm.getBootstrapMethods();
// for (int i = 0; i < bms.length; i++)
// {
// bms[i].accept(this);
// }
stack.pop();
}
@Override
public void visitCode(final Code code) {
stack.push(code);
code.accept(visitor);
accept(code.getExceptionTable());
accept(code.getAttributes());
stack.pop();
}
@Override
public void visitCodeException(final CodeException ce) {
stack.push(ce);
ce.accept(visitor);
stack.pop();
}
@Override
public void visitConstantClass(final ConstantClass constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantDouble(final ConstantDouble constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
/** @since 6.3 */
@Override
public void visitConstantDynamic(final ConstantDynamic obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitConstantFieldref(final ConstantFieldref constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantFloat(final ConstantFloat constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantInteger(final ConstantInteger constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantInterfaceMethodref(final ConstantInterfaceMethodref constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitConstantInvokeDynamic(final ConstantInvokeDynamic constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantLong(final ConstantLong constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
/** @since 6.0 */
@Override
public void visitConstantMethodHandle(final ConstantMethodHandle obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitConstantMethodref(final ConstantMethodref constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
/** @since 6.0 */
@Override
public void visitConstantMethodType(final ConstantMethodType obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.1 */
@Override
public void visitConstantModule(final ConstantModule obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitConstantNameAndType(final ConstantNameAndType constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
/** @since 6.1 */
@Override
public void visitConstantPackage(final ConstantPackage obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitConstantPool(final ConstantPool cp) {
stack.push(cp);
cp.accept(visitor);
Stream.of(cp.getConstantPool()).filter(Objects::nonNull).forEach(e -> e.accept(this));
stack.pop();
}
@Override
public void visitConstantString(final ConstantString constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantUtf8(final ConstantUtf8 constant) {
stack.push(constant);
constant.accept(visitor);
stack.pop();
}
@Override
public void visitConstantValue(final ConstantValue cv) {
stack.push(cv);
cv.accept(visitor);
stack.pop();
}
@Override
public void visitDeprecated(final Deprecated attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitEnclosingMethod(final EnclosingMethod obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitExceptionTable(final ExceptionTable table) {
stack.push(table);
table.accept(visitor);
stack.pop();
}
@Override
public void visitField(final Field field) {
stack.push(field);
field.accept(visitor);
accept(field.getAttributes());
stack.pop();
}
@Override
public void visitInnerClass(final InnerClass inner) {
stack.push(inner);
inner.accept(visitor);
stack.pop();
}
@Override
public void visitInnerClasses(final InnerClasses ic) {
stack.push(ic);
ic.accept(visitor);
accept(ic.getInnerClasses());
stack.pop();
}
@Override
public void visitJavaClass(final JavaClass clazz) {
stack.push(clazz);
clazz.accept(visitor);
accept(clazz.getFields());
accept(clazz.getMethods());
accept(clazz.getAttributes());
clazz.getConstantPool().accept(this);
stack.pop();
}
@Override
public void visitLineNumber(final LineNumber number) {
stack.push(number);
number.accept(visitor);
stack.pop();
}
@Override
public void visitLineNumberTable(final LineNumberTable table) {
stack.push(table);
table.accept(visitor);
accept(table.getLineNumberTable());
stack.pop();
}
@Override
public void visitLocalVariable(final LocalVariable var) {
stack.push(var);
var.accept(visitor);
stack.pop();
}
@Override
public void visitLocalVariableTable(final LocalVariableTable table) {
stack.push(table);
table.accept(visitor);
accept(table.getLocalVariableTable());
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitMethod(final Method method) {
stack.push(method);
method.accept(visitor);
accept(method.getAttributes());
stack.pop();
}
/**
* @since 6.4.0
*/
@Override
public void visitMethodParameter(final MethodParameter obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitMethodParameters(final MethodParameters obj) {
stack.push(obj);
obj.accept(visitor);
Stream.of(obj.getParameters()).forEach(e -> e.accept(this));
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModule(final Module obj) {
stack.push(obj);
obj.accept(visitor);
accept(obj.getRequiresTable());
accept(obj.getExportsTable());
accept(obj.getOpensTable());
accept(obj.getProvidesTable());
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModuleExports(final ModuleExports obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModuleMainClass(final ModuleMainClass obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModuleOpens(final ModuleOpens obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModulePackages(final ModulePackages obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModuleProvides(final ModuleProvides obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitModuleRequires(final ModuleRequires obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitNestHost(final NestHost obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.4.0 */
@Override
public void visitNestMembers(final NestMembers obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/**
* @since 6.0
*/
@Override
public void visitParameterAnnotation(final ParameterAnnotations obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
/** @since 6.0 */
@Override
public void visitParameterAnnotationEntry(final ParameterAnnotationEntry obj) {
stack.push(obj);
obj.accept(visitor);
stack.pop();
}
@Override
public void visitRecord(final Record record) {
stack.push(record);
record.accept(visitor);
accept(record.getComponents());
stack.pop();
}
@Override
public void visitRecordComponent(final RecordComponentInfo recordComponentInfo) {
stack.push(recordComponentInfo);
recordComponentInfo.accept(visitor);
stack.pop();
}
@Override
public void visitSignature(final Signature attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitSourceFile(final SourceFile attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitStackMap(final StackMap table) {
stack.push(table);
table.accept(visitor);
accept(table.getStackMap());
stack.pop();
}
@Override
public void visitStackMapEntry(final StackMapEntry var) {
stack.push(var);
var.accept(visitor);
accept(var.getTypesOfLocals());
accept(var.getTypesOfStackItems());
stack.pop();
}
/**
* Visits a {@link StackMapType} object.
* @param var object to visit
* @since 6.8.0
*/
@Override
public void visitStackMapType(final StackMapType var) {
stack.push(var);
var.accept(visitor);
stack.pop();
}
@Override
public void visitSynthetic(final Synthetic attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
@Override
public void visitUnknown(final Unknown attribute) {
stack.push(attribute);
attribute.accept(visitor);
stack.pop();
}
}

View file

@ -0,0 +1,179 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* The element_value structure is documented at https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.16.1
*
* <pre>
* element_value {
* u1 tag;
* union {
* u2 const_value_index;
*
* { u2 type_name_index;
* u2 const_name_index;
* } enum_const_value;
*
* u2 class_info_index;
*
* annotation annotation_value;
*
* { u2 num_values;
* element_value values[num_values];
* } array_value;
* } value;
*}
*</pre>
* @since 6.0
* @LastModified: Sept 2025
*/
public abstract class ElementValue {
public static final byte STRING = 's';
public static final byte ENUM_CONSTANT = 'e';
public static final byte CLASS = 'c';
public static final byte ANNOTATION = '@';
public static final byte ARRAY = '[';
public static final byte PRIMITIVE_INT = 'I';
public static final byte PRIMITIVE_BYTE = 'B';
public static final byte PRIMITIVE_CHAR = 'C';
public static final byte PRIMITIVE_DOUBLE = 'D';
public static final byte PRIMITIVE_FLOAT = 'F';
public static final byte PRIMITIVE_LONG = 'J';
public static final byte PRIMITIVE_SHORT = 'S';
public static final byte PRIMITIVE_BOOLEAN = 'Z';
static final ElementValue[] EMPTY_ARRAY = {};
/**
* Reads an {@code element_value} as an {@code ElementValue}.
*
* @param input Raw data input.
* @param cpool Constant pool.
* @return a new ElementValue.
* @throws IOException if an I/O error occurs.
*/
public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
return readElementValue(input, cpool, 0);
}
/**
* Reads an {@code element_value} as an {@code ElementValue}.
*
* @param input Raw data input.
* @param cpool Constant pool.
* @param arrayNesting level of current array nesting.
* @return a new ElementValue.
* @throws IOException if an I/O error occurs.
* @since 6.7.0
*/
public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
throws IOException {
final byte tag = input.readByte();
switch (tag) {
case PRIMITIVE_BYTE:
case PRIMITIVE_CHAR:
case PRIMITIVE_DOUBLE:
case PRIMITIVE_FLOAT:
case PRIMITIVE_INT:
case PRIMITIVE_LONG:
case PRIMITIVE_SHORT:
case PRIMITIVE_BOOLEAN:
case STRING:
return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
case ENUM_CONSTANT:
return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
case CLASS:
return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
case ANNOTATION:
// TODO isRuntimeVisible
return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
case ARRAY:
arrayNesting++;
if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
// JVM spec 4.4.1
throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
}
final int numArrayVals = input.readUnsignedShort();
final ElementValue[] evalues = new ElementValue[numArrayVals];
for (int j = 0; j < numArrayVals; j++) {
evalues[j] = readElementValue(input, cpool, arrayNesting);
}
return new ArrayElementValue(ARRAY, evalues, cpool);
default:
throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
}
}
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@java.lang.Deprecated
protected int type; // TODO should be final
/**
* @deprecated (since 6.0) will be made private and final; do not access directly, use getter
*/
@java.lang.Deprecated
protected ConstantPool cpool; // TODO should be final
protected ElementValue(final int type, final ConstantPool cpool) {
this.type = type;
this.cpool = cpool;
}
public abstract void dump(DataOutputStream dos) throws IOException;
/** @since 6.0 */
final ConstantPool getConstantPool() {
return cpool;
}
public int getElementValueType() {
return type;
}
/** @since 6.0 */
final int getType() {
return type;
}
public abstract String stringifyValue();
public String toShortString() {
return stringifyValue();
}
@Override
public String toString() {
return stringifyValue();
}
}

View file

@ -0,0 +1,70 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* An annotation's element value pair.
*
* @since 6.0
*/
public class ElementValuePair {
static final ElementValuePair[] EMPTY_ARRAY = {};
private final ElementValue elementValue;
private final ConstantPool constantPool;
private final int elementNameIndex;
public ElementValuePair(final int elementNameIndex, final ElementValue elementValue, final ConstantPool constantPool) {
this.elementValue = elementValue;
this.elementNameIndex = elementNameIndex;
this.constantPool = constantPool;
}
protected void dump(final DataOutputStream dos) throws IOException {
dos.writeShort(elementNameIndex); // u2 name of the element
elementValue.dump(dos);
}
public int getNameIndex() {
return elementNameIndex;
}
public String getNameString() {
return constantPool.getConstantUtf8(elementNameIndex).getBytes();
}
public final ElementValue getValue() {
return elementValue;
}
public String toShortString() {
final StringBuilder result = new StringBuilder();
result.append(getNameString()).append("=").append(getValue().toShortString());
return result.toString();
}
}

View file

@ -0,0 +1,334 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
/**
* Visitor with empty method bodies, can be extended and used in conjunction with the DescendingVisitor class, e.g. By
* courtesy of David Spencer.
*
* @see DescendingVisitor
*/
public class EmptyVisitor implements Visitor {
protected EmptyVisitor() {
}
/**
* @since 6.0
*/
@Override
public void visitAnnotation(final Annotations obj) {
}
/**
* @since 6.0
*/
@Override
public void visitAnnotationDefault(final AnnotationDefault obj) {
}
/**
* @since 6.0
*/
@Override
public void visitAnnotationEntry(final AnnotationEntry obj) {
}
/**
* @since 6.0
*/
@Override
public void visitBootstrapMethods(final BootstrapMethods obj) {
}
@Override
public void visitCode(final Code obj) {
}
@Override
public void visitCodeException(final CodeException obj) {
}
@Override
public void visitConstantClass(final ConstantClass obj) {
}
@Override
public void visitConstantDouble(final ConstantDouble obj) {
}
/**
* @since 6.3
*/
@Override
public void visitConstantDynamic(final ConstantDynamic obj) {
}
@Override
public void visitConstantFieldref(final ConstantFieldref obj) {
}
@Override
public void visitConstantFloat(final ConstantFloat obj) {
}
@Override
public void visitConstantInteger(final ConstantInteger obj) {
}
@Override
public void visitConstantInterfaceMethodref(final ConstantInterfaceMethodref obj) {
}
@Override
public void visitConstantInvokeDynamic(final ConstantInvokeDynamic obj) {
}
@Override
public void visitConstantLong(final ConstantLong obj) {
}
/**
* @since 6.0
*/
@Override
public void visitConstantMethodHandle(final ConstantMethodHandle constantMethodHandle) {
}
@Override
public void visitConstantMethodref(final ConstantMethodref obj) {
}
/**
* @since 6.0
*/
@Override
public void visitConstantMethodType(final ConstantMethodType obj) {
}
/**
* @since 6.1
*/
@Override
public void visitConstantModule(final ConstantModule constantModule) {
}
@Override
public void visitConstantNameAndType(final ConstantNameAndType obj) {
}
/**
* @since 6.1
*/
@Override
public void visitConstantPackage(final ConstantPackage constantPackage) {
}
@Override
public void visitConstantPool(final ConstantPool obj) {
}
@Override
public void visitConstantString(final ConstantString obj) {
}
@Override
public void visitConstantUtf8(final ConstantUtf8 obj) {
}
@Override
public void visitConstantValue(final ConstantValue obj) {
}
@Override
public void visitDeprecated(final Deprecated obj) {
}
/**
* @since 6.0
*/
@Override
public void visitEnclosingMethod(final EnclosingMethod obj) {
}
@Override
public void visitExceptionTable(final ExceptionTable obj) {
}
@Override
public void visitField(final Field obj) {
}
@Override
public void visitInnerClass(final InnerClass obj) {
}
@Override
public void visitInnerClasses(final InnerClasses obj) {
}
@Override
public void visitJavaClass(final JavaClass obj) {
}
@Override
public void visitLineNumber(final LineNumber obj) {
}
@Override
public void visitLineNumberTable(final LineNumberTable obj) {
}
@Override
public void visitLocalVariable(final LocalVariable obj) {
}
@Override
public void visitLocalVariableTable(final LocalVariableTable obj) {
}
/**
* @since 6.0
*/
@Override
public void visitLocalVariableTypeTable(final LocalVariableTypeTable obj) {
}
@Override
public void visitMethod(final Method obj) {
}
/**
* @since 6.0
* @Override public void visitStackMapTable(StackMapTable obj) { }
*/
/**
* @since 6.0
* @Override public void visitStackMapTableEntry(StackMapTableEntry obj) { }
*/
/**
* @since 6.4.0
*/
@Override
public void visitMethodParameter(final MethodParameter obj) {
}
/**
* @since 6.0
*/
@Override
public void visitMethodParameters(final MethodParameters obj) {
}
/** @since 6.4.0 */
@Override
public void visitModule(final Module obj) {
}
/** @since 6.4.0 */
@Override
public void visitModuleExports(final ModuleExports obj) {
}
/** @since 6.4.0 */
@Override
public void visitModuleMainClass(final ModuleMainClass obj) {
}
/** @since 6.4.0 */
@Override
public void visitModuleOpens(final ModuleOpens obj) {
}
/** @since 6.4.0 */
@Override
public void visitModulePackages(final ModulePackages obj) {
}
/** @since 6.4.0 */
@Override
public void visitModuleProvides(final ModuleProvides obj) {
}
/** @since 6.4.0 */
@Override
public void visitModuleRequires(final ModuleRequires obj) {
}
/** @since 6.4.0 */
@Override
public void visitNestHost(final NestHost obj) {
}
/** @since 6.4.0 */
@Override
public void visitNestMembers(final NestMembers obj) {
}
/**
* @since 6.0
*/
@Override
public void visitParameterAnnotation(final ParameterAnnotations obj) {
}
/**
* @since 6.0
*/
@Override
public void visitParameterAnnotationEntry(final ParameterAnnotationEntry parameterAnnotationEntry) {
}
@Override
public void visitSignature(final Signature obj) {
}
@Override
public void visitSourceFile(final SourceFile obj) {
}
@Override
public void visitStackMap(final StackMap obj) {
}
@Override
public void visitStackMapEntry(final StackMapEntry obj) {
}
/**
* Visits a {@link StackMapType} object.
* @param obj object to visit
* @since 6.8.0
*/
@Override
public void visitStackMapType(final StackMapType obj) {
}
@Override
public void visitSynthetic(final Synthetic obj) {
}
@Override
public void visitUnknown(final Unknown obj) {
}
}

View file

@ -0,0 +1,107 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This attribute exists for local or anonymous classes and ... there can be only one.
*
* @since 6.0
*/
public class EnclosingMethod extends Attribute {
// Pointer to the CONSTANT_Class_info structure representing the
// innermost class that encloses the declaration of the current class.
private int classIndex;
// If the current class is not immediately enclosed by a method or
// constructor, then the value of the method_index item must be zero.
// Otherwise, the value of the method_index item must point to a
// CONSTANT_NameAndType_info structure representing the name and the
// type of a method in the class referenced by the class we point
// to in the class_index. *It is the compiler responsibility* to
// ensure that the method identified by this index is the closest
// lexically enclosing method that includes the local/anonymous class.
private int methodIndex;
// Ctors - and code to read an attribute in.
EnclosingMethod(final int nameIndex, final int len, final DataInput input, final ConstantPool cpool) throws IOException {
this(nameIndex, len, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
}
private EnclosingMethod(final int nameIndex, final int len, final int classIndex, final int methodIndex, final ConstantPool cpool) {
super(Const.ATTR_ENCLOSING_METHOD, nameIndex, Args.require(len, 4, "EnclosingMethod attribute length"), cpool);
this.classIndex = Args.requireU2(classIndex, 0, cpool.getLength(), "EnclosingMethod class index");
this.methodIndex = Args.requireU2(methodIndex, "EnclosingMethod method index");
}
@Override
public void accept(final Visitor v) {
v.visitEnclosingMethod(this);
}
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(classIndex);
file.writeShort(methodIndex);
}
public final ConstantClass getEnclosingClass() {
return super.getConstantPool().getConstant(classIndex, Const.CONSTANT_Class, ConstantClass.class);
}
// Accessors
public final int getEnclosingClassIndex() {
return classIndex;
}
public final ConstantNameAndType getEnclosingMethod() {
if (methodIndex == 0) {
return null;
}
return super.getConstantPool().getConstant(methodIndex, Const.CONSTANT_NameAndType, ConstantNameAndType.class);
}
public final int getEnclosingMethodIndex() {
return methodIndex;
}
public final void setEnclosingClassIndex(final int idx) {
classIndex = idx;
}
public final void setEnclosingMethodIndex(final int idx) {
methodIndex = idx;
}
}

View file

@ -0,0 +1,72 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* @since 6.0
*/
public class EnumElementValue extends ElementValue {
// For enum types, these two indices point to the type and value
private final int typeIdx;
private final int valueIdx;
public EnumElementValue(final int type, final int typeIdx, final int valueIdx, final ConstantPool cpool) {
super(type, cpool);
if (type != ENUM_CONSTANT) {
throw new ClassFormatException("Only element values of type enum can be built with this ctor - type specified: " + type);
}
this.typeIdx = typeIdx;
this.valueIdx = valueIdx;
}
@Override
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getType()); // u1 type of value (ENUM_CONSTANT == 'e')
dos.writeShort(typeIdx); // u2
dos.writeShort(valueIdx); // u2
}
public String getEnumTypeString() {
return super.getConstantPool().getConstantUtf8(typeIdx).getBytes();
}
public String getEnumValueString() {
return super.getConstantPool().getConstantUtf8(valueIdx).getBytes();
}
public int getTypeIndex() {
return typeIdx;
}
public int getValueIndex() {
return valueIdx;
}
@Override
public String stringifyValue() {
return super.getConstantPool().getConstantUtf8(valueIdx).getBytes();
}
}

View file

@ -0,0 +1,180 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
import jdk.xml.internal.Utils;
/**
* This class represents the table of exceptions that are thrown by a method. This attribute may be used once per
* method. The name of this class is <em>ExceptionTable</em> for historical reasons; The Java Virtual Machine
* Specification, Second Edition defines this attribute using the name <em>Exceptions</em> (which is inconsistent with
* the other classes).
*
* <pre>
* Exceptions_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 number_of_exceptions;
* u2 exception_index_table[number_of_exceptions];
* }
* </pre>
* @see Code
* @LastModified: Sept 2025
*/
public final class ExceptionTable extends Attribute {
private int[] exceptionIndexTable; // constant pool
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public ExceptionTable(final ExceptionTable c) {
this(c.getNameIndex(), c.getLength(), c.getExceptionIndexTable(), c.getConstantPool());
}
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
ExceptionTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (int[]) null, constantPool);
final int exceptionCount = input.readUnsignedShort();
exceptionIndexTable = new int[exceptionCount];
for (int i = 0; i < exceptionCount; i++) {
exceptionIndexTable[i] = input.readUnsignedShort();
}
}
/**
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param exceptionIndexTable Table of indices in constant pool
* @param constantPool Array of constants
*/
public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) {
super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool);
this.exceptionIndexTable = Utils.createEmptyArrayIfNull(exceptionIndexTable);
Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length");
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitExceptionTable(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final ExceptionTable c = (ExceptionTable) clone();
if (exceptionIndexTable != null) {
c.exceptionIndexTable = exceptionIndexTable.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump exceptions attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(exceptionIndexTable.length);
for (final int index : exceptionIndexTable) {
file.writeShort(index);
}
}
/**
* @return Array of indices into constant pool of thrown exceptions.
*/
public int[] getExceptionIndexTable() {
return exceptionIndexTable;
}
/**
* @return class names of thrown exceptions
*/
public String[] getExceptionNames() {
final String[] names = new String[exceptionIndexTable.length];
Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class)));
return names;
}
/**
* @return Length of exception table.
*/
public int getNumberOfExceptions() {
return exceptionIndexTable == null ? 0 : exceptionIndexTable.length;
}
/**
* @param exceptionIndexTable the list of exception indexes Also redefines number_of_exceptions according to table
* length.
*/
public void setExceptionIndexTable(final int[] exceptionIndexTable) {
this.exceptionIndexTable = Utils.createEmptyArrayIfNull(exceptionIndexTable);
}
/**
* @return String representation, i.e., a list of thrown exceptions.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
String str;
buf.append("Exceptions: ");
for (int i = 0; i < exceptionIndexTable.length; i++) {
str = super.getConstantPool().getConstantString(exceptionIndexTable[i], Const.CONSTANT_Class);
buf.append(Utility.compactClassName(str, false));
if (i < exceptionIndexTable.length - 1) {
buf.append(", ");
}
}
return buf.toString();
}
}

View file

@ -0,0 +1,192 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.IOException;
import java.util.Objects;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.generic.Type;
import com.sun.org.apache.bcel.internal.util.BCELComparator;
/**
* This class represents the field info structure, i.e., the representation for a variable in the class. See JVM
* specification for details.
*/
public final class Field extends FieldOrMethod {
/**
* Empty array constant.
*
* @since 6.6.0
*/
public static final Field[] EMPTY_ARRAY = {};
private static BCELComparator<Field> bcelComparator = new BCELComparator<Field>() {
@Override
public boolean equals(final Field a, final Field b) {
return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature());
}
@Override
public int hashCode(final Field o) {
return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
}
};
/**
* @return Comparison strategy object.
*/
public static BCELComparator<Field> getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object.
*/
public static void setComparator(final BCELComparator<Field> comparator) {
bcelComparator = comparator;
}
/**
* Constructs object from file stream.
*
* @param file Input stream.
*/
Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
super(file, constantPool);
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public Field(final Field c) {
super(c);
}
/**
* @param accessFlags Access rights of field
* @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes
* @param constantPool Array of constants
*/
public Field(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitField(this);
}
/**
* @return deep copy of this field
*/
public Field copy(final ConstantPool constantPool) {
return (Field) copy_(constantPool);
}
/**
* Return value as defined by given BCELComparator strategy. By default two Field objects are said to be equal when
* their names and signatures are equal.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(final Object obj) {
return obj instanceof Field && bcelComparator.equals(this, (Field) obj);
}
/**
* @return constant value associated with this field (may be null)
*/
public ConstantValue getConstantValue() {
for (final Attribute attribute : super.getAttributes()) {
if (attribute.getTag() == Const.ATTR_CONSTANT_VALUE) {
return (ConstantValue) attribute;
}
}
return null;
}
/**
* See https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2.2
*
* @return type of field
*/
public Type getType() {
return Type.getType(getSignature());
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR
* signature.
*
* @see Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
/**
* Return string representation close to declaration format, 'public static final short MAX = 100', e.g..
*
* @return String representation of field, including the signature.
*/
@Override
public String toString() {
String name;
String signature;
String access; // Short cuts to constant pool
// Get names from constant pool
access = Utility.accessToString(super.getAccessFlags());
access = access.isEmpty() ? "" : access + " ";
signature = Utility.signatureToString(getSignature());
name = getName();
final StringBuilder buf = new StringBuilder(64); // CHECKSTYLE IGNORE MagicNumber
buf.append(access).append(signature).append(" ").append(name);
final ConstantValue cv = getConstantValue();
if (cv != null) {
buf.append(" = ").append(cv);
}
for (final Attribute attribute : super.getAttributes()) {
if (!(attribute instanceof ConstantValue)) {
buf.append(" [").append(attribute).append("]");
}
}
return buf.toString();
}
}

View file

@ -0,0 +1,279 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
/**
* Abstract super class for fields and methods.
*
* @LastModified: Sept 2025
*/
public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node {
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int name_index; // Points to field name in constant pool
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected int signature_index; // Points to encoded signature
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected Attribute[] attributes; // Collection of attributes
/**
* @deprecated (since 6.0) will be removed (not needed)
*/
@java.lang.Deprecated
protected int attributes_count; // No. of attributes
// @since 6.0
private AnnotationEntry[] annotationEntries; // annotations defined on the field or method
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
*/
@java.lang.Deprecated
protected ConstantPool constant_pool;
private String signatureAttributeString;
private boolean searchedForSignatureAttribute;
FieldOrMethod() {
}
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constantPool);
final int attributesCount = file.readUnsignedShort();
attributes = new Attribute[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes[i] = Attribute.readAttribute(file, constantPool);
}
this.attributes_count = attributesCount; // init deprecated field
}
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
* @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead.
*/
@java.lang.Deprecated
protected FieldOrMethod(final DataInputStream file, final ConstantPool constantPool) throws IOException {
this((DataInput) file, constantPool);
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
protected FieldOrMethod(final FieldOrMethod c) {
this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool());
}
/**
* @param accessFlags Access rights of method
* @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes
* @param constantPool Array of constants
*/
protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes,
final ConstantPool constantPool) {
super(accessFlags);
this.name_index = nameIndex;
this.signature_index = signatureIndex;
this.constant_pool = constantPool;
setAttributes(attributes);
}
/**
* @return deep copy of this field
*/
protected FieldOrMethod copy_(final ConstantPool constantPool) {
try {
final FieldOrMethod c = (FieldOrMethod) clone();
c.constant_pool = constantPool;
c.attributes = new Attribute[attributes.length];
c.attributes_count = attributes_count; // init deprecated field
Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
return c;
} catch (final CloneNotSupportedException e) {
throw new UnsupportedOperationException(e);
}
}
/**
* Dump object to file stream on binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public final void dump(final DataOutputStream file) throws IOException {
file.writeShort(super.getAccessFlags());
file.writeShort(name_index);
file.writeShort(signature_index);
file.writeShort(attributes_count);
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
}
/**
* @return Annotations on the field or method
* @since 6.0
*/
public AnnotationEntry[] getAnnotationEntries() {
if (annotationEntries == null) {
annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes());
}
return annotationEntries;
}
/**
* Gets attribute for given tag.
* @return Attribute for given tag, null if not found.
* Refer to {@link com.sun.org.apache.bcel.internal.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values.
* @since 6.10.0
*/
@SuppressWarnings("unchecked")
public final <T extends Attribute> T getAttribute(final byte tag) {
for (final Attribute attribute : getAttributes()) {
if (attribute.getTag() == tag) {
return (T) attribute;
}
}
return null;
}
/**
* @return Collection of object attributes.
*/
public final Attribute[] getAttributes() {
return attributes;
}
/**
* @return Constant pool used by this object.
*/
public final ConstantPool getConstantPool() {
return constant_pool;
}
/**
* Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be
* (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector&lt;Ljava/lang/String&gt;;' Coded for
* performance - searches for the attribute only when requested - only searches for it once.
*
* @since 6.0
*/
public final String getGenericSignature() {
if (!searchedForSignatureAttribute) {
boolean found = false;
for (int i = 0; !found && i < attributes.length; i++) {
if (attributes[i] instanceof Signature) {
signatureAttributeString = ((Signature) attributes[i]).getSignature();
found = true;
}
}
searchedForSignatureAttribute = true;
}
return signatureAttributeString;
}
/**
* @return Name of object, i.e., method name or field name
*/
public final String getName() {
return constant_pool.getConstantUtf8(name_index).getBytes();
}
/**
* @return Index in constant pool of object's name.
*/
public final int getNameIndex() {
return name_index;
}
/**
* @return String representation of object's type signature (Java style)
*/
public final String getSignature() {
return constant_pool.getConstantUtf8(signature_index).getBytes();
}
/**
* @return Index in constant pool of field signature.
*/
public final int getSignatureIndex() {
return signature_index;
}
/**
* @param attributes Collection of object attributes.
*/
public final void setAttributes(final Attribute[] attributes) {
this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
this.attributes_count = this.attributes.length; // init deprecated field
}
/**
* @param constantPool Constant pool to be used for this object.
*/
public final void setConstantPool(final ConstantPool constantPool) {
this.constant_pool = constantPool;
}
/**
* @param nameIndex Index in constant pool of object's name.
*/
public final void setNameIndex(final int nameIndex) {
this.name_index = nameIndex;
}
/**
* @param signatureIndex Index in constant pool of field signature.
*/
public final void setSignatureIndex(final int signatureIndex) {
this.signature_index = signatureIndex;
}
}

View file

@ -0,0 +1,198 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a inner class attribute, i.e., the class indices of the inner and outer classes, the name and
* the attributes of the inner class.
*
* @see InnerClasses
*/
public final class InnerClass implements Cloneable, Node {
private int innerClassIndex;
private int outerClassIndex;
private int innerNameIndex;
private int innerAccessFlags;
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
InnerClass(final DataInput file) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* Initialize from another object.
*
* @param c Source to copy.
*/
public InnerClass(final InnerClass c) {
this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c.getInnerAccessFlags());
}
/**
* @param innerClassIndex Class index in constant pool of inner class
* @param outerClassIndex Class index in constant pool of outer class
* @param innerNameIndex Name index in constant pool of inner class
* @param innerAccessFlags Access flags of inner class
*/
public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex, final int innerAccessFlags) {
this.innerClassIndex = innerClassIndex;
this.outerClassIndex = outerClassIndex;
this.innerNameIndex = innerNameIndex;
this.innerAccessFlags = innerAccessFlags;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitInnerClass(this);
}
/**
* @return deep copy of this object
*/
public InnerClass copy() {
try {
return (InnerClass) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dump inner class attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(innerClassIndex);
file.writeShort(outerClassIndex);
file.writeShort(innerNameIndex);
file.writeShort(innerAccessFlags);
}
/**
* @return access flags of inner class.
*/
public int getInnerAccessFlags() {
return innerAccessFlags;
}
/**
* @return class index of inner class.
*/
public int getInnerClassIndex() {
return innerClassIndex;
}
/**
* @return name index of inner class.
*/
public int getInnerNameIndex() {
return innerNameIndex;
}
/**
* @return class index of outer class.
*/
public int getOuterClassIndex() {
return outerClassIndex;
}
/**
* @param innerAccessFlags access flags for this inner class
*/
public void setInnerAccessFlags(final int innerAccessFlags) {
this.innerAccessFlags = innerAccessFlags;
}
/**
* @param innerClassIndex index into the constant pool for this class
*/
public void setInnerClassIndex(final int innerClassIndex) {
this.innerClassIndex = innerClassIndex;
}
/**
* @param innerNameIndex index into the constant pool for this class's name
*/
public void setInnerNameIndex(final int innerNameIndex) { // TODO unused
this.innerNameIndex = innerNameIndex;
}
/**
* @param outerClassIndex index into the constant pool for the owning class
*/
public void setOuterClassIndex(final int outerClassIndex) { // TODO unused
this.outerClassIndex = outerClassIndex;
}
/**
* @return String representation.
*/
@Override
public String toString() {
return "InnerClass(" + innerClassIndex + ", " + outerClassIndex + ", " + innerNameIndex + ", " + innerAccessFlags + ")";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
String outerClassName;
String innerName;
String innerClassName = constantPool.getConstantString(innerClassIndex, Const.CONSTANT_Class);
innerClassName = Utility.compactClassName(innerClassName, false);
if (outerClassIndex != 0) {
outerClassName = constantPool.getConstantString(outerClassIndex, Const.CONSTANT_Class);
outerClassName = " of class " + Utility.compactClassName(outerClassName, false);
} else {
outerClassName = "";
}
if (innerNameIndex != 0) {
innerName = constantPool.getConstantUtf8(innerNameIndex).getBytes();
} else {
innerName = "(anonymous)";
}
String access = Utility.accessToString(innerAccessFlags, true);
access = access.isEmpty() ? "" : access + " ";
return " " + access + innerName + "=class " + innerClassName + outerClassName;
}
}

View file

@ -0,0 +1,161 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and denotes that this class is an Inner class of another. to the source
* file of this class. It is instantiated from the <em>Attribute.readAttribute()</em> method.
*
* @see Attribute
*/
public final class InnerClasses extends Attribute implements Iterable<InnerClass> {
/**
* Empty array.
*/
private static final InnerClass[] EMPTY_ARRAY = {};
private InnerClass[] innerClasses;
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public InnerClasses(final InnerClasses c) {
this(c.getNameIndex(), c.getLength(), c.getInnerClasses(), c.getConstantPool());
}
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
InnerClasses(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (InnerClass[]) null, constantPool);
final int classCount = input.readUnsignedShort();
innerClasses = new InnerClass[classCount];
for (int i = 0; i < classCount; i++) {
innerClasses[i] = new InnerClass(input);
}
}
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param innerClasses array of inner classes attributes
* @param constantPool Array of constants
*/
public InnerClasses(final int nameIndex, final int length, final InnerClass[] innerClasses, final ConstantPool constantPool) {
super(Const.ATTR_INNER_CLASSES, nameIndex, length, constantPool);
this.innerClasses = innerClasses != null ? innerClasses : EMPTY_ARRAY;
Args.requireU2(this.innerClasses.length, "innerClasses.length");
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitInnerClasses(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
// TODO this could be recoded to use a lower level constructor after creating a copy of the inner classes
final InnerClasses c = (InnerClasses) clone();
c.innerClasses = new InnerClass[innerClasses.length];
Arrays.setAll(c.innerClasses, i -> innerClasses[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(innerClasses.length);
for (final InnerClass innerClass : innerClasses) {
innerClass.dump(file);
}
}
/**
* @return array of inner class "records"
*/
public InnerClass[] getInnerClasses() {
return innerClasses;
}
@Override
public Iterator<InnerClass> iterator() {
return Stream.of(innerClasses).iterator();
}
/**
* @param innerClasses the array of inner classes
*/
public void setInnerClasses(final InnerClass[] innerClasses) {
this.innerClasses = innerClasses != null ? innerClasses : EMPTY_ARRAY;
}
/**
* @return String representation.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("InnerClasses(");
buf.append(innerClasses.length);
buf.append("):\n");
for (final InnerClass innerClass : innerClasses) {
buf.append(innerClass.toString(super.getConstantPool())).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View file

@ -0,0 +1,53 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
/**
* Thrown when the BCEL attempts to read a class file and determines that a class is malformed or otherwise cannot be interpreted as a class file.
*
* @since 6.8.0
*/
public class InvalidMethodSignatureException extends ClassFormatException {
private static final long serialVersionUID = 1L;
/**
* Constructs a new instance with the specified invalid signature as the message.
*
* @param signature The invalid signature is saved for later retrieval by the {@link #getMessage()} method.
*/
public InvalidMethodSignatureException(final String signature) {
super(signature);
}
/**
* Constructs a new instance with the specified invalid signature as the message and a cause.
*
* @param signature The invalid signature is saved for later retrieval by the {@link #getMessage()} method.
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). A {@code null} value is permitted, and indicates that
* the cause is nonexistent or unknown.
*/
public InvalidMethodSignatureException(final String signature, final Throwable cause) {
super(signature, cause);
}
}

View file

@ -0,0 +1,942 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.generic.Type;
import com.sun.org.apache.bcel.internal.util.BCELComparator;
import com.sun.org.apache.bcel.internal.util.ClassQueue;
import com.sun.org.apache.bcel.internal.util.SyntheticRepository;
import jdk.xml.internal.Utils;
/**
* Represents a Java class, i.e., the data structures, constant pool, fields, methods and commands contained in a Java
* .class file. See <a href="https://docs.oracle.com/javase/specs/">JVM specification</a> for details. The intent of
* this class is to represent a parsed or otherwise existing class file. Those interested in programmatically generating
* classes should see the <a href="../generic/ClassGen.html">ClassGen</a> class.
*
* @see com.sun.org.apache.bcel.internal.generic.ClassGen
* @LastModified: Sept 2025
*/
public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable<JavaClass> {
/**
* The standard class file extension.
*
* @since 6.7.0
*/
public static final String EXTENSION = ".class";
/**
* Empty array.
*
* @since 6.6.0
*/
public static final JavaClass[] EMPTY_ARRAY = {};
public static final byte HEAP = 1;
public static final byte FILE = 2;
public static final byte ZIP = 3;
private static BCELComparator<JavaClass> bcelComparator = new BCELComparator<JavaClass>() {
@Override
public boolean equals(final JavaClass a, final JavaClass b) {
return a == b || a != null && b != null && Objects.equals(a.getClassName(), b.getClassName());
}
@Override
public int hashCode(final JavaClass o) {
return o != null ? Objects.hashCode(o.getClassName()) : 0;
}
};
/**
* @return Comparison strategy object.
*/
public static BCELComparator<JavaClass> getComparator() {
return bcelComparator;
}
private static String indent(final Object obj) {
final StringTokenizer tokenizer = new StringTokenizer(obj.toString(), "\n");
final StringBuilder buf = new StringBuilder();
while (tokenizer.hasMoreTokens()) {
buf.append("\t").append(tokenizer.nextToken()).append("\n");
}
return buf.toString();
}
/**
* @param comparator Comparison strategy object.
*/
public static void setComparator(final BCELComparator<JavaClass> comparator) {
bcelComparator = comparator;
}
private String fileName;
private final String packageName;
private String sourceFileName = "<Unknown>";
private int classNameIndex;
private int superclassNameIndex;
private String className;
private String superclassName;
private int major;
private int minor; // Compiler version
private ConstantPool constantPool; // Constant pool
private int[] interfaces; // implemented interfaces
private String[] interfaceNames;
private Field[] fields; // Fields, i.e., variables of class
private Method[] methods; // methods defined in the class
private Attribute[] attributes; // attributes defined in the class
private AnnotationEntry[] annotations; // annotations defined on the class
private byte source = HEAP; // Generated in memory
private boolean isAnonymous;
private boolean isNested;
private boolean isRecord;
private boolean computedNestedTypeStatus;
private boolean computedRecord;
/**
* In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any
* better.
*/
private transient com.sun.org.apache.bcel.internal.util.Repository repository = SyntheticRepository.getInstance();
/**
* Constructor gets all contents as arguments.
*
* @param classNameIndex Class name
* @param superclassNameIndex Superclass name
* @param fileName File name
* @param major Major compiler version
* @param minor Minor compiler version
* @param accessFlags Access rights defined by bit flags
* @param constantPool Array of constants
* @param interfaces Implemented interfaces
* @param fields Class fields
* @param methods Class methods
* @param attributes Class attributes
*/
public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags,
final ConstantPool constantPool, final int[] interfaces, final Field[] fields, final Method[] methods, final Attribute[] attributes) {
this(classNameIndex, superclassNameIndex, fileName, major, minor, accessFlags, constantPool, interfaces, fields, methods, attributes, HEAP);
}
/**
* Constructor gets all contents as arguments.
*
* @param classNameIndex Index into constant pool referencing a ConstantClass that represents this class.
* @param superclassNameIndex Index into constant pool referencing a ConstantClass that represents this class's
* superclass.
* @param fileName File name
* @param major Major compiler version
* @param minor Minor compiler version
* @param accessFlags Access rights defined by bit flags
* @param constantPool Array of constants
* @param interfaces Implemented interfaces
* @param fields Class fields
* @param methods Class methods
* @param attributes Class attributes
* @param source Read from file or generated in memory?
*/
public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags,
final ConstantPool constantPool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes, final byte source) {
super(accessFlags);
interfaces = Utils.createEmptyArrayIfNull(interfaces);
if (attributes == null) {
attributes = Attribute.EMPTY_ARRAY;
}
if (fields == null) {
fields = Field.EMPTY_ARRAY;
}
if (methods == null) {
methods = Method.EMPTY_ARRAY;
}
this.classNameIndex = classNameIndex;
this.superclassNameIndex = superclassNameIndex;
this.fileName = fileName;
this.major = major;
this.minor = minor;
this.constantPool = constantPool;
this.interfaces = interfaces;
this.fields = fields;
this.methods = methods;
this.attributes = attributes;
this.source = source;
// Get source file name if available
for (final Attribute attribute : attributes) {
if (attribute instanceof SourceFile) {
sourceFileName = ((SourceFile) attribute).getSourceFileName();
break;
}
}
/*
* According to the specification the following entries must be of type 'ConstantClass' but we check that anyway via the
* 'ConstPool.getConstant' method.
*/
className = constantPool.getConstantString(classNameIndex, Const.CONSTANT_Class);
className = Utility.compactClassName(className, false);
final int index = className.lastIndexOf('.');
if (index < 0) {
packageName = "";
} else {
packageName = className.substring(0, index);
}
if (superclassNameIndex > 0) {
// May be zero -> class is java.lang.Object
superclassName = constantPool.getConstantString(superclassNameIndex, Const.CONSTANT_Class);
superclassName = Utility.compactClassName(superclassName, false);
} else {
superclassName = "java.lang.Object";
}
interfaceNames = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
final String str = constantPool.getConstantString(interfaces[i], Const.CONSTANT_Class);
interfaceNames[i] = Utility.compactClassName(str, false);
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitJavaClass(this);
}
/**
* Return the natural ordering of two JavaClasses. This ordering is based on the class name
*
* @since 6.0
*/
@Override
public int compareTo(final JavaClass obj) {
return getClassName().compareTo(obj.getClassName());
}
private void computeIsRecord() {
if (computedRecord) {
return;
}
for (final Attribute attribute : this.attributes) {
if (attribute instanceof Record) {
isRecord = true;
break;
}
}
this.computedRecord = true;
}
private void computeNestedTypeStatus() {
if (computedNestedTypeStatus) {
return;
}
for (final Attribute attribute : this.attributes) {
if (attribute instanceof InnerClasses) {
((InnerClasses) attribute).forEach(innerClass -> {
boolean innerClassAttributeRefersToMe = false;
String innerClassName = constantPool.getConstantString(innerClass.getInnerClassIndex(), Const.CONSTANT_Class);
innerClassName = Utility.compactClassName(innerClassName, false);
if (innerClassName.equals(getClassName())) {
innerClassAttributeRefersToMe = true;
}
if (innerClassAttributeRefersToMe) {
this.isNested = true;
if (innerClass.getInnerNameIndex() == 0) {
this.isAnonymous = true;
}
}
});
}
}
this.computedNestedTypeStatus = true;
}
/**
* @return deep copy of this class
*/
public JavaClass copy() {
try {
final JavaClass c = (JavaClass) clone();
c.constantPool = constantPool.copy();
c.interfaces = interfaces.clone();
c.interfaceNames = interfaceNames.clone();
c.fields = new Field[fields.length];
Arrays.setAll(c.fields, i -> fields[i].copy(c.constantPool));
c.methods = new Method[methods.length];
Arrays.setAll(c.methods, i -> methods[i].copy(c.constantPool));
c.attributes = new Attribute[attributes.length];
Arrays.setAll(c.attributes, i -> attributes[i].copy(c.constantPool));
return c;
} catch (final CloneNotSupportedException e) {
return null;
}
}
/**
* Dump Java class to output stream in binary format.
*
* @param file Output stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeInt(Const.JVM_CLASSFILE_MAGIC);
file.writeShort(minor);
file.writeShort(major);
constantPool.dump(file);
file.writeShort(super.getAccessFlags());
file.writeShort(classNameIndex);
file.writeShort(superclassNameIndex);
file.writeShort(interfaces.length);
for (final int interface1 : interfaces) {
file.writeShort(interface1);
}
file.writeShort(fields.length);
for (final Field field : fields) {
field.dump(file);
}
file.writeShort(methods.length);
for (final Method method : methods) {
method.dump(file);
}
if (attributes != null) {
file.writeShort(attributes.length);
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
} else {
file.writeShort(0);
}
file.flush();
}
/**
* Dump class to a file.
*
* @param file Output file
* @throws IOException if an I/O error occurs.
*/
public void dump(final File file) throws IOException {
final String parent = file.getParent();
if (parent != null) {
final File dir = new File(parent);
if (!dir.mkdirs() && !dir.isDirectory()) {
throw new IOException("Could not create the directory " + dir);
}
}
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
dump(dos);
}
}
/**
* Dump Java class to output stream in binary format.
*
* @param file Output stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final OutputStream file) throws IOException {
dump(new DataOutputStream(file));
}
/**
* Dump class to a file named fileName.
*
* @param fileName Output file name
* @throws IOException if an I/O error occurs.
*/
public void dump(final String fileName) throws IOException {
dump(new File(fileName));
}
/**
* Return value as defined by given BCELComparator strategy. By default two JavaClass objects are said to be equal when
* their class names are equal.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(final Object obj) {
return obj instanceof JavaClass && bcelComparator.equals(this, (JavaClass) obj);
}
/**
* Finds a visible field by name and type in this class and its super classes.
* @param fieldName the field name to find
* @param fieldType the field type to find
* @return field matching given name and type, null if field is not found or not accessible from this class.
* @throws ClassNotFoundException
* @since 6.8.0
*/
public Field findField(final String fieldName, final Type fieldType) throws ClassNotFoundException {
for (final Field field : fields) {
if (field.getName().equals(fieldName)) {
final Type fType = Type.getType(field.getSignature());
/*
* TODO: Check if assignment compatibility is sufficient. What does Sun do?
*/
if (fType.equals(fieldType)) {
return field;
}
}
}
final JavaClass superclass = getSuperClass();
if (superclass != null && !"java.lang.Object".equals(superclass.getClassName())) {
final Field f = superclass.findField(fieldName, fieldType);
if (f != null && (f.isPublic() || f.isProtected() || !f.isPrivate() && packageName.equals(superclass.getPackageName()))) {
return f;
}
}
final JavaClass[] implementedInterfaces = getInterfaces();
if (implementedInterfaces != null) {
for (final JavaClass implementedInterface : implementedInterfaces) {
final Field f = implementedInterface.findField(fieldName, fieldType);
if (f != null) {
return f;
}
}
}
return null;
}
/**
* Gets all interfaces implemented by this JavaClass (transitively).
*
* @throws ClassNotFoundException if any of the class's superclasses or interfaces can't be found.
*/
public JavaClass[] getAllInterfaces() throws ClassNotFoundException {
final ClassQueue queue = new ClassQueue();
final Set<JavaClass> allInterfaces = new TreeSet<>();
queue.enqueue(this);
while (!queue.empty()) {
final JavaClass clazz = queue.dequeue();
final JavaClass souper = clazz.getSuperClass();
final JavaClass[] interfaces = clazz.getInterfaces();
if (clazz.isInterface()) {
allInterfaces.add(clazz);
} else if (souper != null) {
queue.enqueue(souper);
}
for (final JavaClass iface : interfaces) {
queue.enqueue(iface);
}
}
return allInterfaces.toArray(EMPTY_ARRAY);
}
/**
* @return Annotations on the class
* @since 6.0
*/
public AnnotationEntry[] getAnnotationEntries() {
if (annotations == null) {
annotations = AnnotationEntry.createAnnotationEntries(getAttributes());
}
return annotations;
}
/**
* Gets attribute for given tag.
* @return Attribute for given tag, null if not found.
* Refer to {@link com.sun.org.apache.bcel.internal.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values.
* @since 6.10.0
*/
@SuppressWarnings("unchecked")
public final <T extends Attribute> T getAttribute(final byte tag) {
for (final Attribute attribute : getAttributes()) {
if (attribute.getTag() == tag) {
return (T) attribute;
}
}
return null;
}
/**
* @return Attributes of the class.
*/
public Attribute[] getAttributes() {
return attributes;
}
/**
* @return class in binary format
*/
public byte[] getBytes() {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (DataOutputStream dos = new DataOutputStream(baos)) {
dump(dos);
} catch (final IOException e) {
e.printStackTrace();
}
return baos.toByteArray();
}
/**
* @return Class name.
*/
public String getClassName() {
return className;
}
/**
* @return Class name index.
*/
public int getClassNameIndex() {
return classNameIndex;
}
/**
* @return Constant pool.
*/
public ConstantPool getConstantPool() {
return constantPool;
}
/**
* @return Fields, i.e., variables of the class. Like the JVM spec mandates for the classfile format, these fields are
* those specific to this class, and not those of the superclass or superinterfaces.
*/
public Field[] getFields() {
return fields;
}
/**
* @return File name of class, aka SourceFile attribute value
*/
public String getFileName() {
return fileName;
}
/**
* @return Indices in constant pool of implemented interfaces.
*/
public int[] getInterfaceIndices() {
return interfaces;
}
/**
* @return Names of implemented interfaces.
*/
public String[] getInterfaceNames() {
return interfaceNames;
}
/**
* Gets interfaces directly implemented by this JavaClass.
*
* @throws ClassNotFoundException if any of the class's interfaces can't be found.
*/
public JavaClass[] getInterfaces() throws ClassNotFoundException {
final String[] interfaces = getInterfaceNames();
final JavaClass[] classes = new JavaClass[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
classes[i] = repository.loadClass(interfaces[i]);
}
return classes;
}
/**
* @return Major number of class file version.
*/
public int getMajor() {
return major;
}
/**
* @return A {@link Method} corresponding to java.lang.reflect.Method if any
*/
public Method getMethod(final java.lang.reflect.Method m) {
for (final Method method : methods) {
if (m.getName().equals(method.getName()) && m.getModifiers() == method.getModifiers() && Type.getSignature(m).equals(method.getSignature())) {
return method;
}
}
return null;
}
/**
* @return Methods of the class.
*/
public Method[] getMethods() {
return methods;
}
/**
* @return Minor number of class file version.
*/
public int getMinor() {
return minor;
}
/**
* @return Package name.
*/
public String getPackageName() {
return packageName;
}
/**
* Gets the ClassRepository which holds its definition. By default this is the same as
* SyntheticRepository.getInstance();
*/
public com.sun.org.apache.bcel.internal.util.Repository getRepository() {
return repository;
}
/**
* @return returns either HEAP (generated), FILE, or ZIP
*/
public final byte getSource() {
return source;
}
/**
* @return file name where this class was read from
*/
public String getSourceFileName() {
return sourceFileName;
}
/**
* Gets the source file path including the package path.
*
* @return path to original source file of parsed class, relative to original source directory.
* @since 6.7.0
*/
public String getSourceFilePath() {
final StringBuilder outFileName = new StringBuilder();
if (!packageName.isEmpty()) {
outFileName.append(Utility.packageToPath(packageName));
outFileName.append('/');
}
outFileName.append(sourceFileName);
return outFileName.toString();
}
/**
* @return the superclass for this JavaClass object, or null if this is {@link Object}
* @throws ClassNotFoundException if the superclass can't be found
*/
public JavaClass getSuperClass() throws ClassNotFoundException {
if ("java.lang.Object".equals(getClassName())) {
return null;
}
return repository.loadClass(getSuperclassName());
}
/**
* @return list of super classes of this class in ascending order, i.e., java.lang.Object is always the last element
* @throws ClassNotFoundException if any of the superclasses can't be found
*/
public JavaClass[] getSuperClasses() throws ClassNotFoundException {
JavaClass clazz = this;
final List<JavaClass> allSuperClasses = new ArrayList<>();
for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) {
allSuperClasses.add(clazz);
}
return allSuperClasses.toArray(EMPTY_ARRAY);
}
/**
* returns the super class name of this class. In the case that this class is {@link Object}, it will return itself
* ({@link Object}). This is probably incorrect but isn't fixed at this time to not break existing clients.
*
* @return Superclass name.
*/
public String getSuperclassName() {
return superclassName;
}
/**
* @return Class name index.
*/
public int getSuperclassNameIndex() {
return superclassNameIndex;
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hash code of the class name.
*
* @see Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
/**
* @return true, if this class is an implementation of interface inter
* @throws ClassNotFoundException if superclasses or superinterfaces of this class can't be found
*/
public boolean implementationOf(final JavaClass inter) throws ClassNotFoundException {
if (!inter.isInterface()) {
throw new IllegalArgumentException(inter.getClassName() + " is no interface");
}
if (equals(inter)) {
return true;
}
final JavaClass[] superInterfaces = getAllInterfaces();
for (final JavaClass superInterface : superInterfaces) {
if (superInterface.equals(inter)) {
return true;
}
}
return false;
}
/**
* Equivalent to runtime "instanceof" operator.
*
* @return true if this JavaClass is derived from the super class
* @throws ClassNotFoundException if superclasses or superinterfaces of this object can't be found
*/
public final boolean instanceOf(final JavaClass superclass) throws ClassNotFoundException {
if (equals(superclass)) {
return true;
}
for (final JavaClass clazz : getSuperClasses()) {
if (clazz.equals(superclass)) {
return true;
}
}
if (superclass.isInterface()) {
return implementationOf(superclass);
}
return false;
}
/**
* @since 6.0
*/
public final boolean isAnonymous() {
computeNestedTypeStatus();
return this.isAnonymous;
}
public final boolean isClass() {
return (super.getAccessFlags() & Const.ACC_INTERFACE) == 0;
}
/**
* @since 6.0
*/
public final boolean isNested() {
computeNestedTypeStatus();
return this.isNested;
}
/**
* Tests whether this class was declared as a record
*
* @return true if a record attribute is present, false otherwise.
* @since 6.9.0
*/
public boolean isRecord() {
computeIsRecord();
return this.isRecord;
}
public final boolean isSuper() {
return (super.getAccessFlags() & Const.ACC_SUPER) != 0;
}
/**
* @param attributes .
*/
public void setAttributes(final Attribute[] attributes) {
this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
}
/**
* @param className .
*/
public void setClassName(final String className) {
this.className = className;
}
/**
* @param classNameIndex .
*/
public void setClassNameIndex(final int classNameIndex) {
this.classNameIndex = classNameIndex;
}
/**
* @param constantPool .
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
/**
* @param fields .
*/
public void setFields(final Field[] fields) {
this.fields = fields != null ? fields : Field.EMPTY_ARRAY;
}
/**
* Sets File name of class, aka SourceFile attribute value
*/
public void setFileName(final String fileName) {
this.fileName = fileName;
}
/**
* @param interfaceNames .
*/
public void setInterfaceNames(final String[] interfaceNames) {
this.interfaceNames = Utils.createEmptyArrayIfNull(interfaceNames, String[].class);
}
/**
* @param interfaces .
*/
public void setInterfaces(final int[] interfaces) {
this.interfaces = Utils.createEmptyArrayIfNull(interfaces);
}
/**
* @param major .
*/
public void setMajor(final int major) {
this.major = major;
}
/**
* @param methods .
*/
public void setMethods(final Method[] methods) {
this.methods = methods != null ? methods : Method.EMPTY_ARRAY;
}
/**
* @param minor .
*/
public void setMinor(final int minor) {
this.minor = minor;
}
/**
* Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done.
*/
public void setRepository(final com.sun.org.apache.bcel.internal.util.Repository repository) { // TODO make protected?
this.repository = repository;
}
/**
* Sets absolute path to file this class was read from.
*/
public void setSourceFileName(final String sourceFileName) {
this.sourceFileName = sourceFileName;
}
/**
* @param superclassName .
*/
public void setSuperclassName(final String superclassName) {
this.superclassName = superclassName;
}
/**
* @param superclassNameIndex .
*/
public void setSuperclassNameIndex(final int superclassNameIndex) {
this.superclassNameIndex = superclassNameIndex;
}
/**
* @return String representing class contents.
*/
@Override
public String toString() {
String access = Utility.accessToString(super.getAccessFlags(), true);
access = access.isEmpty() ? "" : access + " ";
final StringBuilder buf = new StringBuilder(128);
buf.append(access).append(Utility.classOrInterface(super.getAccessFlags())).append(" ").append(className).append(" extends ")
.append(Utility.compactClassName(superclassName, false)).append('\n');
final int size = interfaces.length;
if (size > 0) {
buf.append("implements\t\t");
for (int i = 0; i < size; i++) {
buf.append(interfaceNames[i]);
if (i < size - 1) {
buf.append(", ");
}
}
buf.append('\n');
}
buf.append("file name\t\t").append(fileName).append('\n');
buf.append("compiled from\t\t").append(sourceFileName).append('\n');
buf.append("compiler version\t").append(major).append(".").append(minor).append('\n');
buf.append("access flags\t\t").append(super.getAccessFlags()).append('\n');
buf.append("constant pool\t\t").append(constantPool.getLength()).append(" entries\n");
buf.append("ACC_SUPER flag\t\t").append(isSuper()).append("\n");
if (attributes.length > 0) {
buf.append("\nAttribute(s):\n");
for (final Attribute attribute : attributes) {
buf.append(indent(attribute));
}
}
final AnnotationEntry[] annotations = getAnnotationEntries();
if (annotations != null && annotations.length > 0) {
buf.append("\nAnnotation(s):\n");
for (final AnnotationEntry annotation : annotations) {
buf.append(indent(annotation));
}
}
if (fields.length > 0) {
buf.append("\n").append(fields.length).append(" fields:\n");
for (final Field field : fields) {
buf.append("\t").append(field).append('\n');
}
}
if (methods.length > 0) {
buf.append("\n").append(methods.length).append(" methods:\n");
for (final Method method : methods) {
buf.append("\t").append(method).append('\n');
}
}
return buf.toString();
}
}

View file

@ -0,0 +1,143 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents a (PC offset, line number) pair, i.e., a line number in the source that corresponds to a
* relative address in the byte code. This is used for debugging purposes.
*
* @see LineNumberTable
*/
public final class LineNumber implements Cloneable, Node {
static final LineNumber[] EMPTY_ARRAY = {};
/** Program Counter (PC) corresponds to line */
private int startPc;
/** Number in source file */
private int lineNumber;
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort
*/
LineNumber(final DataInput file) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort());
}
/**
* @param startPc Program Counter (PC) corresponds to
* @param lineNumber line number in source file
*/
public LineNumber(final int startPc, final int lineNumber) {
this.startPc = Args.requireU2(startPc, "startPc");
this.lineNumber = Args.requireU2(lineNumber, "lineNumber");
}
/**
* Initialize from another object.
*
* @param c the object to copy
*/
public LineNumber(final LineNumber c) {
this(c.getStartPC(), c.getLineNumber());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitLineNumber(this);
}
/**
* @return deep copy of this object
*/
public LineNumber copy() {
try {
return (LineNumber) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dump line number/pc pair to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(startPc);
file.writeShort(lineNumber);
}
/**
* @return Corresponding source line
*/
public int getLineNumber() {
return lineNumber & 0xffff;
}
/**
* @return PC in code
*/
public int getStartPC() {
return startPc & 0xffff;
}
/**
* @param lineNumber the source line number
*/
public void setLineNumber(final int lineNumber) {
this.lineNumber = (short) lineNumber;
}
/**
* @param startPc the pc for this line number
*/
public void setStartPC(final int startPc) {
this.startPc = (short) startPc;
}
/**
* @return String representation
*/
@Override
public String toString() {
return "LineNumber(" + getStartPC() + ", " + getLineNumber() + ")";
}
}

View file

@ -0,0 +1,218 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
import jdk.xml.internal.SecuritySupport;
/**
* This class represents a table of line numbers for debugging purposes. This attribute is used by the <em>Code</em>
* attribute. It contains pairs of PCs and line numbers.
*
* @see Code
* @see LineNumber
* @LastModified: Sept 2025
*/
public final class LineNumberTable extends Attribute implements Iterable<LineNumber> {
private static final int MAX_LINE_LENGTH = 72;
private LineNumber[] lineNumberTable; // Table of line/numbers pairs
/**
* Constructs a new instance from a data input stream.
*
* @param nameIndex Index of name
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O Exception occurs in readUnsignedShort
*/
LineNumberTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (LineNumber[]) null, constantPool);
final int lineNumberTableLength = input.readUnsignedShort();
lineNumberTable = new LineNumber[lineNumberTableLength];
for (int i = 0; i < lineNumberTableLength; i++) {
lineNumberTable[i] = new LineNumber(input);
}
}
/**
* Constructs a new instance.
*
* @param nameIndex Index of name
* @param length Content length in bytes
* @param lineNumberTable Table of line/numbers pairs
* @param constantPool Array of constants
*/
public LineNumberTable(final int nameIndex, final int length, final LineNumber[] lineNumberTable, final ConstantPool constantPool) {
super(Const.ATTR_LINE_NUMBER_TABLE, nameIndex, length, constantPool);
this.lineNumberTable = lineNumberTable != null ? lineNumberTable : LineNumber.EMPTY_ARRAY;
Args.requireU2(this.lineNumberTable.length, "lineNumberTable.length");
}
/**
* Constructs a new instance from another.
* <p>
* Note that both objects use the same references (shallow copy). Use copy() for a physical copy.
* </p>
*/
public LineNumberTable(final LineNumberTable c) {
this(c.getNameIndex(), c.getLength(), c.getLineNumberTable(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitLineNumberTable(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
// TODO could use the lower level constructor and thereby allow
// lineNumberTable to be made final
final LineNumberTable c = (LineNumberTable) clone();
c.lineNumberTable = new LineNumber[lineNumberTable.length];
Arrays.setAll(c.lineNumberTable, i -> lineNumberTable[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump line number table attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(lineNumberTable.length);
for (final LineNumber lineNumber : lineNumberTable) {
lineNumber.dump(file);
}
}
/**
* @return Array of (pc offset, line number) pairs.
*/
public LineNumber[] getLineNumberTable() {
return lineNumberTable;
}
/**
* Map byte code positions to source code lines.
*
* @param pos byte code offset
* @return corresponding line in source code
*/
public int getSourceLine(final int pos) {
int l = 0;
int r = lineNumberTable.length - 1;
if (r < 0) {
return -1;
}
int minIndex = -1;
int min = -1;
/*
* Do a binary search since the array is ordered.
*/
do {
final int i = l + r >>> 1;
final int j = lineNumberTable[i].getStartPC();
if (j == pos) {
return lineNumberTable[i].getLineNumber();
}
if (pos < j) {
r = i - 1;
} else {
l = i + 1;
}
/*
* If exact match can't be found (which is the most common case) return the line number that corresponds to the greatest
* index less than pos.
*/
if (j < pos && j > min) {
min = j;
minIndex = i;
}
} while (l <= r);
/*
* It's possible that we did not find any valid entry for the bytecode offset we were looking for.
*/
if (minIndex < 0) {
return -1;
}
return lineNumberTable[minIndex].getLineNumber();
}
public int getTableLength() {
return lineNumberTable == null ? 0 : lineNumberTable.length;
}
@Override
public Iterator<LineNumber> iterator() {
return Stream.of(lineNumberTable).iterator();
}
/**
* @param lineNumberTable the line number entries for this table
*/
public void setLineNumberTable(final LineNumber[] lineNumberTable) {
this.lineNumberTable = lineNumberTable != null ? lineNumberTable : LineNumber.EMPTY_ARRAY;
}
/**
* @return String representation.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
final StringBuilder line = new StringBuilder();
for (int i = 0; i < lineNumberTable.length; i++) {
line.append(lineNumberTable[i].toString());
if (i < lineNumberTable.length - 1) {
line.append(", ");
}
if (line.length() > MAX_LINE_LENGTH && i < lineNumberTable.length - 1) {
line.append(SecuritySupport.NEWLINE);
buf.append(line);
line.setLength(0);
}
}
buf.append(line);
return buf.toString();
}
}

View file

@ -0,0 +1,282 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents a local variable within a method. It contains its scope, name, signature and index on the
* method's frame. It is used both to represent an element of the LocalVariableTable as well as an element of the
* LocalVariableTypeTable. The nomenclature used here may be a bit confusing; while the two items have the same layout
* in a class file, a LocalVariableTable attribute contains a descriptor_index, not a signatureIndex. The
* LocalVariableTypeTable attribute does have a signatureIndex.
*
* @see com.sun.org.apache.bcel.internal.classfile.Utility for more details on the difference.
*
* @see LocalVariableTable
* @see LocalVariableTypeTable
* @LastModified: Feb 2023
*/
public final class LocalVariable implements Cloneable, Node {
static final LocalVariable[] EMPTY_ARRAY = {};
/** Range in which the variable is valid. */
private int startPc;
private int length;
/** Index in constant pool of variable name. */
private int nameIndex;
/**
* Technically, a decscriptor_index for a local variable table entry and a signatureIndex for a local variable type table entry. Index of variable signature
*/
private int signatureIndex;
/*
* Variable is index'th local variable on this method's frame.
*/
private int index;
private ConstantPool constantPool;
/** Never changes; used to match up with LocalVariableTypeTable entries. */
private final int origIndex;
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
LocalVariable(final DataInput file, final ConstantPool constantPool) throws IOException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), constantPool);
}
/**
* @param startPc Range in which the variable
* @param length ... is valid
* @param nameIndex Index in constant pool of variable name
* @param signatureIndex Index of variable's signature
* @param index Variable is 'index'th local variable on the method's frame
* @param constantPool Array of constants
*/
public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool) {
this(startPc, length, nameIndex, signatureIndex, index, constantPool, index);
}
/**
* @param startPc Range in which the variable
* @param length ... is valid
* @param nameIndex Index in constant pool of variable name
* @param signatureIndex Index of variable's signature
* @param index Variable is 'index'th local variable on the method's frame
* @param constantPool Array of constants
* @param origIndex Variable is 'index'th local variable on the method's frame prior to any changes
*/
public LocalVariable(final int startPc, final int length, final int nameIndex, final int signatureIndex, final int index, final ConstantPool constantPool,
final int origIndex) {
this.startPc = Args.requireU2(startPc, "startPc");
this.length = Args.requireU2(length, "length");
this.nameIndex = Args.requireU2(nameIndex, "nameIndex");
this.signatureIndex = Args.requireU2(signatureIndex, "signatureIndex");
this.index = Args.requireU2(index, "index");
this.origIndex = Args.requireU2(origIndex, "origIndex");
this.constantPool = constantPool;
}
/**
* Initializes from another LocalVariable. Note that both objects use the same references (shallow copy). Use copy() for
* a physical copy.
*
* @param localVariable Another LocalVariable.
*/
public LocalVariable(final LocalVariable localVariable) {
this(localVariable.getStartPC(), localVariable.getLength(), localVariable.getNameIndex(), localVariable.getSignatureIndex(), localVariable.getIndex(),
localVariable.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitLocalVariable(this);
}
/**
* @return deep copy of this object
*/
public LocalVariable copy() {
try {
return (LocalVariable) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dumps local variable to file stream in binary format.
*
* @param dataOutputStream Output file stream
* @throws IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public void dump(final DataOutputStream dataOutputStream) throws IOException {
dataOutputStream.writeShort(startPc);
dataOutputStream.writeShort(length);
dataOutputStream.writeShort(nameIndex);
dataOutputStream.writeShort(signatureIndex);
dataOutputStream.writeShort(index);
}
/**
* @return Constant pool used by this object.
*/
public ConstantPool getConstantPool() {
return constantPool;
}
/**
* @return index of register where variable is stored
*/
public int getIndex() {
return index;
}
/**
* @return Variable is valid within getStartPC() .. getStartPC()+getLength()
*/
public int getLength() {
return length;
}
/**
* @return Variable name.
*/
public String getName() {
return constantPool.getConstantUtf8(nameIndex).getBytes();
}
/**
* @return Index in constant pool of variable name.
*/
public int getNameIndex() {
return nameIndex;
}
/**
* @return index of register where variable was originally stored
*/
public int getOrigIndex() {
return origIndex;
}
/**
* @return Signature.
*/
public String getSignature() {
return constantPool.getConstantUtf8(signatureIndex).getBytes();
}
/**
* @return Index in constant pool of variable signature.
*/
public int getSignatureIndex() {
return signatureIndex;
}
/**
* @return Start of range where the variable is valid
*/
public int getStartPC() {
return startPc;
}
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
/**
* @param index the index in the local variable table of this variable
*/
public void setIndex(final int index) { // TODO unused
this.index = index;
}
/**
* @param length the length of this local variable
*/
public void setLength(final int length) {
this.length = length;
}
/**
* @param nameIndex the index into the constant pool for the name of this variable
*/
public void setNameIndex(final int nameIndex) { // TODO unused
this.nameIndex = nameIndex;
}
/**
* @param signatureIndex the index into the constant pool for the signature of this variable
*/
public void setSignatureIndex(final int signatureIndex) { // TODO unused
this.signatureIndex = signatureIndex;
}
/**
* @param startPc Specify range where the local variable is valid.
*/
public void setStartPC(final int startPc) { // TODO unused
this.startPc = startPc;
}
/**
* @return string representation.
*/
@Override
public String toString() {
return toStringShared(false);
}
/*
* Helper method shared with LocalVariableTypeTable
*/
String toStringShared(final boolean typeTable) {
final String name = getName();
final String signature = Utility.signatureToString(getSignature(), false);
final String label = "LocalVariable" + (typeTable ? "Types" : "");
return label + "(startPc = " + startPc + ", length = " + length + ", index = " + index + ":" + signature + " " + name + ")";
}
}

View file

@ -0,0 +1,198 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents colection of local variables in a method. This attribute is contained in the <em>Code</em>
* attribute.
*
* @see Code
* @see LocalVariable
*/
public class LocalVariableTable extends Attribute implements Iterable<LocalVariable> {
private static final LocalVariable[] EMPTY_ARRAY = {};
private LocalVariable[] localVariableTable; // variables
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
LocalVariableTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (LocalVariable[]) null, constantPool);
final int localVariableTableLength = input.readUnsignedShort();
localVariableTable = new LocalVariable[localVariableTableLength];
for (int i = 0; i < localVariableTableLength; i++) {
localVariableTable[i] = new LocalVariable(input, constantPool);
}
}
/**
* @param nameIndex Index in constant pool to 'LocalVariableTable'
* @param length Content length in bytes
* @param localVariableTable Table of local variables
* @param constantPool Array of constants
*/
public LocalVariableTable(final int nameIndex, final int length, final LocalVariable[] localVariableTable, final ConstantPool constantPool) {
super(Const.ATTR_LOCAL_VARIABLE_TABLE, nameIndex, length, constantPool);
this.localVariableTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY;
Args.requireU2(this.localVariableTable.length, "localVariableTable.length");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public LocalVariableTable(final LocalVariableTable c) {
this(c.getNameIndex(), c.getLength(), c.getLocalVariableTable(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitLocalVariableTable(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final LocalVariableTable c = (LocalVariableTable) clone();
c.localVariableTable = new LocalVariable[localVariableTable.length];
Arrays.setAll(c.localVariableTable, i -> localVariableTable[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump local variable table attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(localVariableTable.length);
for (final LocalVariable variable : localVariableTable) {
variable.dump(file);
}
}
/**
*
* @param index the variable slot
*
* @return the first LocalVariable that matches the slot or null if not found
*
* @deprecated since 5.2 because multiple variables can share the same slot, use getLocalVariable(int index, int pc)
* instead.
*/
@java.lang.Deprecated
public final LocalVariable getLocalVariable(final int index) {
for (final LocalVariable variable : localVariableTable) {
if (variable.getIndex() == index) {
return variable;
}
}
return null;
}
/**
*
* @param index the variable slot
* @param pc the current pc that this variable is alive
*
* @return the LocalVariable that matches or null if not found
*/
public final LocalVariable getLocalVariable(final int index, final int pc) {
for (final LocalVariable variable : localVariableTable) {
if (variable.getIndex() == index) {
final int startPc = variable.getStartPC();
final int endPc = startPc + variable.getLength();
if (pc >= startPc && pc <= endPc) {
return variable;
}
}
}
return null;
}
/**
* @return Array of local variables of method.
*/
public final LocalVariable[] getLocalVariableTable() {
return localVariableTable;
}
public final int getTableLength() {
return localVariableTable.length;
}
@Override
public Iterator<LocalVariable> iterator() {
return Stream.of(localVariableTable).iterator();
}
public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
this.localVariableTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY;
}
/**
* @return String representation.
*/
@Override
public final String toString() {
final StringBuilder buf = new StringBuilder();
for (int i = 0; i < localVariableTable.length; i++) {
buf.append(localVariableTable[i]);
if (i < localVariableTable.length - 1) {
buf.append('\n');
}
}
return buf.toString();
}
}

View file

@ -0,0 +1,155 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
// The new table is used when generic types are about...
//LocalVariableTable_attribute {
// u2 attribute_name_index;
// u4 attribute_length;
// u2 local_variable_table_length;
// { u2 start_pc;
// u2 length;
// u2 name_index;
// u2 descriptor_index;
// u2 index;
// } local_variable_table[local_variable_table_length];
// }
//LocalVariableTypeTable_attribute {
// u2 attribute_name_index;
// u4 attribute_length;
// u2 local_variable_type_table_length;
// {
// u2 start_pc;
// u2 length;
// u2 name_index;
// u2 signature_index;
// u2 index;
// } localVariableTypeTable[local_variable_type_table_length];
// }
// J5TODO: Needs some testing !
/**
* @since 6.0
*/
public class LocalVariableTypeTable extends Attribute implements Iterable<LocalVariable> {
private static final LocalVariable[] EMPTY_ARRAY = {};
private LocalVariable[] localVariableTypeTable; // variables
LocalVariableTypeTable(final int nameIdx, final int len, final DataInput input, final ConstantPool cpool) throws IOException {
this(nameIdx, len, (LocalVariable[]) null, cpool);
final int localVariableTypeTableLength = input.readUnsignedShort();
localVariableTypeTable = new LocalVariable[localVariableTypeTableLength];
for (int i = 0; i < localVariableTypeTableLength; i++) {
localVariableTypeTable[i] = new LocalVariable(input, cpool);
}
}
public LocalVariableTypeTable(final int nameIndex, final int length, final LocalVariable[] localVariableTypeTable, final ConstantPool constantPool) {
super(Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE, nameIndex, length, constantPool);
this.localVariableTypeTable = localVariableTypeTable != null ? localVariableTypeTable : LocalVariable.EMPTY_ARRAY;
Args.requireU2(this.localVariableTypeTable.length, "localVariableTypeTable.length");
}
public LocalVariableTypeTable(final LocalVariableTypeTable c) {
this(c.getNameIndex(), c.getLength(), c.getLocalVariableTypeTable(), c.getConstantPool());
}
@Override
public void accept(final Visitor v) {
v.visitLocalVariableTypeTable(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final LocalVariableTypeTable c = (LocalVariableTypeTable) clone();
c.localVariableTypeTable = new LocalVariable[localVariableTypeTable.length];
Arrays.setAll(c.localVariableTypeTable, i -> localVariableTypeTable[i].copy());
c.setConstantPool(constantPool);
return c;
}
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(localVariableTypeTable.length);
for (final LocalVariable variable : localVariableTypeTable) {
variable.dump(file);
}
}
public final LocalVariable getLocalVariable(final int index) {
for (final LocalVariable variable : localVariableTypeTable) {
if (variable.getIndex() == index) {
return variable;
}
}
return null;
}
public final LocalVariable[] getLocalVariableTypeTable() {
return localVariableTypeTable;
}
public final int getTableLength() {
return localVariableTypeTable == null ? 0 : localVariableTypeTable.length;
}
@Override
public Iterator<LocalVariable> iterator() {
return Stream.of(localVariableTypeTable).iterator();
}
public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
this.localVariableTypeTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY;
}
/**
* @return String representation.
*/
@Override
public final String toString() {
final StringBuilder buf = new StringBuilder();
for (int i = 0; i < localVariableTypeTable.length; i++) {
buf.append(localVariableTypeTable[i].toStringShared(true));
if (i < localVariableTypeTable.length - 1) {
buf.append('\n');
}
}
return buf.toString();
}
}

View file

@ -0,0 +1,266 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.IOException;
import java.util.Objects;
import com.sun.org.apache.bcel.internal.generic.Type;
import com.sun.org.apache.bcel.internal.util.BCELComparator;
/**
* This class represents the method info structure, i.e., the representation for a method in the class. See JVM
* specification for details. A method has access flags, a name, a signature and a number of attributes.
*/
public final class Method extends FieldOrMethod {
/**
* Empty array constant.
*
* @since 6.6.0
*/
public static final Method[] EMPTY_ARRAY = {};
private static BCELComparator<Method> bcelComparator = new BCELComparator<Method>() {
@Override
public boolean equals(final Method a, final Method b) {
return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature());
}
@Override
public int hashCode(final Method o) {
return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
}
};
/**
* @return Comparison strategy object.
*/
public static BCELComparator<Method> getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object.
*/
public static void setComparator(final BCELComparator<Method> comparator) {
bcelComparator = comparator;
}
/** Annotations defined on the parameters of a method. */
private ParameterAnnotationEntry[] parameterAnnotationEntries;
/**
* Empty constructor, all attributes have to be defined via 'setXXX' methods. Use at your own risk.
*/
public Method() {
}
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
Method(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
super(file, constantPool);
}
/**
* @param accessFlags Access rights of method
* @param nameIndex Points to field name in constant pool
* @param signatureIndex Points to encoded signature
* @param attributes Collection of attributes
* @param constantPool Array of constants
*/
public Method(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, final ConstantPool constantPool) {
super(accessFlags, nameIndex, signatureIndex, attributes, constantPool);
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public Method(final Method c) {
super(c);
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitMethod(this);
}
/**
* @return deep copy of this method
*/
public Method copy(final ConstantPool constantPool) {
return (Method) copy_(constantPool);
}
/**
* Return value as defined by given BCELComparator strategy. By default two method objects are said to be equal when
* their names and signatures are equal.
*
* @see Object#equals(Object)
*/
@Override
public boolean equals(final Object obj) {
return obj instanceof Method && bcelComparator.equals(this, (Method) obj);
}
/**
* @return array of method argument types
*/
public Type[] getArgumentTypes() {
return Type.getArgumentTypes(getSignature());
}
/**
* @return Code attribute of method, if any
*/
public Code getCode() {
for (final Attribute attribute : super.getAttributes()) {
if (attribute instanceof Code) {
return (Code) attribute;
}
}
return null;
}
/**
* @return ExceptionTable attribute of method, if any, i.e., list all exceptions the method may throw not exception
* handlers!
*/
public ExceptionTable getExceptionTable() {
for (final Attribute attribute : super.getAttributes()) {
if (attribute instanceof ExceptionTable) {
return (ExceptionTable) attribute;
}
}
return null;
}
/**
* @return LineNumberTable of code attribute if any, i.e. the call is forwarded to the Code atribute.
*/
public LineNumberTable getLineNumberTable() {
final Code code = getCode();
if (code == null) {
return null;
}
return code.getLineNumberTable();
}
/**
* @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code attribute.
*/
public LocalVariableTable getLocalVariableTable() {
final Code code = getCode();
if (code == null) {
return null;
}
return code.getLocalVariableTable();
}
/**
* Gets the local variable type table attribute {@link LocalVariableTypeTable}.
* @return LocalVariableTypeTable of code attribute if any, i.e. the call is forwarded to the Code attribute.
* @since 6.10.0
*/
public LocalVariableTypeTable getLocalVariableTypeTable() {
final Code code = getCode();
if (code == null) {
return null;
}
return code.getLocalVariableTypeTable();
}
/**
* @return Annotations on the parameters of a method
* @since 6.0
*/
public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
if (parameterAnnotationEntries == null) {
parameterAnnotationEntries = ParameterAnnotationEntry.createParameterAnnotationEntries(getAttributes());
}
return parameterAnnotationEntries;
}
/**
* @return return type of method
*/
public Type getReturnType() {
return Type.getReturnType(getSignature());
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR
* signature.
*
* @see Object#hashCode()
*/
@Override
public int hashCode() {
return bcelComparator.hashCode(this);
}
/**
* Return string representation close to declaration format, 'public static void main(String[] args) throws
* IOException', e.g.
*
* @return String representation of the method.
*/
@Override
public String toString() {
final String access = Utility.accessToString(super.getAccessFlags());
// Get name and signature from constant pool
ConstantUtf8 c = super.getConstantPool().getConstantUtf8(super.getSignatureIndex());
String signature = c.getBytes();
c = super.getConstantPool().getConstantUtf8(super.getNameIndex());
final String name = c.getBytes();
signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable());
final StringBuilder buf = new StringBuilder(signature);
for (final Attribute attribute : super.getAttributes()) {
if (!(attribute instanceof Code || attribute instanceof ExceptionTable)) {
buf.append(" [").append(attribute).append("]");
}
}
final ExceptionTable e = getExceptionTable();
if (e != null) {
final String str = e.toString();
if (!str.isEmpty()) {
buf.append("\n\t\tthrows ").append(str);
}
}
return buf.toString();
}
}

View file

@ -0,0 +1,131 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Entry of the parameters table.
* <p>
* Implements {@link Node} as of 6.7.0.
* </p>
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24"> The class File Format :
* The MethodParameters Attribute</a>
* @since 6.0
*/
public class MethodParameter implements Cloneable, Node {
/** Index of the CONSTANT_Utf8_info structure in the constant_pool table representing the name of the parameter */
private int nameIndex;
/** The access flags */
private int accessFlags;
public MethodParameter() {
}
/**
* Constructs an instance from a DataInput.
*
* @param input Input stream
* @throws IOException if an I/O error occurs.
* @throws ClassFormatException if a class is malformed or cannot be interpreted as a class file
*/
MethodParameter(final DataInput input) throws IOException {
nameIndex = input.readUnsignedShort();
accessFlags = input.readUnsignedShort();
}
@Override
public void accept(final Visitor v) {
v.visitMethodParameter(this);
}
/**
* @return deep copy of this object
*/
public MethodParameter copy() {
try {
return (MethodParameter) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dumps object to file stream on binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public final void dump(final DataOutputStream file) throws IOException {
file.writeShort(nameIndex);
file.writeShort(accessFlags);
}
public int getAccessFlags() {
return accessFlags;
}
public int getNameIndex() {
return nameIndex;
}
/**
* Gets the name of the parameter.
*
* @param constantPool The pool to query.
* @return Constant from the given pool.
*/
public String getParameterName(final ConstantPool constantPool) {
if (nameIndex == 0) {
return null;
}
return constantPool.getConstantUtf8(nameIndex).getBytes();
}
public boolean isFinal() {
return (accessFlags & Const.ACC_FINAL) != 0;
}
public boolean isMandated() {
return (accessFlags & Const.ACC_MANDATED) != 0;
}
public boolean isSynthetic() {
return (accessFlags & Const.ACC_SYNTHETIC) != 0;
}
public void setAccessFlags(final int accessFlags) {
this.accessFlags = accessFlags;
}
public void setNameIndex(final int nameIndex) {
this.nameIndex = nameIndex;
}
}

View file

@ -0,0 +1,99 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.stream.Stream;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a MethodParameters attribute.
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24"> The class File Format :
* The MethodParameters Attribute</a>
* @since 6.0
*/
public class MethodParameters extends Attribute implements Iterable<MethodParameter> {
/**
* Empty array.
*/
private static final MethodParameter[] EMPTY_ARRAY = {};
private MethodParameter[] parameters = EMPTY_ARRAY;
MethodParameters(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
super(Const.ATTR_METHOD_PARAMETERS, nameIndex, length, constantPool);
final int parameterCount = input.readUnsignedByte();
parameters = new MethodParameter[parameterCount];
for (int i = 0; i < parameterCount; i++) {
parameters[i] = new MethodParameter(input);
}
}
@Override
public void accept(final Visitor v) {
v.visitMethodParameters(this);
}
@Override
public Attribute copy(final ConstantPool constantPool) {
final MethodParameters c = (MethodParameters) clone();
c.parameters = new MethodParameter[parameters.length];
Arrays.setAll(c.parameters, i -> parameters[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump method parameters attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeByte(parameters.length);
for (final MethodParameter parameter : parameters) {
parameter.dump(file);
}
}
public MethodParameter[] getParameters() {
return parameters;
}
@Override
public Iterator<MethodParameter> iterator() {
return Stream.of(parameters).iterator();
}
public void setParameters(final MethodParameter[] parameters) {
this.parameters = parameters != null ? parameters : EMPTY_ARRAY;
}
}

View file

@ -0,0 +1,304 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from <em>Attribute</em> and represents the list of modules required, exported, opened or
* provided by a module. There may be at most one Module attribute in a ClassFile structure.
*
* @see Attribute
* @since 6.4.0
*/
public final class Module extends Attribute {
/**
* The module file name extension.
*
* @since 6.7.0
*/
public static final String EXTENSION = ".jmod";
private static String getClassNameAtIndex(final ConstantPool cp, final int index, final boolean compactClassName) {
final String className = cp.getConstantString(index, Const.CONSTANT_Class);
if (compactClassName) {
return Utility.compactClassName(className, false);
}
return className;
}
private final int moduleNameIndex;
private final int moduleFlags;
private final int moduleVersionIndex;
private ModuleRequires[] requiresTable;
private ModuleExports[] exportsTable;
private ModuleOpens[] opensTable;
private final int usesCount;
private final int[] usesIndex;
private ModuleProvides[] providesTable;
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Module(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
super(Const.ATTR_MODULE, nameIndex, length, constantPool);
moduleNameIndex = input.readUnsignedShort();
moduleFlags = input.readUnsignedShort();
moduleVersionIndex = input.readUnsignedShort();
final int requiresCount = input.readUnsignedShort();
requiresTable = new ModuleRequires[requiresCount];
for (int i = 0; i < requiresCount; i++) {
requiresTable[i] = new ModuleRequires(input);
}
final int exportsCount = input.readUnsignedShort();
exportsTable = new ModuleExports[exportsCount];
for (int i = 0; i < exportsCount; i++) {
exportsTable[i] = new ModuleExports(input);
}
final int opensCount = input.readUnsignedShort();
opensTable = new ModuleOpens[opensCount];
for (int i = 0; i < opensCount; i++) {
opensTable[i] = new ModuleOpens(input);
}
usesCount = input.readUnsignedShort();
usesIndex = new int[usesCount];
for (int i = 0; i < usesCount; i++) {
usesIndex[i] = input.readUnsignedShort();
}
final int providesCount = input.readUnsignedShort();
providesTable = new ModuleProvides[providesCount];
for (int i = 0; i < providesCount; i++) {
providesTable[i] = new ModuleProvides(input);
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitModule(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final Module c = (Module) clone();
c.requiresTable = new ModuleRequires[requiresTable.length];
Arrays.setAll(c.requiresTable, i -> requiresTable[i].copy());
c.exportsTable = new ModuleExports[exportsTable.length];
Arrays.setAll(c.exportsTable, i -> exportsTable[i].copy());
c.opensTable = new ModuleOpens[opensTable.length];
Arrays.setAll(c.opensTable, i -> opensTable[i].copy());
c.providesTable = new ModuleProvides[providesTable.length];
Arrays.setAll(c.providesTable, i -> providesTable[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump Module attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(moduleNameIndex);
file.writeShort(moduleFlags);
file.writeShort(moduleVersionIndex);
file.writeShort(requiresTable.length);
for (final ModuleRequires entry : requiresTable) {
entry.dump(file);
}
file.writeShort(exportsTable.length);
for (final ModuleExports entry : exportsTable) {
entry.dump(file);
}
file.writeShort(opensTable.length);
for (final ModuleOpens entry : opensTable) {
entry.dump(file);
}
file.writeShort(usesIndex.length);
for (final int entry : usesIndex) {
file.writeShort(entry);
}
file.writeShort(providesTable.length);
for (final ModuleProvides entry : providesTable) {
entry.dump(file);
}
}
/**
* @return table of exported interfaces
* @see ModuleExports
*/
public ModuleExports[] getExportsTable() {
return exportsTable;
}
/**
* Gets flags for this module.
* @return module flags
* @since 6.10.0
*/
public int getModuleFlags() {
return moduleFlags;
}
/**
* Gets module name.
* @param cp Array of constants
* @return module name
* @since 6.10.0
*/
public String getModuleName(final ConstantPool cp) {
return cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module);
}
/**
* @return table of provided interfaces
* @see ModuleOpens
*/
public ModuleOpens[] getOpensTable() {
return opensTable;
}
/**
* @return table of provided interfaces
* @see ModuleProvides
*/
public ModuleProvides[] getProvidesTable() {
return providesTable;
}
/**
* @return table of required modules
* @see ModuleRequires
*/
public ModuleRequires[] getRequiresTable() {
return requiresTable;
}
/**
* Gets the array of class names for this module's uses.
* @param constantPool Array of constants usually obtained from the ClassFile object
* @param compactClassName false for original constant pool value, true to replace '/' with '.'
* @return array of used class names
* @since 6.10.0
*/
public String[] getUsedClassNames(final ConstantPool constantPool, final boolean compactClassName) {
final String[] usedClassNames = new String[usesCount];
for (int i = 0; i < usesCount; i++) {
usedClassNames[i] = getClassNameAtIndex(constantPool, usesIndex[i], compactClassName);
}
return usedClassNames;
}
/**
* Gets version for this module.
* @param cp Array of constants
* @return version from constant pool, "0" if version index is 0
* @since 6.10.0
*/
public String getVersion(final ConstantPool cp) {
return moduleVersionIndex == 0 ? "0" : cp.getConstantString(moduleVersionIndex, Const.CONSTANT_Utf8);
}
/**
* @return String representation, i.e., a list of packages.
*/
@Override
public String toString() {
final ConstantPool cp = super.getConstantPool();
final StringBuilder buf = new StringBuilder();
buf.append("Module:\n");
buf.append(" name: ").append(Utility.pathToPackage(getModuleName(cp))).append("\n");
buf.append(" flags: ").append(String.format("%04x", moduleFlags)).append("\n");
final String version = getVersion(cp);
buf.append(" version: ").append(version).append("\n");
buf.append(" requires(").append(requiresTable.length).append("):\n");
for (final ModuleRequires module : requiresTable) {
buf.append(" ").append(module.toString(cp)).append("\n");
}
buf.append(" exports(").append(exportsTable.length).append("):\n");
for (final ModuleExports module : exportsTable) {
buf.append(" ").append(module.toString(cp)).append("\n");
}
buf.append(" opens(").append(opensTable.length).append("):\n");
for (final ModuleOpens module : opensTable) {
buf.append(" ").append(module.toString(cp)).append("\n");
}
buf.append(" uses(").append(usesIndex.length).append("):\n");
for (final int index : usesIndex) {
final String className = getClassNameAtIndex(cp, index, true);
buf.append(" ").append(className).append("\n");
}
buf.append(" provides(").append(providesTable.length).append("):\n");
for (final ModuleProvides module : providesTable) {
buf.append(" ").append(module.toString(cp)).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View file

@ -0,0 +1,158 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents an entry in the exports table of the Module attribute. Each entry describes a package which may
* open the parent module.
*
* @see Module
* @since 6.4.0
*/
public final class ModuleExports implements Cloneable, Node {
private static String getToModuleNameAtIndex(final ConstantPool constantPool, final int index) {
return constantPool.getConstantString(index, Const.CONSTANT_Module);
}
private final int exportsIndex; // points to CONSTANT_Package_info
private final int exportsFlags;
private final int exportsToCount;
private final int[] exportsToIndex; // points to CONSTANT_Module_info
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort
*/
ModuleExports(final DataInput file) throws IOException {
exportsIndex = file.readUnsignedShort();
exportsFlags = file.readUnsignedShort();
exportsToCount = file.readUnsignedShort();
exportsToIndex = new int[exportsToCount];
for (int i = 0; i < exportsToCount; i++) {
exportsToIndex[i] = file.readUnsignedShort();
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitModuleExports(this);
}
/**
* @return deep copy of this object
*/
public ModuleExports copy() {
try {
return (ModuleExports) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(exportsIndex);
file.writeShort(exportsFlags);
file.writeShort(exportsToCount);
for (final int entry : exportsToIndex) {
file.writeShort(entry);
}
}
/**
* Gets the flags for this ModuleExports.
* @return the exportsFlags
* @since 6.10.0
*/
public int getExportsFlags() {
return exportsFlags;
}
/**
* Gets the exported package name.
* @param constantPool the constant pool from the ClassFile
* @return the exported package name
* @since 6.10.0
*/
public String getPackageName(final ConstantPool constantPool) {
return constantPool.constantToString(exportsIndex, Const.CONSTANT_Package);
}
/**
* Gets an array of module names for this ModuleExports.
* @param constantPool Array of constants usually obtained from the ClassFile object
* @return array of module names following 'exports to'
* @since 6.10.0
*/
public String[] getToModuleNames(final ConstantPool constantPool) {
final String[] toModuleNames = new String[exportsToCount];
for (int i = 0; i < exportsToCount; i++) {
toModuleNames[i] = getToModuleNameAtIndex(constantPool, exportsToIndex[i]);
}
return toModuleNames;
}
/**
* @return String representation
*/
@Override
public String toString() {
return "exports(" + exportsIndex + ", " + exportsFlags + ", " + exportsToCount + ", ...)";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String packageName = getPackageName(constantPool);
buf.append(packageName);
buf.append(", ").append(String.format("%04x", exportsFlags));
buf.append(", to(").append(exportsToCount).append("):\n");
for (final int index : exportsToIndex) {
final String moduleName = getToModuleNameAtIndex(constantPool, index);
buf.append(" ").append(moduleName).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View file

@ -0,0 +1,134 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and indicates the main class of a module. There may be at most one
* ModuleMainClass attribute in a ClassFile structure.
*
* @see Attribute
*/
public final class ModuleMainClass extends Attribute {
private int mainClassIndex;
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
ModuleMainClass(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, 0, constantPool);
mainClassIndex = input.readUnsignedShort();
}
/**
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param mainClassIndex Host class index
* @param constantPool Array of constants
*/
public ModuleMainClass(final int nameIndex, final int length, final int mainClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);
this.mainClassIndex = Args.requireU2(mainClassIndex, "mainClassIndex");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public ModuleMainClass(final ModuleMainClass c) {
this(c.getNameIndex(), c.getLength(), c.getHostClassIndex(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. I.e.,
* the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitModuleMainClass(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final ModuleMainClass c = (ModuleMainClass) clone();
c.setConstantPool(constantPool);
return c;
}
/**
* Dump ModuleMainClass attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(mainClassIndex);
}
/**
* @return index into constant pool of host class name.
*/
public int getHostClassIndex() {
return mainClassIndex;
}
/**
* @param mainClassIndex the host class index
*/
public void setHostClassIndex(final int mainClassIndex) {
this.mainClassIndex = mainClassIndex;
}
/**
* @return String representation
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("ModuleMainClass: ");
final String className = super.getConstantPool().getConstantString(mainClassIndex, Const.CONSTANT_Class);
buf.append(Utility.compactClassName(className, false));
return buf.toString();
}
}

View file

@ -0,0 +1,158 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents an entry in the opens table of the Module attribute. Each entry describes a package which the
* parent module opens.
*
* @see Module
* @since 6.4.0
*/
public final class ModuleOpens implements Cloneable, Node {
private static String getToModuleNameAtIndex(final ConstantPool constantPool, final int index) {
return constantPool.getConstantString(index, Const.CONSTANT_Module);
}
private final int opensIndex; // points to CONSTANT_Package_info
private final int opensFlags;
private final int opensToCount;
private final int[] opensToIndex; // points to CONSTANT_Module_info
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort
*/
ModuleOpens(final DataInput file) throws IOException {
opensIndex = file.readUnsignedShort();
opensFlags = file.readUnsignedShort();
opensToCount = file.readUnsignedShort();
opensToIndex = new int[opensToCount];
for (int i = 0; i < opensToCount; i++) {
opensToIndex[i] = file.readUnsignedShort();
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitModuleOpens(this);
}
/**
* @return deep copy of this object
*/
public ModuleOpens copy() {
try {
return (ModuleOpens) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(opensIndex);
file.writeShort(opensFlags);
file.writeShort(opensToCount);
for (final int entry : opensToIndex) {
file.writeShort(entry);
}
}
/**
* Gets the flags for this ModuleOpens.
* @return the opensFlags
* @since 6.10.0
*/
public int getOpensFlags() {
return opensFlags;
}
/**
* Gets the opened package name.
* @param constantPool the constant pool from the ClassFile
* @return the opened package name
* @since 6.10.0
*/
public String getPackageName(final ConstantPool constantPool) {
return constantPool.constantToString(opensIndex, Const.CONSTANT_Package);
}
/**
* Gets an array of module names for this ModuleOpens.
* @param constantPool Array of constants usually obtained from the ClassFile object
* @return array of module names following 'opens to'
* @since 6.10.0
*/
public String[] getToModuleNames(final ConstantPool constantPool) {
final String[] toModuleNames = new String[opensToCount];
for (int i = 0; i < opensToCount; i++) {
toModuleNames[i] = getToModuleNameAtIndex(constantPool, opensToIndex[i]);
}
return toModuleNames;
}
/**
* @return String representation
*/
@Override
public String toString() {
return "opens(" + opensIndex + ", " + opensFlags + ", " + opensToCount + ", ...)";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String packageName = getPackageName(constantPool);
buf.append(packageName);
buf.append(", ").append(String.format("%04x", opensFlags));
buf.append(", to(").append(opensToCount).append("):\n");
for (final int index : opensToIndex) {
final String moduleName = getToModuleNameAtIndex(constantPool, index);
buf.append(" ").append(moduleName).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View file

@ -0,0 +1,167 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
import jdk.xml.internal.Utils;
/**
* This class is derived from <em>Attribute</em> and represents the list of packages that are exported or opened by the
* Module attribute. There may be at most one ModulePackages attribute in a ClassFile structure.
*
* @see Attribute
* @LastModified: Sept 2025
*/
public final class ModulePackages extends Attribute {
private int[] packageIndexTable;
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
ModulePackages(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (int[]) null, constantPool);
final int packageCount = input.readUnsignedShort();
packageIndexTable = new int[packageCount];
for (int i = 0; i < packageCount; i++) {
packageIndexTable[i] = input.readUnsignedShort();
}
}
/**
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param packageIndexTable Table of indices in constant pool
* @param constantPool Array of constants
*/
public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) {
super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool);
this.packageIndexTable = Utils.createEmptyArrayIfNull(packageIndexTable);
Args.requireU2(this.packageIndexTable.length, "packageIndexTable.length");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public ModulePackages(final ModulePackages c) {
this(c.getNameIndex(), c.getLength(), c.getPackageIndexTable(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitModulePackages(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final ModulePackages c = (ModulePackages) clone();
if (packageIndexTable != null) {
c.packageIndexTable = packageIndexTable.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump ModulePackages attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(packageIndexTable.length);
for (final int index : packageIndexTable) {
file.writeShort(index);
}
}
/**
* @return Length of package table.
*/
public int getNumberOfPackages() {
return packageIndexTable == null ? 0 : packageIndexTable.length;
}
/**
* @return array of indices into constant pool of package names.
*/
public int[] getPackageIndexTable() {
return packageIndexTable;
}
/**
* @return string array of package names
*/
public String[] getPackageNames() {
final String[] names = new String[packageIndexTable.length];
Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(packageIndexTable[i], Const.CONSTANT_Package)));
return names;
}
/**
* @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length.
*/
public void setPackageIndexTable(final int[] packageIndexTable) {
this.packageIndexTable = Utils.createEmptyArrayIfNull(packageIndexTable);
}
/**
* @return String representation, i.e., a list of packages.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("ModulePackages(");
buf.append(packageIndexTable.length);
buf.append("):\n");
for (final int index : packageIndexTable) {
final String packageName = super.getConstantPool().getConstantString(index, Const.CONSTANT_Package);
buf.append(" ").append(Utility.compactClassName(packageName, false)).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View file

@ -0,0 +1,150 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents an entry in the provides table of the Module attribute. Each entry describes a service
* implementation that the parent module provides.
*
* @see Module
* @since 6.4.0
*/
public final class ModuleProvides implements Cloneable, Node {
private static String getImplementationClassNameAtIndex(final ConstantPool constantPool, final int index, final boolean compactClassName) {
final String className = constantPool.getConstantString(index, Const.CONSTANT_Class);
if (compactClassName) {
return Utility.compactClassName(className, false);
}
return className;
}
private final int providesIndex; // points to CONSTANT_Class_info
private final int providesWithCount;
private final int[] providesWithIndex; // points to CONSTANT_Class_info
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort
*/
ModuleProvides(final DataInput file) throws IOException {
providesIndex = file.readUnsignedShort();
providesWithCount = file.readUnsignedShort();
providesWithIndex = new int[providesWithCount];
for (int i = 0; i < providesWithCount; i++) {
providesWithIndex[i] = file.readUnsignedShort();
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitModuleProvides(this);
}
/**
* @return deep copy of this object
*/
public ModuleProvides copy() {
try {
return (ModuleProvides) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(providesIndex);
file.writeShort(providesWithCount);
for (final int entry : providesWithIndex) {
file.writeShort(entry);
}
}
/**
* Gets the array of implementation class names for this ModuleProvides.
* @param constantPool Array of constants usually obtained from the ClassFile object
* @param compactClassName false for original constant pool value, true to replace '/' with '.'
* @return array of implementation class names
* @since 6.10.0
*/
public String[] getImplementationClassNames(final ConstantPool constantPool, final boolean compactClassName) {
final String[] implementationClassNames = new String[providesWithCount];
for (int i = 0; i < providesWithCount; i++) {
implementationClassNames[i] = getImplementationClassNameAtIndex(constantPool, providesWithIndex[i], compactClassName);
}
return implementationClassNames;
}
/**
* Gets the interface name for this ModuleProvides.
* @param constantPool Array of constants usually obtained from the ClassFile object
* @return interface name
* @since 6.10.0
*/
public String getInterfaceName(final ConstantPool constantPool) {
return constantPool.constantToString(providesIndex, Const.CONSTANT_Class);
}
/**
* @return String representation
*/
@Override
public String toString() {
return "provides(" + providesIndex + ", " + providesWithCount + ", ...)";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String interfaceName = getInterfaceName(constantPool);
buf.append(interfaceName);
buf.append(", with(").append(providesWithCount).append("):\n");
for (final int index : providesWithIndex) {
final String className = getImplementationClassNameAtIndex(constantPool, index, true);
buf.append(" ").append(className).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View file

@ -0,0 +1,139 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents an entry in the requires table of the Module attribute. Each entry describes a module on which
* the parent module depends.
*
* @see Module
* @since 6.4.0
*/
public final class ModuleRequires implements Cloneable, Node {
private final int requiresIndex; // points to CONSTANT_Module_info
private final int requiresFlags;
private final int requiresVersionIndex; // either 0 or points to CONSTANT_Utf8_info
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort
*/
ModuleRequires(final DataInput file) throws IOException {
requiresIndex = file.readUnsignedShort();
requiresFlags = file.readUnsignedShort();
requiresVersionIndex = file.readUnsignedShort();
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitModuleRequires(this);
}
/**
* @return deep copy of this object
*/
public ModuleRequires copy() {
try {
return (ModuleRequires) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dump table entry to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O Exception occurs in writeShort
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(requiresIndex);
file.writeShort(requiresFlags);
file.writeShort(requiresVersionIndex);
}
/**
* Gets the module name from the constant pool.
* @param constantPool Array of constants usually obtained from the ClassFile object
* @return module name
* @since 6.10.0
*/
public String getModuleName(final ConstantPool constantPool) {
return constantPool.constantToString(requiresIndex, Const.CONSTANT_Module);
}
/**
* Gets the flags for this ModuleRequires.
* @return the requiresFlags
* @since 6.10.0
*/
public int getRequiresFlags() {
return requiresFlags;
}
/**
* Gets the required version from the constant pool.
* @param constantPool Array of constants usually obtained from the ClassFile object
* @return required version, "0" if version index is 0.
* @since 6.10.0
*/
public String getVersion(final ConstantPool constantPool) {
return requiresVersionIndex == 0 ? "0" : constantPool.getConstantString(requiresVersionIndex, Const.CONSTANT_Utf8);
}
/**
* @return String representation
*/
@Override
public String toString() {
return "requires(" + requiresIndex + ", " + String.format("%04x", requiresFlags) + ", " + requiresVersionIndex + ")";
}
/**
* @return Resolved string representation
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String moduleName = getModuleName(constantPool);
buf.append(moduleName);
buf.append(", ").append(String.format("%04x", requiresFlags));
final String version = getVersion(constantPool);
buf.append(", ").append(version);
return buf.toString();
}
}

View file

@ -0,0 +1,134 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and records the nest host of the nest to which the current class or
* interface claims to belong. There may be at most one NestHost attribute in a ClassFile structure.
*
* @see Attribute
*/
public final class NestHost extends Attribute {
private int hostClassIndex;
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
NestHost(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, 0, constantPool);
hostClassIndex = input.readUnsignedShort();
}
/**
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param hostClassIndex Host class index
* @param constantPool Array of constants
*/
public NestHost(final int nameIndex, final int length, final int hostClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);
this.hostClassIndex = Args.requireU2(hostClassIndex, "hostClassIndex");
}
/**
* Initializes from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public NestHost(final NestHost c) {
this(c.getNameIndex(), c.getLength(), c.getHostClassIndex(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitNestHost(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final NestHost c = (NestHost) clone();
c.setConstantPool(constantPool);
return c;
}
/**
* Dumps NestHost attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(hostClassIndex);
}
/**
* @return index into constant pool of host class name.
*/
public int getHostClassIndex() {
return hostClassIndex;
}
/**
* @param hostClassIndex the host class index
*/
public void setHostClassIndex(final int hostClassIndex) {
this.hostClassIndex = hostClassIndex;
}
/**
* @return String representation
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("NestHost: ");
final String className = super.getConstantPool().getConstantString(hostClassIndex, Const.CONSTANT_Class);
buf.append(Utility.compactClassName(className, false));
return buf.toString();
}
}

View file

@ -0,0 +1,168 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
import jdk.xml.internal.Utils;
/**
* This class is derived from <em>Attribute</em> and records the classes and interfaces that are authorized to claim
* membership in the nest hosted by the current class or interface. There may be at most one NestMembers attribute in a
* ClassFile structure.
*
* @see Attribute
* @LastModified: Sept 2025
*/
public final class NestMembers extends Attribute {
private int[] classes;
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
NestMembers(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (int[]) null, constantPool);
final int classCount = input.readUnsignedShort();
classes = new int[classCount];
for (int i = 0; i < classCount; i++) {
classes[i] = input.readUnsignedShort();
}
}
/**
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param classes Table of indices in constant pool
* @param constantPool Array of constants
*/
public NestMembers(final int nameIndex, final int length, final int[] classes, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);
this.classes = Utils.createEmptyArrayIfNull(classes);
Args.requireU2(this.classes.length, "classes.length");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public NestMembers(final NestMembers c) {
this(c.getNameIndex(), c.getLength(), c.getClasses(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitNestMembers(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final NestMembers c = (NestMembers) clone();
if (classes.length > 0) {
c.classes = classes.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump NestMembers attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(classes.length);
for (final int index : classes) {
file.writeShort(index);
}
}
/**
* @return array of indices into constant pool of class names.
*/
public int[] getClasses() {
return classes;
}
/**
* @return string array of class names
*/
public String[] getClassNames() {
final String[] names = new String[classes.length];
Arrays.setAll(names, i -> Utility.pathToPackage(super.getConstantPool().getConstantString(classes[i], Const.CONSTANT_Class)));
return names;
}
/**
* @return Length of classes table.
*/
public int getNumberClasses() {
return classes.length;
}
/**
* @param classes the list of class indexes Also redefines number_of_classes according to table length.
*/
public void setClasses(final int[] classes) {
this.classes = Utils.createEmptyArrayIfNull(classes);
}
/**
* @return String representation, i.e., a list of classes.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("NestMembers(");
buf.append(classes.length);
buf.append("):\n");
for (final int index : classes) {
final String className = super.getConstantPool().getConstantString(index, Const.CONSTANT_Class);
buf.append(" ").append(Utility.compactClassName(className, false)).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View file

@ -0,0 +1,30 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
/**
* Denote class to have an accept method();
*/
public interface Node {
void accept(Visitor visitor);
}

View file

@ -0,0 +1,157 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class is derived from <em>Attribute</em> and represents a reference to a PMG attribute.
*
* @see Attribute
*/
public final class PMGClass extends Attribute {
private int pmgClassIndex;
private int pmgIndex;
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
PMGClass(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, input.readUnsignedShort(), input.readUnsignedShort(), constantPool);
}
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param pmgIndex index in constant pool for source file name
* @param pmgClassIndex Index in constant pool to CONSTANT_Utf8
* @param constantPool Array of constants
*/
public PMGClass(final int nameIndex, final int length, final int pmgIndex, final int pmgClassIndex, final ConstantPool constantPool) {
super(Const.ATTR_PMG, nameIndex, length, constantPool);
this.pmgIndex = pmgIndex;
this.pmgClassIndex = pmgClassIndex;
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param pgmClass Source to copy.
*/
public PMGClass(final PMGClass pgmClass) {
this(pgmClass.getNameIndex(), pgmClass.getLength(), pgmClass.getPMGIndex(), pgmClass.getPMGClassIndex(), pgmClass.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
println("Visiting non-standard PMGClass object");
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(pmgIndex);
file.writeShort(pmgClassIndex);
}
/**
* @return Index in constant pool of source file name.
*/
public int getPMGClassIndex() {
return pmgClassIndex;
}
/**
* @return PMG class name.
*/
public String getPMGClassName() {
return super.getConstantPool().getConstantUtf8(pmgClassIndex).getBytes();
}
/**
* @return Index in constant pool of source file name.
*/
public int getPMGIndex() {
return pmgIndex;
}
/**
* @return PMG name.
*/
public String getPMGName() {
return super.getConstantPool().getConstantUtf8(pmgIndex).getBytes();
}
/**
* @param pmgClassIndex
*/
public void setPMGClassIndex(final int pmgClassIndex) {
this.pmgClassIndex = pmgClassIndex;
}
/**
* @param pmgIndex
*/
public void setPMGIndex(final int pmgIndex) {
this.pmgIndex = pmgIndex;
}
/**
* @return String representation
*/
@Override
public String toString() {
return "PMGClass(" + getPMGName() + ", " + getPMGClassName() + ")";
}
}

View file

@ -0,0 +1,99 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* represents one parameter annotation in the parameter annotation table
*
* @since 6.0
*/
public class ParameterAnnotationEntry implements Node {
static final ParameterAnnotationEntry[] EMPTY_ARRAY = {};
public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attributes) {
if (attributes == null) {
return EMPTY_ARRAY;
}
// Find attributes that contain parameter annotation data
final List<ParameterAnnotationEntry> accumulatedAnnotations = new ArrayList<>(attributes.length);
for (final Attribute attribute : attributes) {
if (attribute instanceof ParameterAnnotations) {
final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute;
final ParameterAnnotationEntry[] parameterAnnotationEntries = runtimeAnnotations.getParameterAnnotationEntries();
if (parameterAnnotationEntries != null) {
Collections.addAll(accumulatedAnnotations, parameterAnnotationEntries);
}
}
}
return accumulatedAnnotations.toArray(EMPTY_ARRAY);
}
private final AnnotationEntry[] annotationTable;
/**
* Constructs object from input stream.
*
* @param input Input stream
* @throws IOException if an I/O error occurs.
*/
ParameterAnnotationEntry(final DataInput input, final ConstantPool constantPool) throws IOException {
final int annotationTableLength = input.readUnsignedShort();
annotationTable = new AnnotationEntry[annotationTableLength];
for (int i = 0; i < annotationTableLength; i++) {
// TODO isRuntimeVisible
annotationTable[i] = AnnotationEntry.read(input, constantPool, false);
}
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitParameterAnnotationEntry(this);
}
public void dump(final DataOutputStream dos) throws IOException {
dos.writeShort(annotationTable.length);
for (final AnnotationEntry entry : annotationTable) {
entry.dump(dos);
}
}
/**
* returns the array of annotation entries in this annotation
*/
public AnnotationEntry[] getAnnotationEntries() {
return annotationTable;
}
}

View file

@ -0,0 +1,131 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.stream.Stream;
/**
* base class for parameter annotations
*
* @since 6.0
*/
public abstract class ParameterAnnotations extends Attribute implements Iterable<ParameterAnnotationEntry> {
private static final ParameterAnnotationEntry[] EMPTY_ARRAY = {};
/** Table of parameter annotations */
private ParameterAnnotationEntry[] parameterAnnotationTable;
/**
* Constructs a new instance.
*
* @param parameterAnnotationType the subclass type of the parameter annotation
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
*/
ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException {
this(parameterAnnotationType, nameIndex, length, (ParameterAnnotationEntry[]) null, constantPool);
final int numParameters = input.readUnsignedByte();
parameterAnnotationTable = new ParameterAnnotationEntry[numParameters];
for (int i = 0; i < numParameters; i++) {
parameterAnnotationTable[i] = new ParameterAnnotationEntry(input, constantPool);
}
}
/**
* Constructs a new instance.
*
* @param parameterAnnotationType the subclass type of the parameter annotation
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param parameterAnnotationTable the actual parameter annotations
* @param constantPool Array of constants
*/
public ParameterAnnotations(final byte parameterAnnotationType, final int nameIndex, final int length,
final ParameterAnnotationEntry[] parameterAnnotationTable, final ConstantPool constantPool) {
super(parameterAnnotationType, nameIndex, length, constantPool);
this.parameterAnnotationTable = parameterAnnotationTable;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitParameterAnnotation(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
dos.writeByte(parameterAnnotationTable.length);
for (final ParameterAnnotationEntry element : parameterAnnotationTable) {
element.dump(dos);
}
}
/**
* returns the array of parameter annotation entries in this parameter annotation
*/
public ParameterAnnotationEntry[] getParameterAnnotationEntries() {
return parameterAnnotationTable;
}
/**
* @return the parameter annotation entry table
*/
public final ParameterAnnotationEntry[] getParameterAnnotationTable() {
return parameterAnnotationTable;
}
@Override
public Iterator<ParameterAnnotationEntry> iterator() {
return Stream.of(parameterAnnotationTable).iterator();
}
/**
* @param parameterAnnotationTable the entries to set in this parameter annotation
*/
public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) {
this.parameterAnnotationTable = parameterAnnotationTable != null ? parameterAnnotationTable : EMPTY_ARRAY;
}
}

View file

@ -0,0 +1,153 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* Extends {@link Attribute} and records the classes and
* interfaces that are authorized to claim membership in the nest hosted by the
* current class or interface. There may be at most one Record attribute in a
* ClassFile structure.
*
* @see Attribute
* @since 6.9.0
*/
public final class Record extends Attribute {
private static final RecordComponentInfo[] EMPTY_RCI_ARRAY = {};
private static RecordComponentInfo[] readComponents(final DataInput input, final ConstantPool constantPool)
throws IOException {
final int classCount = input.readUnsignedShort();
final RecordComponentInfo[] components = new RecordComponentInfo[classCount];
for (int i = 0; i < classCount; i++) {
components[i] = new RecordComponentInfo(input, constantPool);
}
return components;
}
private RecordComponentInfo[] components;
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Record(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException {
this(nameIndex, length, readComponents(input, constantPool), constantPool);
}
/**
* Constructs a new instance using components.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param classes Array of Record Component Info elements
* @param constantPool Array of constants
*/
public Record(final int nameIndex, final int length, final RecordComponentInfo[] classes,
final ConstantPool constantPool) {
super(Const.ATTR_RECORD, nameIndex, length, constantPool);
this.components = classes != null ? classes : EMPTY_RCI_ARRAY;
Args.requireU2(this.components.length, "attributes.length");
}
/**
* Called by objects that are traversing the nodes of the tree implicitly
* defined by the contents of a Java class. For example, the hierarchy of methods,
* fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitRecord(this);
}
/**
* Copies this instance and its components.
*
* @return a deep copy of this instance and its components.
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final Record c = (Record) clone();
if (components.length > 0) {
c.components = components.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dumps this instance into a file stream in binary format.
*
* @param file output stream.
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(components.length);
for (final RecordComponentInfo component : components) {
component.dump(file);
}
}
/**
* Gets all the record components.
*
* @return array of Record Component Info elements.
*/
public RecordComponentInfo[] getComponents() {
return components;
}
/**
* Converts this instance to a String suitable for debugging.
*
* @return String a String suitable for debugging.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("Record(");
buf.append(components.length);
buf.append("):\n");
for (final RecordComponentInfo component : components) {
buf.append(" ").append(component.toString()).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View file

@ -0,0 +1,139 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Record component info from a record. Instances from this class maps
* every component from a given record.
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se14/preview/specs/records-jvms.html#jvms-4.7.30">
* The Java Virtual Machine Specification, Java SE 14 Edition, Records (preview)</a>
* @since 6.9.0
*/
public class RecordComponentInfo implements Node {
private final int index;
private final int descriptorIndex;
private final Attribute[] attributes;
private final ConstantPool constantPool;
/**
* Constructs a new instance from an input stream.
*
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
public RecordComponentInfo(final DataInput input, final ConstantPool constantPool) throws IOException {
this.index = input.readUnsignedShort();
this.descriptorIndex = input.readUnsignedShort();
final int attributesCount = input.readUnsignedShort();
this.attributes = new Attribute[attributesCount];
for (int j = 0; j < attributesCount; j++) {
attributes[j] = Attribute.readAttribute(input, constantPool);
}
this.constantPool = constantPool;
}
@Override
public void accept(final Visitor v) {
v.visitRecordComponent(this);
}
/**
* Dumps contents into a file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(index);
file.writeShort(descriptorIndex);
file.writeShort(attributes.length);
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
}
/**
* Gets all attributes.
*
* @return all attributes.
*/
public Attribute[] getAttributes() {
return attributes;
}
/**
* Gets the constant pool.
*
* @return Constant pool.
*/
public ConstantPool getConstantPool() {
return constantPool;
}
/**
* Gets the description index.
*
* @return index in constant pool of this record component descriptor.
*/
public int getDescriptorIndex() {
return descriptorIndex;
}
/**
* Gets the name index.
*
* @return index in constant pool of this record component name.
*/
public int getIndex() {
return index;
}
/**
* Converts this instance to a String suitable for debugging.
*
* @return a String suitable for debugging.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder();
buf.append("RecordComponentInfo(");
buf.append(constantPool.getConstantString(index, Const.CONSTANT_Utf8));
buf.append(",");
buf.append(constantPool.getConstantString(descriptorIndex, Const.CONSTANT_Utf8));
buf.append(",");
buf.append(attributes.length);
buf.append("):\n");
for (final Attribute attribute : attributes) {
buf.append(" ").append(attribute.toString()).append("\n");
}
return buf.substring(0, buf.length() - 1); // remove the last newline
}
}

View file

@ -0,0 +1,65 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* An annotation that is represented in the class file but is not provided to the JVM.
*
* @since 6.0
*/
public class RuntimeInvisibleAnnotations extends Annotations {
/**
* Constructs a new instance.
*
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeInvisibleAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
super(Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS, nameIndex, length, input, constantPool, false);
}
/**
* Creates a deep copy of this attribute.
*
* @return deep copy of this attribute.
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public final void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
writeAnnotations(dos);
}
}

View file

@ -0,0 +1,49 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Represents a parameter annotation that is represented in the class file but is not provided to the JVM.
*
* @since 6.0
*/
public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations {
/**
* Constructs a new instance.
*
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeInvisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException {
super(Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool);
}
}

View file

@ -0,0 +1,65 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* An annotation that is represented in the class file and is provided to the JVM.
*
* @since 6.0
*/
public class RuntimeVisibleAnnotations extends Annotations {
/**
* Constructs a new instance.
*
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeVisibleAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
super(Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS, nameIndex, length, input, constantPool, true);
}
/**
* Creates a deep copy of this attribute.
*
* @return deep copy of this attribute.
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
@Override
public final void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
writeAnnotations(dos);
}
}

View file

@ -0,0 +1,49 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* Represents a parameter annotation that is represented in the class file and is provided to the JVM.
*
* @since 6.0
*/
public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations {
/**
* Constructs a new instance.
*
* @param nameIndex Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException Thrown when an I/O exception of some sort has occurred.
*/
public RuntimeVisibleParameterAnnotations(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool)
throws IOException {
super(Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, nameIndex, length, input, constantPool);
}
}

View file

@ -0,0 +1,258 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and represents a reference to a GJ attribute.
*
* @see Attribute
*/
public final class Signature extends Attribute {
/**
* Extends ByteArrayInputStream to make 'unreading' chars possible.
*/
private static final class MyByteArrayInputStream extends ByteArrayInputStream {
MyByteArrayInputStream(final String data) {
super(data.getBytes(StandardCharsets.UTF_8));
}
String getData() {
return new String(buf, StandardCharsets.UTF_8);
}
void unread() {
if (pos > 0) {
pos--;
}
}
}
private static boolean identStart(final int ch) {
return ch == 'T' || ch == 'L';
}
// @since 6.0 is no longer final
public static boolean isActualParameterList(final String s) {
return s.startsWith("L") && s.endsWith(">;");
}
// @since 6.0 is no longer final
public static boolean isFormalParameterList(final String s) {
return s.startsWith("<") && s.indexOf(':') > 0;
}
private static void matchGJIdent(final MyByteArrayInputStream in, final StringBuilder buf) {
int ch;
matchIdent(in, buf);
ch = in.read();
if (ch == '<' || ch == '(') { // Parameterized or method
// System.out.println("Enter <");
buf.append((char) ch);
matchGJIdent(in, buf);
while ((ch = in.read()) != '>' && ch != ')') { // List of parameters
if (ch == -1) {
throw new IllegalArgumentException("Illegal signature: " + in.getData() + " reaching EOF");
}
// System.out.println("Still no >");
buf.append(", ");
in.unread();
matchGJIdent(in, buf); // Recursive call
}
// System.out.println("Exit >");
buf.append((char) ch);
} else {
in.unread();
}
ch = in.read();
if (identStart(ch)) {
in.unread();
matchGJIdent(in, buf);
} else if (ch == ')') {
in.unread();
} else if (ch != ';') {
throw new IllegalArgumentException("Illegal signature: " + in.getData() + " read " + (char) ch);
}
}
private static void matchIdent(final MyByteArrayInputStream in, final StringBuilder buf) {
int ch;
if ((ch = in.read()) == -1) {
throw new IllegalArgumentException("Illegal signature: " + in.getData() + " no ident, reaching EOF");
}
// System.out.println("return from ident:" + (char) ch);
if (!identStart(ch)) {
final StringBuilder buf2 = new StringBuilder();
int count = 1;
while (Character.isJavaIdentifierPart((char) ch)) {
buf2.append((char) ch);
count++;
ch = in.read();
}
if (ch == ':') { // Ok, formal parameter
final int skipExpected = "Ljava/lang/Object".length();
final long skipActual = in.skip(skipExpected);
if (skipActual != skipExpected) {
throw new IllegalStateException(String.format("Unexpected skip: expected=%,d, actual=%,d", skipExpected, skipActual));
}
buf.append(buf2);
ch = in.read();
in.unread();
// System.out.println("so far:" + buf2 + ":next:" +(char) ch);
} else {
for (int i = 0; i < count; i++) {
in.unread();
}
}
return;
}
final StringBuilder buf2 = new StringBuilder();
ch = in.read();
do {
buf2.append((char) ch);
ch = in.read();
// System.out.println("within ident:"+ (char) ch);
} while (ch != -1 && (Character.isJavaIdentifierPart((char) ch) || ch == '/'));
buf.append(Utility.pathToPackage(buf2.toString()));
// System.out.println("regular return ident:"+ (char) ch + ":" + buf2);
if (ch != -1) {
in.unread();
}
}
public static String translate(final String s) {
// System.out.println("Sig:" + s);
final StringBuilder buf = new StringBuilder();
matchGJIdent(new MyByteArrayInputStream(s), buf);
return buf.toString();
}
private int signatureIndex;
/**
* Constructs object from file stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Signature(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, input.readUnsignedShort(), constantPool);
}
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param signatureIndex Index in constant pool to CONSTANT_Utf8
* @param constantPool Array of constants
*/
public Signature(final int nameIndex, final int length, final int signatureIndex, final ConstantPool constantPool) {
super(Const.ATTR_SIGNATURE, nameIndex, Args.require(length, 2, "Signature length attribute"), constantPool);
this.signatureIndex = signatureIndex;
// validate:
Objects.requireNonNull(constantPool.getConstantUtf8(signatureIndex), "constantPool.getConstantUtf8(signatureIndex)");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public Signature(final Signature c) {
this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
// System.err.println("Visiting non-standard Signature object");
v.visitSignature(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(signatureIndex);
}
/**
* @return GJ signature.
*/
public String getSignature() {
return super.getConstantPool().getConstantUtf8(signatureIndex).getBytes();
}
/**
* @return Index in constant pool of source file name.
*/
public int getSignatureIndex() {
return signatureIndex;
}
/**
* @param signatureIndex the index info the constant pool of this signature
*/
public void setSignatureIndex(final int signatureIndex) {
this.signatureIndex = signatureIndex;
}
/**
* @return String representation
*/
@Override
public String toString() {
return "Signature: " + getSignature();
}
}

View file

@ -0,0 +1,183 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* @since 6.0
*/
public class SimpleElementValue extends ElementValue {
private int index;
public SimpleElementValue(final int type, final int index, final ConstantPool cpool) {
super(type, cpool);
this.index = index;
}
@Override
public void dump(final DataOutputStream dos) throws IOException {
final int type = super.getType();
dos.writeByte(type); // u1 kind of value
switch (type) {
case PRIMITIVE_INT:
case PRIMITIVE_BYTE:
case PRIMITIVE_CHAR:
case PRIMITIVE_FLOAT:
case PRIMITIVE_LONG:
case PRIMITIVE_BOOLEAN:
case PRIMITIVE_SHORT:
case PRIMITIVE_DOUBLE:
case STRING:
dos.writeShort(getIndex());
break;
default:
throw new ClassFormatException("SimpleElementValue doesn't know how to write out type " + type);
}
}
/**
* @return Value entry index in the cpool
*/
public int getIndex() {
return index;
}
public boolean getValueBoolean() {
if (super.getType() != PRIMITIVE_BOOLEAN) {
throw new IllegalStateException("Don't call getValueBoolean() on a non BOOLEAN ElementValue");
}
final ConstantInteger bo = (ConstantInteger) super.getConstantPool().getConstant(getIndex());
return bo.getBytes() != 0;
}
public byte getValueByte() {
if (super.getType() != PRIMITIVE_BYTE) {
throw new IllegalStateException("Don't call getValueByte() on a non BYTE ElementValue");
}
return (byte) super.getConstantPool().getConstantInteger(getIndex()).getBytes();
}
public char getValueChar() {
if (super.getType() != PRIMITIVE_CHAR) {
throw new IllegalStateException("Don't call getValueChar() on a non CHAR ElementValue");
}
return (char) super.getConstantPool().getConstantInteger(getIndex()).getBytes();
}
public double getValueDouble() {
if (super.getType() != PRIMITIVE_DOUBLE) {
throw new IllegalStateException("Don't call getValueDouble() on a non DOUBLE ElementValue");
}
final ConstantDouble d = (ConstantDouble) super.getConstantPool().getConstant(getIndex());
return d.getBytes();
}
public float getValueFloat() {
if (super.getType() != PRIMITIVE_FLOAT) {
throw new IllegalStateException("Don't call getValueFloat() on a non FLOAT ElementValue");
}
final ConstantFloat f = (ConstantFloat) super.getConstantPool().getConstant(getIndex());
return f.getBytes();
}
public int getValueInt() {
if (super.getType() != PRIMITIVE_INT) {
throw new IllegalStateException("Don't call getValueInt() on a non INT ElementValue");
}
return super.getConstantPool().getConstantInteger(getIndex()).getBytes();
}
public long getValueLong() {
if (super.getType() != PRIMITIVE_LONG) {
throw new IllegalStateException("Don't call getValueLong() on a non LONG ElementValue");
}
final ConstantLong j = (ConstantLong) super.getConstantPool().getConstant(getIndex());
return j.getBytes();
}
public short getValueShort() {
if (super.getType() != PRIMITIVE_SHORT) {
throw new IllegalStateException("Don't call getValueShort() on a non SHORT ElementValue");
}
final ConstantInteger s = (ConstantInteger) super.getConstantPool().getConstant(getIndex());
return (short) s.getBytes();
}
public String getValueString() {
if (super.getType() != STRING) {
throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue");
}
return super.getConstantPool().getConstantUtf8(getIndex()).getBytes();
}
public void setIndex(final int index) {
this.index = index;
}
// Whatever kind of value it is, return it as a string
@Override
public String stringifyValue() {
final ConstantPool cpool = super.getConstantPool();
final int type = super.getType();
switch (type) {
case PRIMITIVE_INT:
return Integer.toString(cpool.getConstantInteger(getIndex()).getBytes());
case PRIMITIVE_LONG:
final ConstantLong j = cpool.getConstant(getIndex(), Const.CONSTANT_Long, ConstantLong.class);
return Long.toString(j.getBytes());
case PRIMITIVE_DOUBLE:
final ConstantDouble d = cpool.getConstant(getIndex(), Const.CONSTANT_Double, ConstantDouble.class);
return Double.toString(d.getBytes());
case PRIMITIVE_FLOAT:
final ConstantFloat f = cpool.getConstant(getIndex(), Const.CONSTANT_Float, ConstantFloat.class);
return Float.toString(f.getBytes());
case PRIMITIVE_SHORT:
final ConstantInteger s = cpool.getConstantInteger(getIndex());
return Integer.toString(s.getBytes());
case PRIMITIVE_BYTE:
final ConstantInteger b = cpool.getConstantInteger(getIndex());
return Integer.toString(b.getBytes());
case PRIMITIVE_CHAR:
final ConstantInteger ch = cpool.getConstantInteger(getIndex());
return String.valueOf((char) ch.getBytes());
case PRIMITIVE_BOOLEAN:
final ConstantInteger bo = cpool.getConstantInteger(getIndex());
if (bo.getBytes() == 0) {
return "false";
}
return "true";
case STRING:
return cpool.getConstantUtf8(getIndex()).getBytes();
default:
throw new IllegalStateException("SimpleElementValue class does not know how to stringify type " + type);
}
}
@Override
public String toString() {
return stringifyValue();
}
}

View file

@ -0,0 +1,138 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and represents a reference to the source file of this class. At most
* one SourceFile attribute should appear per classfile. The intention of this class is that it is instantiated from the
* <em>Attribute.readAttribute()</em> method.
*
* @see Attribute
*/
public final class SourceFile extends Attribute {
private int sourceFileIndex;
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
SourceFile(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, input.readUnsignedShort(), constantPool);
}
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "SourceFile".
* @param length Content length in bytes, the value should be 2.
* @param constantPool The constant pool that this attribute is associated with.
* @param sourceFileIndex Index in constant pool to CONSTANT_Utf8. This string will be interpreted as the name of the
* file from which this class was compiled. It will not be interpreted as indicating the name of the directory
* contqining the file or an absolute path; this information has to be supplied the consumer of this attribute -
* in many cases, the JVM.
*/
public SourceFile(final int nameIndex, final int length, final int sourceFileIndex, final ConstantPool constantPool) {
super(Const.ATTR_SOURCE_FILE, nameIndex, Args.require(length, 2, "SourceFile length attribute"), constantPool);
this.sourceFileIndex = Args.requireU2(sourceFileIndex, 0, constantPool.getLength(), "SourceFile source file index");
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
* physical copy.
*
* @param c Source to copy.
*/
public SourceFile(final SourceFile c) {
this(c.getNameIndex(), c.getLength(), c.getSourceFileIndex(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitSourceFile(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
return (Attribute) clone();
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(sourceFileIndex);
}
/**
* @return Index in constant pool of source file name.
*/
public int getSourceFileIndex() {
return sourceFileIndex;
}
/**
* @return Source file name.
*/
public String getSourceFileName() {
return super.getConstantPool().getConstantUtf8(sourceFileIndex).getBytes();
}
/**
* @param sourceFileIndex
*/
public void setSourceFileIndex(final int sourceFileIndex) {
this.sourceFileIndex = sourceFileIndex;
}
/**
* @return String representation
*/
@Override
public String toString() {
return "SourceFile: " + getSourceFileName();
}
}

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class represents a stack map attribute used for preverification of Java classes for the
* <a href="https://java.sun.com/j2me/"> Java 2 Micro Edition</a> (J2ME). This attribute is used by the
* <a href="https://java.sun.com/products/cldc/">KVM</a> and contained within the Code attribute of a method. See CLDC
* specification 5.3.1.2
*
* <pre>
* StackMapTable_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 number_of_entries;
* stack_map_frame entries[number_of_entries];
* }
* </pre>
*
* @see Code
* @see StackMapEntry
* @see StackMapType
* @LastModified: Sept 2025
*/
public final class StackMap extends Attribute {
private StackMapEntry[] table; // Table of stack map entries
/**
* Constructs object from input stream.
*
* @param nameIndex Index of name
* @param length Content length in bytes
* @param dataInput Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
StackMap(final int nameIndex, final int length, final DataInput dataInput, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (StackMapEntry[]) null, constantPool);
final int mapLength = dataInput.readUnsignedShort();
table = new StackMapEntry[mapLength];
for (int i = 0; i < mapLength; i++) {
table[i] = new StackMapEntry(dataInput, constantPool);
}
}
/*
* @param nameIndex Index of name
*
* @param length Content length in bytes
*
* @param map Table of stack map entries
*
* @param constantPool Array of constants
*/
public StackMap(final int nameIndex, final int length, final StackMapEntry[] table, final ConstantPool constantPool) {
super(Const.ATTR_STACK_MAP, nameIndex, length, constantPool);
this.table = table != null ? table : StackMapEntry.EMPTY_ARRAY;
Args.requireU2(this.table.length, "table.length");
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitStackMap(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final StackMap c = (StackMap) clone();
c.table = new StackMapEntry[table.length];
Arrays.setAll(c.table, i -> table[i].copy());
c.setConstantPool(constantPool);
return c;
}
/**
* Dump stack map table attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
file.writeShort(table.length);
for (final StackMapEntry entry : table) {
entry.dump(file);
}
}
public int getMapLength() {
return table.length;
}
/**
* @return Array of stack map entries
*/
public StackMapEntry[] getStackMap() {
return table;
}
/**
* @param table Array of stack map entries
*/
public void setStackMap(final StackMapEntry[] table) {
this.table = table != null ? table : StackMapEntry.EMPTY_ARRAY;
int len = 2; // Length of 'number_of_entries' field prior to the array of stack maps
for (final StackMapEntry element : this.table) {
len += element.getMapEntrySize();
}
setLength(len);
}
/**
* @return String representation.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder("StackMap(");
int runningOffset = -1; // no +1 on first entry
for (int i = 0; i < table.length; i++) {
runningOffset = table[i].getByteCodeOffset() + runningOffset + 1;
buf.append(String.format("%n@%03d %s", runningOffset, table[i]));
if (i < table.length - 1) {
buf.append(", ");
}
}
buf.append(')');
return buf.toString();
}
}

View file

@ -0,0 +1,414 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a stack map entry recording the types of local variables and the of stack items at a given
* byte code offset. See CLDC specification 5.3.1.2.
*
* See also https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4
*
* <pre>
* union stack_map_frame {
* same_frame;
* same_locals_1_stack_item_frame;
* same_locals_1_stack_item_frame_extended;
* chop_frame;
* same_frame_extended;
* append_frame;
* full_frame;
* }
* </pre>
* @see StackMap
* @see StackMapType
*/
public final class StackMapEntry implements Node, Cloneable {
static final StackMapEntry[] EMPTY_ARRAY = {};
private int frameType;
private int byteCodeOffset;
private StackMapType[] typesOfLocals;
private StackMapType[] typesOfStackItems;
private ConstantPool constantPool;
/**
* Constructs object from input stream.
*
* @param dataInput Input stream
* @throws IOException if an I/O error occurs.
*/
StackMapEntry(final DataInput dataInput, final ConstantPool constantPool) throws IOException {
this(dataInput.readByte() & 0xFF, -1, null, null, constantPool);
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
byteCodeOffset = frameType - Const.SAME_FRAME;
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
byteCodeOffset = frameType - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
byteCodeOffset = dataInput.readUnsignedShort();
typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
} else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
byteCodeOffset = dataInput.readUnsignedShort();
} else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
byteCodeOffset = dataInput.readUnsignedShort();
final int numberOfLocals = frameType - 251;
typesOfLocals = new StackMapType[numberOfLocals];
for (int i = 0; i < numberOfLocals; i++) {
typesOfLocals[i] = new StackMapType(dataInput, constantPool);
}
} else if (frameType == Const.FULL_FRAME) {
byteCodeOffset = dataInput.readUnsignedShort();
final int numberOfLocals = dataInput.readUnsignedShort();
typesOfLocals = new StackMapType[numberOfLocals];
for (int i = 0; i < numberOfLocals; i++) {
typesOfLocals[i] = new StackMapType(dataInput, constantPool);
}
final int numberOfStackItems = dataInput.readUnsignedShort();
typesOfStackItems = new StackMapType[numberOfStackItems];
for (int i = 0; i < numberOfStackItems; i++) {
typesOfStackItems[i] = new StackMapType(dataInput, constantPool);
}
} else {
/* Can't happen */
throw new ClassFormatException("Invalid frame type found while parsing stack map table: " + frameType);
}
}
/**
* DO NOT USE
*
* @param byteCodeOffset
* @param numberOfLocals NOT USED
* @param typesOfLocals array of {@link StackMapType}s of locals
* @param numberOfStackItems NOT USED
* @param typesOfStackItems array ot {@link StackMapType}s of stack items
* @param constantPool the constant pool
* @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)} instead
*/
@java.lang.Deprecated
public StackMapEntry(final int byteCodeOffset, final int numberOfLocals, final StackMapType[] typesOfLocals, final int numberOfStackItems,
final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
this.byteCodeOffset = byteCodeOffset;
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY;
this.constantPool = constantPool;
if (numberOfLocals < 0) {
throw new IllegalArgumentException("numberOfLocals < 0");
}
if (numberOfStackItems < 0) {
throw new IllegalArgumentException("numberOfStackItems < 0");
}
}
/**
* Create an instance
*
* @param tag the frameType to use
* @param byteCodeOffset
* @param typesOfLocals array of {@link StackMapType}s of locals
* @param typesOfStackItems array ot {@link StackMapType}s of stack items
* @param constantPool the constant pool
*/
public StackMapEntry(final int tag, final int byteCodeOffset, final StackMapType[] typesOfLocals, final StackMapType[] typesOfStackItems,
final ConstantPool constantPool) {
this.frameType = tag;
this.byteCodeOffset = byteCodeOffset;
this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY;
this.constantPool = constantPool;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitStackMapEntry(this);
}
/**
* @return deep copy of this object
*/
public StackMapEntry copy() {
StackMapEntry e;
try {
e = (StackMapEntry) clone();
} catch (final CloneNotSupportedException ex) {
throw new UnsupportedOperationException("Clone Not Supported", ex);
}
e.typesOfLocals = new StackMapType[typesOfLocals.length];
Arrays.setAll(e.typesOfLocals, i -> typesOfLocals[i].copy());
e.typesOfStackItems = new StackMapType[typesOfStackItems.length];
Arrays.setAll(e.typesOfStackItems, i -> typesOfStackItems[i].copy());
return e;
}
/**
* Dump stack map entry
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.write(frameType);
if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
typesOfStackItems[0].dump(file);
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
file.writeShort(byteCodeOffset);
typesOfStackItems[0].dump(file);
} else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
file.writeShort(byteCodeOffset);
} else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
file.writeShort(byteCodeOffset);
for (final StackMapType type : typesOfLocals) {
type.dump(file);
}
} else if (frameType == Const.FULL_FRAME) {
file.writeShort(byteCodeOffset);
file.writeShort(typesOfLocals.length);
for (final StackMapType type : typesOfLocals) {
type.dump(file);
}
file.writeShort(typesOfStackItems.length);
for (final StackMapType type : typesOfStackItems) {
type.dump(file);
}
} else if (!(frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX)) {
/* Can't happen */
throw new ClassFormatException("Invalid Stack map table tag: " + frameType);
}
}
public int getByteCodeOffset() {
return byteCodeOffset;
}
/**
* @return Constant pool used by this object.
*/
public ConstantPool getConstantPool() {
return constantPool;
}
public int getFrameType() {
return frameType;
}
/**
* Calculate stack map entry size
*/
int getMapEntrySize() {
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
return 1;
}
if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
return 1 + (typesOfStackItems[0].hasIndex() ? 3 : 1);
}
if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
return 3 + (typesOfStackItems[0].hasIndex() ? 3 : 1);
}
if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
return 3;
}
if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
int len = 3;
for (final StackMapType typesOfLocal : typesOfLocals) {
len += typesOfLocal.hasIndex() ? 3 : 1;
}
return len;
}
if (frameType != Const.FULL_FRAME) {
throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
}
int len = 7;
for (final StackMapType typesOfLocal : typesOfLocals) {
len += typesOfLocal.hasIndex() ? 3 : 1;
}
for (final StackMapType typesOfStackItem : typesOfStackItems) {
len += typesOfStackItem.hasIndex() ? 3 : 1;
}
return len;
}
public int getNumberOfLocals() {
return typesOfLocals.length;
}
public int getNumberOfStackItems() {
return typesOfStackItems.length;
}
public StackMapType[] getTypesOfLocals() {
return typesOfLocals;
}
public StackMapType[] getTypesOfStackItems() {
return typesOfStackItems;
}
private boolean invalidFrameType(final int f) {
// @formatter:off
return f != Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
&& !(f >= Const.CHOP_FRAME && f <= Const.CHOP_FRAME_MAX)
&& f != Const.SAME_FRAME_EXTENDED
&& !(f >= Const.APPEND_FRAME && f <= Const.APPEND_FRAME_MAX)
&& f != Const.FULL_FRAME;
// @formatter:on
}
public void setByteCodeOffset(final int newOffset) {
if (newOffset < 0 || newOffset > 32767) {
throw new IllegalArgumentException("Invalid StackMap offset: " + newOffset);
}
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
if (newOffset > Const.SAME_FRAME_MAX) {
frameType = Const.SAME_FRAME_EXTENDED;
} else {
frameType = newOffset;
}
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
if (newOffset > Const.SAME_FRAME_MAX) {
frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
} else {
frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + newOffset;
}
} else if (invalidFrameType(frameType)) {
throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
}
byteCodeOffset = newOffset;
}
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
public void setFrameType(final int ft) {
if (ft >= Const.SAME_FRAME && ft <= Const.SAME_FRAME_MAX) {
byteCodeOffset = ft - Const.SAME_FRAME;
} else if (ft >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && ft <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
byteCodeOffset = ft - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
} else if (invalidFrameType(ft)) {
throw new IllegalArgumentException("Invalid StackMap frameType");
}
frameType = ft;
}
/**
*
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfLocals(final int n) { // TODO unused
}
/**
*
* @deprecated since 6.0
*/
@java.lang.Deprecated
public void setNumberOfStackItems(final int n) { // TODO unused
}
public void setTypesOfLocals(final StackMapType[] types) {
typesOfLocals = types != null ? types : StackMapType.EMPTY_ARRAY;
}
public void setTypesOfStackItems(final StackMapType[] types) {
typesOfStackItems = types != null ? types : StackMapType.EMPTY_ARRAY;
}
/**
* @return String representation.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder(64);
buf.append("(");
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
buf.append("SAME");
} else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
buf.append("SAME_LOCALS_1_STACK");
} else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
buf.append("SAME_LOCALS_1_STACK_EXTENDED");
} else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
buf.append("CHOP ").append(String.valueOf(251 - frameType));
} else if (frameType == Const.SAME_FRAME_EXTENDED) {
buf.append("SAME_EXTENDED");
} else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
buf.append("APPEND ").append(String.valueOf(frameType - 251));
} else if (frameType == Const.FULL_FRAME) {
buf.append("FULL");
} else {
buf.append("UNKNOWN (").append(frameType).append(")");
}
buf.append(", offset delta=").append(byteCodeOffset);
if (typesOfLocals.length > 0) {
buf.append(", locals={");
for (int i = 0; i < typesOfLocals.length; i++) {
buf.append(typesOfLocals[i]);
if (i < typesOfLocals.length - 1) {
buf.append(", ");
}
}
buf.append("}");
}
if (typesOfStackItems.length > 0) {
buf.append(", stack items={");
for (int i = 0; i < typesOfStackItems.length; i++) {
buf.append(typesOfStackItems[i]);
if (i < typesOfStackItems.length - 1) {
buf.append(", ");
}
}
buf.append("}");
}
buf.append(")");
return buf.toString();
}
/**
* Update the distance (as an offset delta) from this StackMap entry to the next. Note that this might cause the
* frame type to change. Note also that delta may be negative.
*
* @param delta offset delta
*/
public void updateByteCodeOffset(final int delta) {
setByteCodeOffset(byteCodeOffset + delta);
}
}

View file

@ -0,0 +1,183 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents the type of a local variable or item on stack used in the StackMap entries.
*
* @see StackMapEntry
* @see StackMap
* @see Const
*/
public final class StackMapType implements Node, Cloneable {
public static final StackMapType[] EMPTY_ARRAY = {}; // BCELifier code generator writes calls to constructor translating null to EMPTY_ARRAY
private byte type;
private int index = -1; // Index to CONSTANT_Class or offset
private ConstantPool constantPool;
/**
* @param type type tag as defined in the Constants interface
* @param index index to constant pool, or byte code offset
*/
public StackMapType(final byte type, final int index, final ConstantPool constantPool) {
this.type = checkType(type);
this.index = index;
this.constantPool = constantPool;
}
/**
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
*/
StackMapType(final DataInput file, final ConstantPool constantPool) throws IOException {
this(file.readByte(), -1, constantPool);
if (hasIndex()) {
this.index = file.readUnsignedShort();
}
this.constantPool = constantPool;
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
* @since 6.8.0
*/
@Override
public void accept(final Visitor v) {
v.visitStackMapType(this);
}
private byte checkType(final byte type) {
if (type < Const.ITEM_Bogus || type > Const.ITEM_NewObject) {
throw new ClassFormatException("Illegal type for StackMapType: " + type);
}
return type;
}
/**
* @return deep copy of this object
*/
public StackMapType copy() {
try {
return (StackMapType) clone();
} catch (final CloneNotSupportedException e) {
// TODO should this throw?
}
return null;
}
/**
* Dump type entries to file.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
public void dump(final DataOutputStream file) throws IOException {
file.writeByte(type);
if (hasIndex()) {
file.writeShort(getIndex());
}
}
/**
* Gets the class name of this StackMapType from the constant pool at index position.
* @return the fully qualified name of the class for this StackMapType.
* @since 6.8.0
*/
public String getClassName() {
return constantPool.constantToString(index, Const.CONSTANT_Class);
}
/**
* @return Constant pool used by this object.
*/
public ConstantPool getConstantPool() {
return constantPool;
}
/**
* @return index to constant pool if type == ITEM_Object, or offset in byte code, if type == ITEM_NewObject, and -1
* otherwise
*/
public int getIndex() {
return index;
}
public byte getType() {
return type;
}
/**
* @return true, if type is either ITEM_Object or ITEM_NewObject
*/
public boolean hasIndex() {
return type == Const.ITEM_Object || type == Const.ITEM_NewObject;
}
private String printIndex() {
if (type == Const.ITEM_Object) {
if (index < 0) {
return ", class=<unknown>";
}
return ", class=" + getClassName();
}
if (type == Const.ITEM_NewObject) {
return ", offset=" + index;
}
return "";
}
/**
* @param constantPool Constant pool to be used for this object.
*/
public void setConstantPool(final ConstantPool constantPool) {
this.constantPool = constantPool;
}
public void setIndex(final int index) {
this.index = index;
}
public void setType(final byte type) {
this.type = checkType(type);
}
/**
* @return String representation
*/
@Override
public String toString() {
return "(type=" + Const.getItemName(type) + printIndex() + ")";
}
}

View file

@ -0,0 +1,145 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.util.Args;
/**
* This class is derived from <em>Attribute</em> and declares this class as 'synthetic', i.e., it needs special
* handling. The JVM specification states "A class member that does not appear in the source code must be marked using a
* Synthetic attribute." It may appear in the ClassFile attribute table, a field_info table or a method_info table. This
* class is intended to be instantiated from the <em>Attribute.readAttribute()</em> method.
*
* @see Attribute
*/
public final class Synthetic extends Attribute {
private byte[] bytes;
/**
* @param nameIndex Index in constant pool to CONSTANT_Utf8, which should represent the string "Synthetic".
* @param length Content length in bytes - should be zero.
* @param bytes Attribute contents
* @param constantPool The constant pool this attribute is associated with.
*/
public Synthetic(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
super(Const.ATTR_SYNTHETIC, nameIndex, Args.require0(length, "Synthetic attribute length"), constantPool);
this.bytes = bytes;
}
/**
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Synthetic(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (byte[]) null, constantPool);
if (length > 0) {
bytes = new byte[length];
input.readFully(bytes);
println("Synthetic attribute with length > 0");
}
}
/**
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
*
* @param c Source to copy.
*/
public Synthetic(final Synthetic c) {
this(c.getNameIndex(), c.getLength(), c.getBytes(), c.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitSynthetic(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final Synthetic c = (Synthetic) clone();
if (bytes != null) {
c.bytes = bytes.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dump source file attribute to file stream in binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
if (super.getLength() > 0) {
file.write(bytes, 0, super.getLength());
}
}
/**
* @return data bytes.
*/
public byte[] getBytes() {
return bytes;
}
/**
* @param bytes
*/
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@Override
public String toString() {
final StringBuilder buf = new StringBuilder("Synthetic");
if (super.getLength() > 0) {
buf.append(" ").append(Utility.toHexString(bytes));
}
return buf.toString();
}
}

View file

@ -0,0 +1,164 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import com.sun.org.apache.bcel.internal.Const;
/**
* This class represents a reference to an unknown (i.e., application-specific) attribute of a class. It is instantiated
* from the {@link Attribute#readAttribute(java.io.DataInput, ConstantPool)} method. Applications that need to read in
* application-specific attributes should create an {@link UnknownAttributeReader} implementation and attach it via
* {@link Attribute#addAttributeReader(String, UnknownAttributeReader)}.
*
* @see Attribute
* @see UnknownAttributeReader
*/
public final class Unknown extends Attribute {
private byte[] bytes;
private final String name;
/**
* Constructs a new instance for a non-standard attribute.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param bytes Attribute contents
* @param constantPool Array of constants
*/
public Unknown(final int nameIndex, final int length, final byte[] bytes, final ConstantPool constantPool) {
super(Const.ATTR_UNKNOWN, nameIndex, length, constantPool);
this.bytes = bytes;
this.name = constantPool.getConstantUtf8(nameIndex).getBytes();
}
/**
* Constructs a new instance from an input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
* @param input Input stream
* @param constantPool Array of constants
* @throws IOException if an I/O error occurs.
*/
Unknown(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
this(nameIndex, length, (byte[]) null, constantPool);
if (length > 0) {
bytes = new byte[length];
input.readFully(bytes);
}
}
/**
* Constructs a new instance from another instance. Note that both objects use the same references (shallow copy). Use clone() for a physical copy.
*
* @param unknown Source.
*/
public Unknown(final Unknown unknown) {
this(unknown.getNameIndex(), unknown.getLength(), unknown.getBytes(), unknown.getConstantPool());
}
/**
* Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
* I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitUnknown(this);
}
/**
* @return deep copy of this attribute
*/
@Override
public Attribute copy(final ConstantPool constantPool) {
final Unknown c = (Unknown) clone();
if (bytes != null) {
c.bytes = bytes.clone();
}
c.setConstantPool(constantPool);
return c;
}
/**
* Dumps unknown bytes to file stream.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
*/
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
if (super.getLength() > 0) {
file.write(bytes, 0, super.getLength());
}
}
/**
* @return data bytes.
*/
public byte[] getBytes() {
return bytes;
}
/**
* @return name of attribute.
*/
@Override
public String getName() {
return name;
}
/**
* @param bytes the bytes to set
*/
public void setBytes(final byte[] bytes) {
this.bytes = bytes;
}
/**
* @return String representation.
*/
@Override
public String toString() {
if (super.getLength() == 0 || bytes == null) {
return "(Unknown attribute " + name + ")";
}
String hex;
final int limit = 10;
if (super.getLength() > limit) {
final byte[] tmp = Arrays.copyOf(bytes, limit);
hex = Utility.toHexString(tmp) + "... (truncated)";
} else {
hex = Utility.toHexString(bytes);
}
return "(Unknown attribute " + name + ": " + hex + ")";
}
}

View file

@ -0,0 +1,50 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
/**
* Unknown (non-standard) attributes may be read via user-defined factory objects that can be registered with the
* Attribute.addAttributeReader method. These factory objects should implement this interface.
*
* @see Attribute
* @since 6.0
*/
public interface UnknownAttributeReader {
/**
* When this attribute reader is added via the static method Attribute.addAttributeReader, an attribute name is
* associated with it. As the class file parser parses attributes, it will call various AttributeReaders based on the
* name of the attributes it is constructing.
*
* @param nameIndex An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute.
* @param length The length of the data contained in the attribute. This is written into the constant pool and should
* agree with what the factory expects the length to be.
* @param file This is the data input that the factory needs to read its data from.
* @param constantPool This is the constant pool associated with the Attribute that we are constructing.
*
* @return The user-defined AttributeReader should take this data and use it to construct an attribute. In the case of
* errors, a null can be returned which will cause the parsing of the class file to fail.
*
* @see Attribute#addAttributeReader(String, UnknownAttributeReader)
*/
Attribute createAttribute(int nameIndex, int length, java.io.DataInput file, ConstantPool constantPool);
}

View file

@ -0,0 +1,268 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.classfile;
/**
* Interface to make use of the Visitor pattern programming style. I.e. a class that implements this interface can
* traverse the contents of a Java class just by calling the 'accept' method which all classes have.
*/
public interface Visitor {
/**
* @since 6.0
*/
void visitAnnotation(Annotations obj);
/**
* @since 6.0
*/
void visitAnnotationDefault(AnnotationDefault obj);
/**
* @since 6.0
*/
void visitAnnotationEntry(AnnotationEntry obj);
/**
* @since 6.0
*/
void visitBootstrapMethods(BootstrapMethods obj);
void visitCode(Code obj);
void visitCodeException(CodeException obj);
void visitConstantClass(ConstantClass obj);
void visitConstantDouble(ConstantDouble obj);
/**
* @since 6.3
*/
default void visitConstantDynamic(final ConstantDynamic constantDynamic) {
// empty
}
void visitConstantFieldref(ConstantFieldref obj);
void visitConstantFloat(ConstantFloat obj);
void visitConstantInteger(ConstantInteger obj);
void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj);
void visitConstantInvokeDynamic(ConstantInvokeDynamic obj);
void visitConstantLong(ConstantLong obj);
/**
* @since 6.0
*/
void visitConstantMethodHandle(ConstantMethodHandle obj);
void visitConstantMethodref(ConstantMethodref obj);
/**
* @since 6.0
*/
void visitConstantMethodType(ConstantMethodType obj);
/**
* @since 6.1
*/
void visitConstantModule(ConstantModule constantModule);
void visitConstantNameAndType(ConstantNameAndType obj);
/**
* @since 6.1
*/
void visitConstantPackage(ConstantPackage constantPackage);
void visitConstantPool(ConstantPool obj);
void visitConstantString(ConstantString obj);
void visitConstantUtf8(ConstantUtf8 obj);
void visitConstantValue(ConstantValue obj);
void visitDeprecated(Deprecated obj);
/**
* @since 6.0
*/
void visitEnclosingMethod(EnclosingMethod obj);
void visitExceptionTable(ExceptionTable obj);
void visitField(Field obj);
void visitInnerClass(InnerClass obj);
void visitInnerClasses(InnerClasses obj);
void visitJavaClass(JavaClass obj);
void visitLineNumber(LineNumber obj);
void visitLineNumberTable(LineNumberTable obj);
void visitLocalVariable(LocalVariable obj);
void visitLocalVariableTable(LocalVariableTable obj);
/**
* @since 6.0
*/
void visitLocalVariableTypeTable(LocalVariableTypeTable obj);
void visitMethod(Method obj);
/**
* @since 6.4.0
*/
default void visitMethodParameter(final MethodParameter obj) {
// empty
}
/**
* @since 6.0
*/
void visitMethodParameters(MethodParameters obj);
/**
* @since 6.4.0
*/
default void visitModule(final Module constantModule) {
// empty
}
/**
* @since 6.4.0
*/
default void visitModuleExports(final ModuleExports constantModule) {
// empty
}
/**
* @since 6.4.0
*/
default void visitModuleMainClass(final ModuleMainClass obj) {
// empty
}
/**
* @since 6.4.0
*/
default void visitModuleOpens(final ModuleOpens constantModule) {
// empty
}
/**
* @since 6.4.0
*/
default void visitModulePackages(final ModulePackages constantModule) {
// empty
}
/**
* @since 6.4.0
*/
default void visitModuleProvides(final ModuleProvides constantModule) {
// empty
}
/**
* @since 6.4.0
*/
default void visitModuleRequires(final ModuleRequires constantModule) {
// empty
}
/**
* @since 6.4.0
*/
default void visitNestHost(final NestHost obj) {
// empty
}
/**
* @since 6.4.0
*/
default void visitNestMembers(final NestMembers obj) {
// empty
}
/**
* @since 6.0
*/
void visitParameterAnnotation(ParameterAnnotations obj);
/**
* @since 6.0
*/
void visitParameterAnnotationEntry(ParameterAnnotationEntry obj);
/**
* Visits a {@link Record} object.
*
* @param obj Record to visit
* @since 6.9.0
*/
default void visitRecord(final Record obj) {
// empty
}
/**
* Visits a {@link RecordComponentInfo} object.
*
* @param record component to visit
* @since 6.9.0
*/
default void visitRecordComponent(final RecordComponentInfo record) {
// noop
}
void visitSignature(Signature obj);
void visitSourceFile(SourceFile obj);
void visitStackMap(StackMap obj);
void visitStackMapEntry(StackMapEntry obj);
/**
* Visits a {@link StackMapType} object.
*
* @param obj object to visit
* @since 6.8.0
*/
default void visitStackMapType(final StackMapType obj) {
// empty
}
void visitSynthetic(Synthetic obj);
void visitUnknown(Unknown obj);
}

View file

@ -0,0 +1,25 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Classes that describe the structure of a Java class file and a class file parser.
*/
package com.sun.org.apache.bcel.internal.classfile;

View file

@ -0,0 +1,30 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--
$Id: package.html 919342 2010-03-05 09:12:23Z markt $
-->
</head>
<body bgcolor="white">
<p>
This package contains the classes that describe the structure of a
Java class file and a class file parser.
</p>
</body>
</html>

View file

@ -0,0 +1,54 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.generic;
/**
* AALOAD - Load reference from array
*
* <PRE>
* Stack: ..., arrayref, index -&gt; value
* </PRE>
*/
public class AALOAD extends ArrayInstruction implements StackProducer {
/**
* Load reference from array
*/
public AALOAD() {
super(com.sun.org.apache.bcel.internal.Const.AALOAD);
}
/**
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitStackProducer(this);
v.visitExceptionThrower(this);
v.visitTypedInstruction(this);
v.visitArrayInstruction(this);
v.visitAALOAD(this);
}
}

View file

@ -0,0 +1,54 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.generic;
/**
* AASTORE - Store into reference array
*
* <PRE>
* Stack: ..., arrayref, index, value -&gt; ...
* </PRE>
*/
public class AASTORE extends ArrayInstruction implements StackConsumer {
/**
* Store into reference array
*/
public AASTORE() {
super(com.sun.org.apache.bcel.internal.Const.AASTORE);
}
/**
* Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
* methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
*
* @param v Visitor object
*/
@Override
public void accept(final Visitor v) {
v.visitStackConsumer(this);
v.visitExceptionThrower(this);
v.visitTypedInstruction(this);
v.visitArrayInstruction(this);
v.visitAASTORE(this);
}
}

Some files were not shown because too many files have changed in this diff Show more