8336695: Update Commons BCEL to Version 6.10.0

Reviewed-by: lancea, naoto, iris
This commit is contained in:
Joe Wang 2025-10-03 03:50:01 +00:00
parent f62b9eca08
commit 3790965df3
122 changed files with 2461 additions and 1128 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -26,7 +26,7 @@ import jdk.xml.internal.Utils;
* Exception constants.
*
* @since 6.0 (intended to replace the InstructionConstant interface)
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public final class ExceptionConst {
@ -52,7 +52,6 @@ public final class ExceptionConst {
* Super class of any linking exception (aka Linkage Error)
*/
public static final Class<LinkageError> LINKING_EXCEPTION = LinkageError.class;
/**
* Linking Exceptions
*/
@ -67,10 +66,10 @@ public final class ExceptionConst {
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
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -30,7 +30,7 @@ import com.sun.org.apache.bcel.internal.util.SyntheticRepository;
* @see com.sun.org.apache.bcel.internal.util.Repository
* @see SyntheticRepository
*
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public abstract class Repository {
@ -174,7 +174,7 @@ public abstract class Repository {
}
/**
* Lookups class somewhere found on your CLASSPATH, or wherever the repository instance looks for it.
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -25,27 +25,36 @@ 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: Jan 2020
* @LastModified: Sept 2025
*/
public abstract class AccessFlags {
/**
* @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
* 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() {
}
/**
* @param a initial access flags
* Constructs a new instance.
*
* @param accessFlags initial access flags.
*/
public AccessFlags(final int a) {
access_flags = a;
public AccessFlags(final int accessFlags) {
access_flags = accessFlags;
}
/**
* Gets access flags.
*
* @return Access flags of the object aka. "modifiers".
*/
public final int getAccessFlags() {
@ -53,142 +62,303 @@ public abstract class AccessFlags {
}
/**
* @return Access flags of the object aka. "modifiers".
* 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 (access_flags & Const.ACC_ABSTRACT) != 0;
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 (access_flags & Const.ACC_ANNOTATION) != 0;
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 (access_flags & Const.ACC_ENUM) != 0;
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 (access_flags & Const.ACC_FINAL) != 0;
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 (access_flags & Const.ACC_INTERFACE) != 0;
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 (access_flags & Const.ACC_NATIVE) != 0;
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 (access_flags & Const.ACC_PRIVATE) != 0;
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 (access_flags & Const.ACC_PROTECTED) != 0;
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 (access_flags & Const.ACC_PUBLIC) != 0;
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 (access_flags & Const.ACC_STATIC) != 0;
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 (access_flags & Const.ACC_STRICT) != 0;
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 (access_flags & Const.ACC_SYNCHRONIZED) != 0;
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 (access_flags & Const.ACC_SYNTHETIC) != 0;
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 (access_flags & Const.ACC_TRANSIENT) != 0;
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 (access_flags & Const.ACC_VARARGS) != 0;
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 (access_flags & Const.ACC_VOLATILE) != 0;
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);
}
/**
* Set access flags aka "modifiers".
* Sets access flags also known as modifiers.
*
* @param accessFlags Access flags of the object.
*/
@ -207,11 +377,21 @@ public abstract class AccessFlags {
}
/**
* Set access flags aka "modifiers".
* 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

@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -27,20 +26,22 @@ 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[] attrs) {
public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attributes) {
// Find attributes that contain annotation data
return Stream.of(attrs).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries()))
.toArray(AnnotationEntry[]::new);
return Utils.streamOfIfNonNull(attributes).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries()))
.toArray(AnnotationEntry[]::new);
}
/**
@ -55,7 +56,6 @@ public class AnnotationEntry implements Node {
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();
annotationEntry.elementValuePairs = new ArrayList<>();
for (int i = 0; i < numElementValuePairs; i++) {
annotationEntry.elementValuePairs
.add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool));
@ -69,12 +69,13 @@ public class AnnotationEntry implements Node {
private final boolean isRuntimeVisible;
private List<ElementValuePair> elementValuePairs;
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<>();
}
/**

View File

@ -52,7 +52,7 @@ public abstract class Annotations extends Attribute implements Iterable<Annotati
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);
this.annotationTable = annotationTable;
setAnnotationTable(annotationTable);
this.isRuntimeVisible = isRuntimeVisible;
}
@ -108,9 +108,6 @@ public abstract class Annotations extends Attribute implements Iterable<Annotati
* @return the number of annotation entries in this annotation
*/
public final int getNumAnnotations() {
if (annotationTable == null) {
return 0;
}
return annotationTable.length;
}
@ -129,7 +126,7 @@ public abstract class Annotations extends Attribute implements Iterable<Annotati
* @param annotationTable the entries to set in this annotation
*/
public final void setAnnotationTable(final AnnotationEntry[] annotationTable) {
this.annotationTable = annotationTable;
this.annotationTable = annotationTable != null ? annotationTable : AnnotationEntry.EMPTY_ARRAY;
}
/**
@ -151,9 +148,6 @@ public abstract class Annotations extends Attribute implements Iterable<Annotati
}
protected void writeAnnotations(final DataOutputStream dos) throws IOException {
if (annotationTable == null) {
return;
}
dos.writeShort(annotationTable.length);
for (final AnnotationEntry element : annotationTable) {
element.dump(dos);

View File

@ -31,12 +31,12 @@ public class ArrayElementValue extends ElementValue {
// For array types, this is the array
private final ElementValue[] elementValues;
public ArrayElementValue(final int type, final ElementValue[] datums, final ConstantPool cpool) {
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 = datums;
this.elementValues = elementValues != null ? elementValues : EMPTY_ARRAY;
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -53,7 +53,7 @@ import com.sun.org.apache.bcel.internal.util.Args;
* @see Synthetic
* @see Deprecated
* @see Signature
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public abstract class Attribute implements Cloneable, Node {
private static final boolean debug = false;
@ -181,6 +181,8 @@ public abstract class Attribute implements Cloneable, Node {
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);
@ -279,7 +281,7 @@ public abstract class Attribute implements Cloneable, Node {
try {
attr = (Attribute) super.clone();
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
}
return attr;
}

View File

@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -27,6 +26,7 @@ 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
@ -35,9 +35,12 @@ import com.sun.org.apache.bcel.internal.Const;
* @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;
@ -54,7 +57,7 @@ public class BootstrapMethod implements Cloneable {
}
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param input Input stream
* @throws IOException if an I/O error occurs.
@ -78,7 +81,7 @@ public class BootstrapMethod implements Cloneable {
*/
public BootstrapMethod(final int bootstrapMethodRef, final int[] bootstrapArguments) {
this.bootstrapMethodRef = bootstrapMethodRef;
this.bootstrapArguments = bootstrapArguments;
setBootstrapArguments(bootstrapArguments);
}
/**
@ -87,7 +90,7 @@ public class BootstrapMethod implements Cloneable {
public BootstrapMethod copy() {
try {
return (BootstrapMethod) clone();
} catch (final CloneNotSupportedException e) {
} catch (final CloneNotSupportedException ignore) {
// TODO should this throw?
}
return null;
@ -132,7 +135,7 @@ public class BootstrapMethod implements Cloneable {
* @param bootstrapArguments int[] indices into constant_pool of CONSTANT_[type]_info
*/
public void setBootstrapArguments(final int[] bootstrapArguments) {
this.bootstrapArguments = bootstrapArguments;
this.bootstrapArguments = Utils.createEmptyArrayIfNull(bootstrapArguments);
}
/**

View File

@ -58,11 +58,11 @@ public class BootstrapMethods extends Attribute implements Iterable<BootstrapMet
*/
public BootstrapMethods(final int nameIndex, final int length, final BootstrapMethod[] bootstrapMethods, final ConstantPool constantPool) {
super(Const.ATTR_BOOTSTRAP_METHODS, nameIndex, length, constantPool);
this.bootstrapMethods = bootstrapMethods;
setBootstrapMethods(bootstrapMethods);
}
/**
* Construct object from Input stream.
* Constructs object from Input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
@ -135,7 +135,7 @@ public class BootstrapMethods extends Attribute implements Iterable<BootstrapMet
* @param bootstrapMethods the array of bootstrap methods
*/
public final void setBootstrapMethods(final BootstrapMethod[] bootstrapMethods) {
this.bootstrapMethods = bootstrapMethods;
this.bootstrapMethods = bootstrapMethods != null ? bootstrapMethods : BootstrapMethod.EMPTY_ARRAY;
}
/**

View File

@ -47,12 +47,10 @@ public class ClassFormatException extends RuntimeException {
/**
* Constructs a new instance with the specified detail message and cause.
* <p>
* Note that the detail message associated with {@code cause} is <i>not</i> automatically incorporated in this runtime exception's detail message.
*
* @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.)
* @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) {
@ -63,8 +61,8 @@ public class ClassFormatException extends RuntimeException {
* 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.)
* @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) {

View File

@ -37,7 +37,7 @@ import com.sun.org.apache.bcel.internal.Const;
* appropriate exception is propagated back to the caller.
*
* The structure and the names comply, except for a few conveniences, exactly with the
* <a href="http://docs.oracle.com/javase/specs/"> JVM specification 1.0</a>. See this paper for further details about
* <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 {
@ -57,7 +57,7 @@ public final class ClassParser {
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
private final boolean isZip; // Loaded from ZIP file
/**
* Parses class from the given stream.
@ -91,7 +91,7 @@ public final class ClassParser {
/**
* Parses class from given .class file in a ZIP-archive
*
* @param zipFile zip file name
* @param zipFile ZIP file name
* @param fileName file name
*/
public ClassParser(final String zipFile, final String fileName) {
@ -104,7 +104,7 @@ public final class ClassParser {
/**
* 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).
* 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.
@ -151,11 +151,11 @@ public final class ClassParser {
// for (int i=0; i < u.length; i++)
// System.err.println("WARNING: " + u[i]);
// Everything should have been read now
// if(file.available() > 0) {
// if (file.available() > 0) {
// int bytes = file.available();
// byte[] buf = new byte[bytes];
// file.read(buf);
// if(!(isZip && (buf.length == 1))) {
// if (!(isZip && (buf.length == 1))) {
// System.err.println("WARNING: Trailing garbage at end of " + fileName);
// System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf));
// }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -27,6 +27,7 @@ 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
@ -59,7 +60,7 @@ import com.sun.org.apache.bcel.internal.util.Args;
* @see CodeException
* @see LineNumberTable
* @see LocalVariableTable
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public final class Code extends Attribute {
@ -93,7 +94,7 @@ public final class Code extends 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()
* Read exception table that contains all regions where an exception handler is active, i.e., a try { ... } catch ()
* block.
*/
final int exceptionTableLength = file.readUnsignedShort();
@ -107,7 +108,7 @@ public final class Code extends Attribute {
final int attributesCount = file.readUnsignedShort();
attributes = new Attribute[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes[i] = Attribute.readAttribute(file, constantPool);
attributes[i] = readAttribute(file, constantPool);
}
/*
* Adjust length, because of setAttributes in this(), s.b. length is incorrect, because it didn't take the internal
@ -131,8 +132,8 @@ public final class Code extends Attribute {
super(Const.ATTR_CODE, nameIndex, length, constantPool);
this.maxStack = Args.requireU2(maxStack, "maxStack");
this.maxLocals = Args.requireU2(maxLocals, "maxLocals");
this.code = code != null ? code : Const.EMPTY_BYTE_ARRAY;
this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY;
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
@ -263,6 +264,20 @@ public final class Code extends 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.
*/
@ -277,6 +292,20 @@ public final class Code extends Attribute {
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
*/
@ -289,7 +318,7 @@ public final class Code extends Attribute {
* @param code byte code
*/
public void setCode(final byte[] code) {
this.code = code != null ? code : Const.EMPTY_BYTE_ARRAY;
this.code = Utils.createEmptyArrayIfNull(code);
super.setLength(calculateLength()); // Adjust length
}
@ -297,7 +326,7 @@ public final class Code extends Attribute {
* @param exceptionTable exception table
*/
public void setExceptionTable(final CodeException[] exceptionTable) {
this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY;
this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_ARRAY;
super.setLength(calculateLength()); // Adjust length
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -52,19 +52,19 @@ import com.sun.org.apache.bcel.internal.util.Args;
* </pre>
*
* @see Code
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public final class CodeException implements Cloneable, Node {
/**
* Empty array.
*/
static final CodeException[] EMPTY_CODE_EXCEPTION_ARRAY = {};
static final CodeException[] EMPTY_ARRAY = {};
/** Range in the code the exception handler. */
private int startPc;
/** active. startPc is inclusive, endPc exclusive. */
/** Active. startPc is inclusive, endPc exclusive. */
private int endPc;
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -32,30 +32,29 @@ import com.sun.org.apache.bcel.internal.util.BCELComparator;
* in the constant pool of a class file. The classes keep closely to
* the JVM specification.
*
* @LastModified: May 2021
* @LastModified: Sept 2025
*/
public abstract class Constant implements Cloneable, Node {
private static BCELComparator bcelComparator = new BCELComparator() {
static final Constant[] EMPTY_ARRAY = {};
private static BCELComparator<Constant> bcelComparator = new BCELComparator<Constant>() {
@Override
public boolean equals(final Object o1, final Object o2) {
final Constant THIS = (Constant) o1;
final Constant THAT = (Constant) o2;
return Objects.equals(THIS.toString(), THAT.toString());
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 Object o) {
final Constant THIS = (Constant) o;
return THIS.toString().hashCode();
public int hashCode(final Constant o) {
return o != null ? Objects.hashCode(o.toString()) : 0;
}
};
/**
* @return Comparison strategy object
* @return Comparison strategy object.
*/
public static BCELComparator getComparator() {
public static BCELComparator<Constant> getComparator() {
return bcelComparator;
}
@ -113,7 +112,7 @@ public abstract class Constant implements Cloneable, Node {
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
public static void setComparator(final BCELComparator<Constant> comparator) {
bcelComparator = comparator;
}
@ -148,7 +147,7 @@ public abstract class Constant implements Cloneable, Node {
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
}
}
@ -174,7 +173,7 @@ public abstract class Constant implements Cloneable, Node {
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
return obj instanceof Constant && bcelComparator.equals(this, (Constant) obj);
}
/**
@ -185,7 +184,7 @@ public abstract class Constant implements Cloneable, Node {
}
/**
* Returns value as defined by given BCELComparator strategy. By default return the hashcode of the result of
* Returns value as defined by given BCELComparator strategy. By default return the hash code of the result of
* toString().
*
* @see Object#hashCode()

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -28,11 +28,11 @@ 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: Jun 2019
* @see ConstantFieldref
* @see ConstantMethodref
* @see ConstantInterfaceMethodref
* @see ConstantInvokeDynamic
* @LastModified: Sept 2025
*/
public abstract class ConstantCP extends Constant {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -29,8 +29,8 @@ 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: Jun 2019
* @see Constant
* @LastModified: Sept 2025
*/
public final class ConstantDouble extends Constant implements ConstantObject {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -29,8 +29,8 @@ 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: Jun 2019
* @see Constant
* @LastModified: Sept 2025
*/
public final class ConstantFloat extends Constant implements ConstantObject {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -29,8 +29,8 @@ 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: Jun 2019
* @see Constant
* @LastModified: Sept 2025
*/
public final class ConstantInteger extends Constant implements ConstantObject {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -29,8 +29,8 @@ 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: Jan 2020
* @see Constant
* @LastModified: Sept 2025
*/
public final class ConstantLong extends Constant implements ConstantObject {

View File

@ -29,7 +29,10 @@ package com.sun.org.apache.bcel.internal.classfile;
public interface ConstantObject {
/**
* @return object representing the constant, e.g., Long for ConstantLong
* 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 cp);
Object getConstantValue(ConstantPool constantPool);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -35,7 +35,7 @@ import com.sun.org.apache.bcel.internal.Const;
*
* @see Constant
* @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
@ -73,7 +73,7 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* @param constantPool Array of constants
*/
public ConstantPool(final Constant[] constantPool) {
this.constantPool = constantPool;
setConstantPool(constantPool);
}
/**
@ -88,6 +88,7 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
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);
@ -288,7 +289,7 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
*/
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.getTag() != tag) {
if (c == null || c.getTag() != tag) {
throw new ClassFormatException("Expected class '" + Const.getConstantName(tag) + "' at index " + index + " and got " + c);
}
return c;
@ -313,15 +314,17 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
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
// the 0th element is always null
&& index != 0) {
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 null.");
}
if (c == null) {
throw new ClassFormatException("Constant pool at index " + index + " is null.");
}
return c;
}
@ -402,7 +405,7 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* @return Length of constant pool.
*/
public int getLength() {
return constantPool == null ? 0 : constantPool.length;
return constantPool.length;
}
@Override
@ -421,7 +424,7 @@ public class ConstantPool implements Cloneable, Node, Iterable<Constant> {
* @param constantPool
*/
public void setConstantPool(final Constant[] constantPool) {
this.constantPool = constantPool;
this.constantPool = constantPool != null ? constantPool : Constant.EMPTY_ARRAY;
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -36,11 +36,11 @@ import com.sun.org.apache.bcel.internal.Const;
* The following system properties govern caching this class performs.
* </p>
* <ul>
* <li>{@value #SYS_PROP_CACHE_MAX_ENTRIES} (since 6.4): The size of the cache, by default 0, meaning caching is
* <li>{@link #SYS_PROP_CACHE_MAX_ENTRIES} (since 6.4): The size of the cache, by default 0, meaning caching is
* disabled.</li>
* <li>{@value #SYS_PROP_CACHE_MAX_ENTRY_SIZE} (since 6.0): The maximum size of the values to cache, by default 200, 0
* <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>{@value #SYS_PROP_STATISTICS} (since 6.0): Prints statistics on the console when the JVM exits.</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:
@ -58,11 +58,11 @@ import com.sun.org.apache.bcel.internal.Const;
* </pre>
*
* @see Constant
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public final class ConstantUtf8 extends Constant {
private static class Cache {
private static final class Cache {
private static final boolean BCEL_STATISTICS = false;
private static final int MAX_ENTRIES = 20000;
@ -82,7 +82,7 @@ public final class ConstantUtf8 extends Constant {
private static final int MAX_ENTRY_SIZE = 200;
static boolean isEnabled() {
return Cache.MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0;
return MAX_ENTRIES > 0 && MAX_ENTRY_SIZE > 0;
}
}
@ -117,6 +117,11 @@ public final class ConstantUtf8 extends Constant {
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>
@ -203,7 +208,7 @@ public final class ConstantUtf8 extends Constant {
ConstantUtf8(final DataInput dataInput) throws IOException {
super(Const.CONSTANT_Utf8);
value = dataInput.readUTF();
created++;
countCreated();
}
/**
@ -212,7 +217,7 @@ public final class ConstantUtf8 extends Constant {
public ConstantUtf8(final String value) {
super(Const.CONSTANT_Utf8);
this.value = Objects.requireNonNull(value, "value");
created++;
countCreated();
}
/**

View File

@ -56,7 +56,7 @@ public final class ConstantValue extends Attribute {
}
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Name index in constant pool
* @param length Content length in bytes

View File

@ -59,7 +59,7 @@ public final class Deprecated extends Attribute {
}
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -22,12 +22,13 @@ 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.
* 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;
@ -46,7 +47,7 @@ public class DescendingVisitor implements Visitor {
}
private <E extends Node> void accept(final E[] node) {
Stream.of(node).forEach(e -> e.accept(this));
Utils.streamOfIfNonNull(node).forEach(e -> e.accept(this));
}
/**
@ -507,6 +508,21 @@ public class DescendingVisitor implements 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);
@ -531,6 +547,20 @@ public class DescendingVisitor implements Visitor {
@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();
@ -549,4 +579,5 @@ public class DescendingVisitor implements Visitor {
attribute.accept(visitor);
stack.pop();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -50,7 +50,7 @@ import com.sun.org.apache.bcel.internal.Const;
*}
*</pre>
* @since 6.0
* @LastModified: May 2021
* @LastModified: Sept 2025
*/
public abstract class ElementValue {
@ -67,6 +67,7 @@ public abstract class ElementValue {
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}.
@ -124,7 +125,7 @@ public abstract class ElementValue {
final int numArrayVals = input.readUnsignedShort();
final ElementValue[] evalues = new ElementValue[numArrayVals];
for (int j = 0; j < numArrayVals; j++) {
evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting);
evalues[j] = readElementValue(input, cpool, arrayNesting);
}
return new ArrayElementValue(ARRAY, evalues, cpool);

View File

@ -315,6 +315,15 @@ public class EmptyVisitor implements Visitor {
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) {
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -27,6 +27,7 @@ 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
@ -43,7 +44,7 @@ import com.sun.org.apache.bcel.internal.util.Args;
* }
* </pre>
* @see Code
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public final class ExceptionTable extends Attribute {
@ -60,7 +61,7 @@ public final class ExceptionTable extends Attribute {
}
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
@ -85,7 +86,7 @@ public final class ExceptionTable extends Attribute {
*/
public ExceptionTable(final int nameIndex, final int length, final int[] exceptionIndexTable, final ConstantPool constantPool) {
super(Const.ATTR_EXCEPTIONS, nameIndex, length, constantPool);
this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : Const.EMPTY_INT_ARRAY;
this.exceptionIndexTable = Utils.createEmptyArrayIfNull(exceptionIndexTable);
Args.requireU2(this.exceptionIndexTable.length, "exceptionIndexTable.length");
}
@ -156,7 +157,7 @@ public final class ExceptionTable extends Attribute {
* length.
*/
public void setExceptionIndexTable(final int[] exceptionIndexTable) {
this.exceptionIndexTable = exceptionIndexTable != null ? exceptionIndexTable : Const.EMPTY_INT_ARRAY;
this.exceptionIndexTable = Utils.createEmptyArrayIfNull(exceptionIndexTable);
}
/**

View File

@ -42,45 +42,37 @@ public final class Field extends FieldOrMethod {
*/
public static final Field[] EMPTY_ARRAY = {};
private static BCELComparator bcelComparator = new BCELComparator() {
private static BCELComparator<Field> bcelComparator = new BCELComparator<Field>() {
@Override
public boolean equals(final Object o1, final Object o2) {
final Field THIS = (Field) o1;
final Field THAT = (Field) o2;
return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature());
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 Object o) {
final Field THIS = (Field) o;
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
public int hashCode(final Field o) {
return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
}
};
/**
* Empty array.
* @return Comparison strategy object.
*/
static final Field[] EMPTY_FIELD_ARRAY = {};
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
public static BCELComparator<Field> getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
* @param comparator Comparison strategy object.
*/
public static void setComparator(final BCELComparator comparator) {
public static void setComparator(final BCELComparator<Field> comparator) {
bcelComparator = comparator;
}
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @param file Input stream.
*/
Field(final DataInput file, final ConstantPool constantPool) throws IOException, ClassFormatException {
super(file, constantPool);
@ -133,7 +125,7 @@ public final class Field extends FieldOrMethod {
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
return obj instanceof Field && bcelComparator.equals(this, (Field) obj);
}
/**
@ -149,14 +141,16 @@ public final class Field extends FieldOrMethod {
}
/**
* 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.getReturnType(getSignature());
return Type.getType(getSignature());
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR
* Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR
* signature.
*
* @see Object#hashCode()

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -28,7 +28,7 @@ import java.util.Arrays;
/**
* Abstract super class for fields and methods.
*
* @LastModified: Jan 2020
* @LastModified: Sept 2025
*/
public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node {
@ -72,7 +72,7 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
}
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
@ -88,7 +88,7 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
}
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
@ -137,7 +137,7 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
return c;
} catch (final CloneNotSupportedException e) {
throw new IllegalStateException(e);
throw new UnsupportedOperationException(e);
}
}
@ -152,10 +152,8 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
file.writeShort(name_index);
file.writeShort(signature_index);
file.writeShort(attributes_count);
if (attributes != null) {
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
}
@ -171,6 +169,22 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
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.
*/
@ -221,7 +235,7 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
}
/**
* @return String representation of object's type signature (java style)
* @return String representation of object's type signature (Java style)
*/
public final String getSignature() {
return constant_pool.getConstantUtf8(signature_index).getBytes();
@ -238,8 +252,8 @@ public abstract class FieldOrMethod extends AccessFlags implements Cloneable, No
* @param attributes Collection of object attributes.
*/
public final void setAttributes(final Attribute[] attributes) {
this.attributes = attributes;
this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field
this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
this.attributes_count = this.attributes.length; // init deprecated field
}
/**

View File

@ -41,7 +41,7 @@ public final class InnerClass implements Cloneable, Node {
private int innerAccessFlags;
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.

View File

@ -42,7 +42,7 @@ public final class InnerClasses extends Attribute implements Iterable<InnerClass
/**
* Empty array.
*/
private static final InnerClass[] EMPTY_INNER_CLASSE_ARRAY = {};
private static final InnerClass[] EMPTY_ARRAY = {};
private InnerClass[] innerClasses;
@ -57,7 +57,7 @@ public final class InnerClasses extends Attribute implements Iterable<InnerClass
}
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes
@ -82,7 +82,7 @@ public final class InnerClasses extends Attribute implements Iterable<InnerClass
*/
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_INNER_CLASSE_ARRAY;
this.innerClasses = innerClasses != null ? innerClasses : EMPTY_ARRAY;
Args.requireU2(this.innerClasses.length, "innerClasses.length");
}
@ -141,7 +141,7 @@ public final class InnerClasses extends Attribute implements Iterable<InnerClass
* @param innerClasses the array of inner classes
*/
public void setInnerClasses(final InnerClass[] innerClasses) {
this.innerClasses = innerClasses != null ? innerClasses : EMPTY_INNER_CLASSE_ARRAY;
this.innerClasses = innerClasses != null ? innerClasses : EMPTY_ARRAY;
}
/**

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -38,6 +38,7 @@ 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
@ -46,7 +47,7 @@ import com.sun.org.apache.bcel.internal.util.SyntheticRepository;
* classes should see the <a href="../generic/ClassGen.html">ClassGen</a> class.
*
* @see com.sun.org.apache.bcel.internal.generic.ClassGen
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable<JavaClass> {
@ -67,26 +68,23 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
public static final byte HEAP = 1;
public static final byte FILE = 2;
public static final byte ZIP = 3;
private static BCELComparator bcelComparator = new BCELComparator() {
private static BCELComparator<JavaClass> bcelComparator = new BCELComparator<JavaClass>() {
@Override
public boolean equals(final Object o1, final Object o2) {
final JavaClass THIS = (JavaClass) o1;
final JavaClass THAT = (JavaClass) o2;
return Objects.equals(THIS.getClassName(), THAT.getClassName());
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 Object o) {
final JavaClass THIS = (JavaClass) o;
return THIS.getClassName().hashCode();
public int hashCode(final JavaClass o) {
return o != null ? Objects.hashCode(o.getClassName()) : 0;
}
};
/**
* @return Comparison strategy object
* @return Comparison strategy object.
*/
public static BCELComparator getComparator() {
public static BCELComparator<JavaClass> getComparator() {
return bcelComparator;
}
@ -100,9 +98,9 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
}
/**
* @param comparator Comparison strategy object
* @param comparator Comparison strategy object.
*/
public static void setComparator(final BCELComparator comparator) {
public static void setComparator(final BCELComparator<JavaClass> comparator) {
bcelComparator = comparator;
}
@ -128,8 +126,10 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
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
@ -177,17 +177,15 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
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);
if (interfaces == null) {
interfaces = Const.EMPTY_INT_ARRAY;
}
interfaces = Utils.createEmptyArrayIfNull(interfaces);
if (attributes == null) {
attributes = Attribute.EMPTY_ARRAY;
}
if (fields == null) {
fields = Field.EMPTY_FIELD_ARRAY;
fields = Field.EMPTY_ARRAY;
}
if (methods == null) {
methods = Method.EMPTY_METHOD_ARRAY;
methods = Method.EMPTY_ARRAY;
}
this.classNameIndex = classNameIndex;
this.superclassNameIndex = superclassNameIndex;
@ -254,6 +252,19 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
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;
@ -384,11 +395,51 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
return obj instanceof JavaClass && bcelComparator.equals(this, (JavaClass) obj);
}
/**
* Get all interfaces implemented by this JavaClass (transitively).
* 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.
*/
@ -409,7 +460,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
queue.enqueue(iface);
}
}
return allInterfaces.toArray(JavaClass.EMPTY_ARRAY);
return allInterfaces.toArray(EMPTY_ARRAY);
}
/**
@ -424,6 +475,22 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
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.
*/
@ -495,7 +562,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
}
/**
* Get interfaces directly implemented by this JavaClass.
* Gets interfaces directly implemented by this JavaClass.
*
* @throws ClassNotFoundException if any of the class's interfaces can't be found.
*/
@ -587,7 +654,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
}
/**
* @return the superclass for this JavaClass object, or null if this is java.lang.Object
* @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 {
@ -607,12 +674,12 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) {
allSuperClasses.add(clazz);
}
return allSuperClasses.toArray(JavaClass.EMPTY_ARRAY);
return allSuperClasses.toArray(EMPTY_ARRAY);
}
/**
* returns the super class name of this class. In the case that this class is java.lang.Object, it will return itself
* (java.lang.Object). This is probably incorrect but isn't fixed at this time to not break existing clients.
* 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.
*/
@ -628,7 +695,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name.
* Return value as defined by given BCELComparator strategy. By default return the hash code of the class name.
*
* @see Object#hashCode()
*/
@ -645,7 +712,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
if (!inter.isInterface()) {
throw new IllegalArgumentException(inter.getClassName() + " is no interface");
}
if (this.equals(inter)) {
if (equals(inter)) {
return true;
}
final JavaClass[] superInterfaces = getAllInterfaces();
@ -664,7 +731,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
* @throws ClassNotFoundException if superclasses or superinterfaces of this object can't be found
*/
public final boolean instanceOf(final JavaClass superclass) throws ClassNotFoundException {
if (this.equals(superclass)) {
if (equals(superclass)) {
return true;
}
for (final JavaClass clazz : getSuperClasses()) {
@ -698,6 +765,17 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
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;
}
@ -706,7 +784,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
* @param attributes .
*/
public void setAttributes(final Attribute[] attributes) {
this.attributes = attributes;
this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
}
/**
@ -734,11 +812,11 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
* @param fields .
*/
public void setFields(final Field[] fields) {
this.fields = fields;
this.fields = fields != null ? fields : Field.EMPTY_ARRAY;
}
/**
* Set File name of class, aka SourceFile attribute value
* Sets File name of class, aka SourceFile attribute value
*/
public void setFileName(final String fileName) {
this.fileName = fileName;
@ -748,14 +826,14 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
* @param interfaceNames .
*/
public void setInterfaceNames(final String[] interfaceNames) {
this.interfaceNames = interfaceNames;
this.interfaceNames = Utils.createEmptyArrayIfNull(interfaceNames, String[].class);
}
/**
* @param interfaces .
*/
public void setInterfaces(final int[] interfaces) {
this.interfaces = interfaces;
this.interfaces = Utils.createEmptyArrayIfNull(interfaces);
}
/**
@ -769,7 +847,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
* @param methods .
*/
public void setMethods(final Method[] methods) {
this.methods = methods;
this.methods = methods != null ? methods : Method.EMPTY_ARRAY;
}
/**
@ -787,7 +865,7 @@ public class JavaClass extends AccessFlags implements Cloneable, Node, Comparabl
}
/**
* Set absolute path to file this class was read from.
* Sets absolute path to file this class was read from.
*/
public void setSourceFileName(final String sourceFileName) {
this.sourceFileName = sourceFileName;

View File

@ -40,11 +40,11 @@ public final class LineNumber implements Cloneable, Node {
/** Program Counter (PC) corresponds to line */
private int startPc;
/** number in source file */
/** Number in source file */
private int lineNumber;
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -36,7 +36,7 @@ import jdk.xml.internal.SecuritySupport;
*
* @see Code
* @see LineNumber
* @LastModified: May 2021
* @LastModified: Sept 2025
*/
public final class LineNumberTable extends Attribute implements Iterable<LineNumber> {
@ -44,7 +44,7 @@ public final class LineNumberTable extends Attribute implements Iterable<LineNum
private LineNumber[] lineNumberTable; // Table of line/numbers pairs
/**
* Construct object from input stream.
* Constructs a new instance from a data input stream.
*
* @param nameIndex Index of name
* @param length Content length in bytes
@ -61,13 +61,12 @@ public final class LineNumberTable extends Attribute implements Iterable<LineNum
}
}
/*
/**
* 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) {
@ -76,9 +75,11 @@ public final class LineNumberTable extends Attribute implements Iterable<LineNum
Args.requireU2(this.lineNumberTable.length, "lineNumberTable.length");
}
/*
* Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
* physical copy.
/**
* 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());
@ -190,7 +191,7 @@ public final class LineNumberTable extends Attribute implements Iterable<LineNum
* @param lineNumberTable the line number entries for this table
*/
public void setLineNumberTable(final LineNumber[] lineNumberTable) {
this.lineNumberTable = lineNumberTable;
this.lineNumberTable = lineNumberTable != null ? lineNumberTable : LineNumber.EMPTY_ARRAY;
}
/**

View File

@ -40,10 +40,12 @@ import com.sun.org.apache.bcel.internal.util.Args;
*/
public class LocalVariableTable extends Attribute implements Iterable<LocalVariable> {
private static final LocalVariable[] EMPTY_ARRAY = {};
private LocalVariable[] localVariableTable; // variables
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
@ -68,7 +70,7 @@ public class LocalVariableTable extends Attribute implements Iterable<LocalVaria
*/
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 : LocalVariable.EMPTY_ARRAY;
this.localVariableTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY;
Args.requireU2(this.localVariableTable.length, "localVariableTable.length");
}
@ -167,7 +169,7 @@ public class LocalVariableTable extends Attribute implements Iterable<LocalVaria
}
public final int getTableLength() {
return localVariableTable == null ? 0 : localVariableTable.length;
return localVariableTable.length;
}
@Override
@ -176,7 +178,7 @@ public class LocalVariableTable extends Attribute implements Iterable<LocalVaria
}
public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
this.localVariableTable = localVariableTable;
this.localVariableTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY;
}
/**

View File

@ -63,14 +63,14 @@ import com.sun.org.apache.bcel.internal.util.Args;
*/
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);
}
@ -97,7 +97,6 @@ public class LocalVariableTypeTable extends Attribute implements Iterable<LocalV
@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);
@ -119,7 +118,6 @@ public class LocalVariableTypeTable extends Attribute implements Iterable<LocalV
return variable;
}
}
return null;
}
@ -137,7 +135,7 @@ public class LocalVariableTypeTable extends Attribute implements Iterable<LocalV
}
public final void setLocalVariableTable(final LocalVariable[] localVariableTable) {
this.localVariableTypeTable = localVariableTable;
this.localVariableTypeTable = localVariableTable != null ? localVariableTable : EMPTY_ARRAY;
}
/**
@ -146,15 +144,12 @@ public class LocalVariableTypeTable extends Attribute implements Iterable<LocalV
@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

@ -40,42 +40,34 @@ public final class Method extends FieldOrMethod {
*/
public static final Method[] EMPTY_ARRAY = {};
private static BCELComparator bcelComparator = new BCELComparator() {
private static BCELComparator<Method> bcelComparator = new BCELComparator<Method>() {
@Override
public boolean equals(final Object o1, final Object o2) {
final Method THIS = (Method) o1;
final Method THAT = (Method) o2;
return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature());
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 Object o) {
final Method THIS = (Method) o;
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
public int hashCode(final Method o) {
return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
}
};
/**
* Empty array.
* @return Comparison strategy object.
*/
static final Method[] EMPTY_METHOD_ARRAY = {};
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
public static BCELComparator<Method> getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
* @param comparator Comparison strategy object.
*/
public static void setComparator(final BCELComparator comparator) {
public static void setComparator(final BCELComparator<Method> comparator) {
bcelComparator = comparator;
}
// annotations defined on the parameters of a method
/** Annotations defined on the parameters of a method. */
private ParameterAnnotationEntry[] parameterAnnotationEntries;
/**
@ -85,7 +77,7 @@ public final class Method extends FieldOrMethod {
}
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
@ -142,7 +134,7 @@ public final class Method extends FieldOrMethod {
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
return obj instanceof Method && bcelComparator.equals(this, (Method) obj);
}
/**
@ -189,7 +181,7 @@ public final class Method extends FieldOrMethod {
}
/**
* @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code atribute.
* @return LocalVariableTable of code attribute if any, i.e. the call is forwarded to the Code attribute.
*/
public LocalVariableTable getLocalVariableTable() {
final Code code = getCode();
@ -199,6 +191,19 @@ public final class Method extends FieldOrMethod {
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
@ -218,7 +223,7 @@ public final class Method extends FieldOrMethod {
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the method's name XOR
* Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR
* signature.
*
* @see Object#hashCode()

View File

@ -29,6 +29,9 @@ 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>
@ -46,7 +49,7 @@ public class MethodParameter implements Cloneable, Node {
}
/**
* Construct object from input stream.
* Constructs an instance from a DataInput.
*
* @param input Input stream
* @throws IOException if an I/O error occurs.
@ -75,7 +78,7 @@ public class MethodParameter implements Cloneable, Node {
}
/**
* Dump object to file stream on binary format.
* Dumps object to file stream on binary format.
*
* @param file Output file stream
* @throws IOException if an I/O error occurs.
@ -94,7 +97,10 @@ public class MethodParameter implements Cloneable, Node {
}
/**
* Returns the name of the parameter.
* 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) {

View File

@ -42,13 +42,12 @@ public class MethodParameters extends Attribute implements Iterable<MethodParame
/**
* Empty array.
*/
private static final MethodParameter[] EMPTY_METHOD_PARAMETER_ARRAY = {};
private static final MethodParameter[] EMPTY_ARRAY = {};
private MethodParameter[] parameters = EMPTY_METHOD_PARAMETER_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++) {
@ -65,7 +64,6 @@ public class MethodParameters extends Attribute implements Iterable<MethodParame
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;
@ -96,6 +94,6 @@ public class MethodParameters extends Attribute implements Iterable<MethodParame
}
public void setParameters(final MethodParameter[] parameters) {
this.parameters = parameters;
this.parameters = parameters != null ? parameters : EMPTY_ARRAY;
}
}

View File

@ -44,19 +44,27 @@ public final class Module extends Attribute {
*/
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 final int moduleVersionIndex;
private ModuleRequires[] requiresTable;
private ModuleExports[] exportsTable;
private ModuleOpens[] opensTable;
private final int usesCount;
private final int[] usesIndex;
private ModuleProvides[] providesTable;
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
@ -113,8 +121,6 @@ public final class Module extends Attribute {
v.visitModule(this);
}
// TODO add more getters and setters?
/**
* @return deep copy of this attribute
*/
@ -186,6 +192,25 @@ public final class Module extends Attribute {
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
@ -210,6 +235,31 @@ public final class Module extends Attribute {
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.
*/
@ -218,9 +268,9 @@ public final class Module extends Attribute {
final ConstantPool cp = super.getConstantPool();
final StringBuilder buf = new StringBuilder();
buf.append("Module:\n");
buf.append(" name: ").append(Utility.pathToPackage(cp.getConstantString(moduleNameIndex, Const.CONSTANT_Module))).append("\n");
buf.append(" name: ").append(Utility.pathToPackage(getModuleName(cp))).append("\n");
buf.append(" flags: ").append(String.format("%04x", moduleFlags)).append("\n");
final String version = moduleVersionIndex == 0 ? "0" : cp.getConstantString(moduleVersionIndex, Const.CONSTANT_Utf8);
final String version = getVersion(cp);
buf.append(" version: ").append(version).append("\n");
buf.append(" requires(").append(requiresTable.length).append("):\n");
@ -240,8 +290,8 @@ public final class Module extends Attribute {
buf.append(" uses(").append(usesIndex.length).append("):\n");
for (final int index : usesIndex) {
final String className = cp.getConstantString(index, Const.CONSTANT_Class);
buf.append(" ").append(Utility.compactClassName(className, false)).append("\n");
final String className = getClassNameAtIndex(cp, index, true);
buf.append(" ").append(className).append("\n");
}
buf.append(" provides(").append(providesTable.length).append("):\n");

View File

@ -36,13 +36,17 @@ import com.sun.org.apache.bcel.internal.Const;
*/
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
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort
@ -68,8 +72,6 @@ public final class ModuleExports implements Cloneable, Node {
v.visitModuleExports(this);
}
// TODO add more getters and setters?
/**
* @return deep copy of this object
*/
@ -97,6 +99,39 @@ public final class ModuleExports implements Cloneable, Node {
}
}
/**
* 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
*/
@ -110,13 +145,13 @@ public final class ModuleExports implements Cloneable, Node {
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String packageName = constantPool.constantToString(exportsIndex, Const.CONSTANT_Package);
buf.append(Utility.compactClassName(packageName, false));
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 = constantPool.getConstantString(index, Const.CONSTANT_Module);
buf.append(" ").append(Utility.compactClassName(moduleName, false)).append("\n");
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

@ -39,7 +39,7 @@ public final class ModuleMainClass extends Attribute {
private int mainClassIndex;
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes

View File

@ -36,13 +36,17 @@ import com.sun.org.apache.bcel.internal.Const;
*/
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
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort
@ -68,8 +72,6 @@ public final class ModuleOpens implements Cloneable, Node {
v.visitModuleOpens(this);
}
// TODO add more getters and setters?
/**
* @return deep copy of this object
*/
@ -97,6 +99,39 @@ public final class ModuleOpens implements Cloneable, Node {
}
}
/**
* 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
*/
@ -110,13 +145,13 @@ public final class ModuleOpens implements Cloneable, Node {
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String packageName = constantPool.constantToString(opensIndex, Const.CONSTANT_Package);
buf.append(Utility.compactClassName(packageName, false));
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 = constantPool.getConstantString(index, Const.CONSTANT_Module);
buf.append(" ").append(Utility.compactClassName(moduleName, false)).append("\n");
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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -27,20 +27,21 @@ 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: Feb 2023
* @LastModified: Sept 2025
*/
public final class ModulePackages extends Attribute {
private int[] packageIndexTable;
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
@ -65,7 +66,7 @@ public final class ModulePackages extends Attribute {
*/
public ModulePackages(final int nameIndex, final int length, final int[] packageIndexTable, final ConstantPool constantPool) {
super(Const.ATTR_MODULE_PACKAGES, nameIndex, length, constantPool);
this.packageIndexTable = packageIndexTable != null ? packageIndexTable : Const.EMPTY_INT_ARRAY;
this.packageIndexTable = Utils.createEmptyArrayIfNull(packageIndexTable);
Args.requireU2(this.packageIndexTable.length, "packageIndexTable.length");
}
@ -145,7 +146,7 @@ public final class ModulePackages extends Attribute {
* @param packageIndexTable the list of package indexes Also redefines number_of_packages according to table length.
*/
public void setPackageIndexTable(final int[] packageIndexTable) {
this.packageIndexTable = packageIndexTable != null ? packageIndexTable : Const.EMPTY_INT_ARRAY;
this.packageIndexTable = Utils.createEmptyArrayIfNull(packageIndexTable);
}
/**

View File

@ -36,12 +36,20 @@ import com.sun.org.apache.bcel.internal.Const;
*/
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
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort
@ -66,8 +74,6 @@ public final class ModuleProvides implements Cloneable, Node {
v.visitModuleProvides(this);
}
// TODO add more getters and setters?
/**
* @return deep copy of this object
*/
@ -94,6 +100,31 @@ public final class ModuleProvides implements Cloneable, Node {
}
}
/**
* 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
*/
@ -107,12 +138,12 @@ public final class ModuleProvides implements Cloneable, Node {
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String interfaceName = constantPool.constantToString(providesIndex, Const.CONSTANT_Class);
buf.append(Utility.compactClassName(interfaceName, false));
final String interfaceName = getInterfaceName(constantPool);
buf.append(interfaceName);
buf.append(", with(").append(providesWithCount).append("):\n");
for (final int index : providesWithIndex) {
final String className = constantPool.getConstantString(index, Const.CONSTANT_Class);
buf.append(" ").append(Utility.compactClassName(className, false)).append("\n");
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

@ -41,7 +41,7 @@ public final class ModuleRequires implements Cloneable, Node {
private final int requiresVersionIndex; // either 0 or points to CONSTANT_Utf8_info
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O Exception occurs in readUnsignedShort
@ -63,8 +63,6 @@ public final class ModuleRequires implements Cloneable, Node {
v.visitModuleRequires(this);
}
// TODO add more getters and setters?
/**
* @return deep copy of this object
*/
@ -89,6 +87,35 @@ public final class ModuleRequires implements Cloneable, Node {
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
*/
@ -102,10 +129,10 @@ public final class ModuleRequires implements Cloneable, Node {
*/
public String toString(final ConstantPool constantPool) {
final StringBuilder buf = new StringBuilder();
final String moduleName = constantPool.constantToString(requiresIndex, Const.CONSTANT_Module);
buf.append(Utility.compactClassName(moduleName, false));
final String moduleName = getModuleName(constantPool);
buf.append(moduleName);
buf.append(", ").append(String.format("%04x", requiresFlags));
final String version = requiresVersionIndex == 0 ? "0" : constantPool.getConstantString(requiresVersionIndex, Const.CONSTANT_Utf8);
final String version = getVersion(constantPool);
buf.append(", ").append(version);
return buf.toString();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -27,6 +27,7 @@ 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
@ -34,14 +35,14 @@ import com.sun.org.apache.bcel.internal.util.Args;
* ClassFile structure.
*
* @see Attribute
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public final class NestMembers extends Attribute {
private int[] classes;
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool
* @param length Content length in bytes
@ -66,7 +67,7 @@ public final class NestMembers extends Attribute {
*/
public NestMembers(final int nameIndex, final int length, final int[] classes, final ConstantPool constantPool) {
super(Const.ATTR_NEST_MEMBERS, nameIndex, length, constantPool);
this.classes = classes != null ? classes : Const.EMPTY_INT_ARRAY;
this.classes = Utils.createEmptyArrayIfNull(classes);
Args.requireU2(this.classes.length, "classes.length");
}
@ -146,7 +147,7 @@ public final class NestMembers extends Attribute {
* @param classes the list of class indexes Also redefines number_of_classes according to table length.
*/
public void setClasses(final int[] classes) {
this.classes = classes != null ? classes : Const.EMPTY_INT_ARRAY;
this.classes = Utils.createEmptyArrayIfNull(classes);
}
/**

View File

@ -26,5 +26,5 @@ package com.sun.org.apache.bcel.internal.classfile;
*/
public interface Node {
void accept(Visitor obj);
void accept(Visitor visitor);
}

View File

@ -38,7 +38,7 @@ public final class PMGClass extends Attribute {
private int pmgIndex;
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes

View File

@ -37,22 +37,28 @@ public class ParameterAnnotationEntry implements Node {
static final ParameterAnnotationEntry[] EMPTY_ARRAY = {};
public static ParameterAnnotationEntry[] createParameterAnnotationEntries(final Attribute[] attrs) {
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<>(attrs.length);
for (final Attribute attribute : attrs) {
final List<ParameterAnnotationEntry> accumulatedAnnotations = new ArrayList<>(attributes.length);
for (final Attribute attribute : attributes) {
if (attribute instanceof ParameterAnnotations) {
final ParameterAnnotations runtimeAnnotations = (ParameterAnnotations) attribute;
Collections.addAll(accumulatedAnnotations, runtimeAnnotations.getParameterAnnotationEntries());
final ParameterAnnotationEntry[] parameterAnnotationEntries = runtimeAnnotations.getParameterAnnotationEntries();
if (parameterAnnotationEntries != null) {
Collections.addAll(accumulatedAnnotations, parameterAnnotationEntries);
}
}
}
return accumulatedAnnotations.toArray(ParameterAnnotationEntry.EMPTY_ARRAY);
return accumulatedAnnotations.toArray(EMPTY_ARRAY);
}
private final AnnotationEntry[] annotationTable;
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param input Input stream
* @throws IOException if an I/O error occurs.

View File

@ -34,10 +34,14 @@ import java.util.stream.Stream;
*/
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
@ -55,6 +59,8 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable
}
/**
* 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
@ -120,6 +126,6 @@ public abstract class ParameterAnnotations extends Attribute implements Iterable
* @param parameterAnnotationTable the entries to set in this parameter annotation
*/
public final void setParameterAnnotationTable(final ParameterAnnotationEntry[] parameterAnnotationTable) {
this.parameterAnnotationTable = 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

@ -28,13 +28,15 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* represents an annotation that is represented in the class file but is not provided to the JVM.
* 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
@ -46,7 +48,9 @@ public class RuntimeInvisibleAnnotations extends Annotations {
}
/**
* @return deep copy of this attribute
* Creates a deep copy of this attribute.
*
* @return deep copy of this attribute.
*/
@Override
public Attribute copy(final ConstantPool constantPool) {

View File

@ -34,6 +34,8 @@ import com.sun.org.apache.bcel.internal.Const;
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

View File

@ -28,13 +28,15 @@ import java.io.IOException;
import com.sun.org.apache.bcel.internal.Const;
/**
* represents an annotation that is represented in the class file and is provided to the JVM.
* 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
@ -46,7 +48,9 @@ public class RuntimeVisibleAnnotations extends Annotations {
}
/**
* @return deep copy of this attribute
* Creates a deep copy of this attribute.
*
* @return deep copy of this attribute.
*/
@Override
public Attribute copy(final ConstantPool constantPool) {

View File

@ -34,6 +34,8 @@ import com.sun.org.apache.bcel.internal.Const;
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

View File

@ -110,7 +110,7 @@ public final class Signature extends Attribute {
if ((ch = in.read()) == -1) {
throw new IllegalArgumentException("Illegal signature: " + in.getData() + " no ident, reaching EOF");
}
// System.out.println("return from ident:" + (char)ch);
// System.out.println("return from ident:" + (char) ch);
if (!identStart(ch)) {
final StringBuilder buf2 = new StringBuilder();
int count = 1;
@ -128,7 +128,7 @@ public final class Signature extends Attribute {
buf.append(buf2);
ch = in.read();
in.unread();
// System.out.println("so far:" + buf2 + ":next:" +(char)ch);
// System.out.println("so far:" + buf2 + ":next:" +(char) ch);
} else {
for (int i = 0; i < count; i++) {
in.unread();
@ -141,10 +141,10 @@ public final class Signature extends Attribute {
do {
buf2.append((char) ch);
ch = in.read();
// System.out.println("within ident:"+ (char)ch);
// 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);
// System.out.println("regular return ident:"+ (char) ch + ":" + buf2);
if (ch != -1) {
in.unread();
}
@ -160,7 +160,7 @@ public final class Signature extends Attribute {
private int signatureIndex;
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes

View File

@ -54,7 +54,7 @@ public class SimpleElementValue extends ElementValue {
dos.writeShort(getIndex());
break;
default:
throw new ClassFormatException("SimpleElementValue doesnt know how to write out type " + type);
throw new ClassFormatException("SimpleElementValue doesn't know how to write out type " + type);
}
}
@ -67,7 +67,7 @@ public class SimpleElementValue extends ElementValue {
public boolean getValueBoolean() {
if (super.getType() != PRIMITIVE_BOOLEAN) {
throw new IllegalStateException("Dont call getValueBoolean() on a non BOOLEAN ElementValue");
throw new IllegalStateException("Don't call getValueBoolean() on a non BOOLEAN ElementValue");
}
final ConstantInteger bo = (ConstantInteger) super.getConstantPool().getConstant(getIndex());
return bo.getBytes() != 0;
@ -75,21 +75,21 @@ public class SimpleElementValue extends ElementValue {
public byte getValueByte() {
if (super.getType() != PRIMITIVE_BYTE) {
throw new IllegalStateException("Dont call getValueByte() on a non BYTE ElementValue");
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("Dont call getValueChar() on a non CHAR ElementValue");
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("Dont call getValueDouble() on a non DOUBLE ElementValue");
throw new IllegalStateException("Don't call getValueDouble() on a non DOUBLE ElementValue");
}
final ConstantDouble d = (ConstantDouble) super.getConstantPool().getConstant(getIndex());
return d.getBytes();
@ -97,7 +97,7 @@ public class SimpleElementValue extends ElementValue {
public float getValueFloat() {
if (super.getType() != PRIMITIVE_FLOAT) {
throw new IllegalStateException("Dont call getValueFloat() on a non FLOAT ElementValue");
throw new IllegalStateException("Don't call getValueFloat() on a non FLOAT ElementValue");
}
final ConstantFloat f = (ConstantFloat) super.getConstantPool().getConstant(getIndex());
return f.getBytes();
@ -105,14 +105,14 @@ public class SimpleElementValue extends ElementValue {
public int getValueInt() {
if (super.getType() != PRIMITIVE_INT) {
throw new IllegalStateException("Dont call getValueInt() on a non INT ElementValue");
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("Dont call getValueLong() on a non LONG ElementValue");
throw new IllegalStateException("Don't call getValueLong() on a non LONG ElementValue");
}
final ConstantLong j = (ConstantLong) super.getConstantPool().getConstant(getIndex());
return j.getBytes();
@ -120,7 +120,7 @@ public class SimpleElementValue extends ElementValue {
public short getValueShort() {
if (super.getType() != PRIMITIVE_SHORT) {
throw new IllegalStateException("Dont call getValueShort() on a non SHORT ElementValue");
throw new IllegalStateException("Don't call getValueShort() on a non SHORT ElementValue");
}
final ConstantInteger s = (ConstantInteger) super.getConstantPool().getConstant(getIndex());
return (short) s.getBytes();
@ -128,7 +128,7 @@ public class SimpleElementValue extends ElementValue {
public String getValueString() {
if (super.getType() != STRING) {
throw new IllegalStateException("Dont call getValueString() on a non STRING ElementValue");
throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue");
}
return super.getConstantPool().getConstantUtf8(getIndex()).getBytes();
}

View File

@ -40,7 +40,7 @@ public final class SourceFile extends Attribute {
private int sourceFileIndex;
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -30,8 +30,8 @@ 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="http://java.sun.com/j2me/"> Java 2 Micro Edition</a> (J2ME). This attribute is used by the
* <a href="http://java.sun.com/products/cldc/">KVM</a> and contained within the Code attribute of a method. See CLDC
* <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>
@ -46,14 +46,14 @@ import com.sun.org.apache.bcel.internal.util.Args;
* @see Code
* @see StackMapEntry
* @see StackMapType
* @LastModified: Oct 2020
* @LastModified: Sept 2025
*/
public final class StackMap extends Attribute {
private StackMapEntry[] table; // Table of stack map entries
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index of name
* @param length Content length in bytes

View File

@ -59,7 +59,7 @@ public final class StackMapEntry implements Node, Cloneable {
private ConstantPool constantPool;
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param dataInput Input stream
* @throws IOException if an I/O error occurs.
@ -75,9 +75,7 @@ public final class StackMapEntry implements Node, Cloneable {
} 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) {
byteCodeOffset = dataInput.readUnsignedShort();
} else if (frameType == Const.SAME_FRAME_EXTENDED) {
} 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();
@ -167,7 +165,7 @@ public final class StackMapEntry implements Node, Cloneable {
try {
e = (StackMapEntry) clone();
} catch (final CloneNotSupportedException ex) {
throw new Error("Clone Not Supported");
throw new UnsupportedOperationException("Clone Not Supported", ex);
}
e.typesOfLocals = new StackMapType[typesOfLocals.length];
@ -190,9 +188,7 @@ public final class StackMapEntry implements Node, Cloneable {
} 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) {
file.writeShort(byteCodeOffset);
} else if (frameType == Const.SAME_FRAME_EXTENDED) {
} 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);
@ -232,7 +228,6 @@ public final class StackMapEntry implements Node, Cloneable {
/**
* Calculate stack map entry size
*
*/
int getMapEntrySize() {
if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {

View File

@ -34,9 +34,9 @@ import com.sun.org.apache.bcel.internal.Const;
* @see StackMap
* @see Const
*/
public final class StackMapType implements Cloneable {
public final class StackMapType implements Node, Cloneable {
public static final StackMapType[] EMPTY_ARRAY = {}; // must be public because BCELifier code generator writes calls to it
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
@ -53,7 +53,7 @@ public final class StackMapType implements Cloneable {
}
/**
* Construct object from file stream.
* Constructs object from file stream.
*
* @param file Input stream
* @throws IOException if an I/O error occurs.
@ -66,6 +66,18 @@ public final class StackMapType implements Cloneable {
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);
@ -98,6 +110,15 @@ public final class StackMapType implements Cloneable {
}
}
/**
* 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.
*/
@ -129,7 +150,7 @@ public final class StackMapType implements Cloneable {
if (index < 0) {
return ", class=<unknown>";
}
return ", class=" + constantPool.constantToString(index, Const.CONSTANT_Class);
return ", class=" + getClassName();
}
if (type == Const.ITEM_NewObject) {
return ", offset=" + index;

View File

@ -52,7 +52,7 @@ public final class Synthetic extends Attribute {
}
/**
* Construct object from input stream.
* Constructs object from input stream.
*
* @param nameIndex Index in constant pool to CONSTANT_Utf8
* @param length Content length in bytes

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -43,7 +43,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence;
/**
* Utility functions that do not really belong to any class in particular.
*
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
// @since 6.0 methods are no longer final
public abstract class Utility {
@ -51,7 +51,7 @@ public abstract class Utility {
/**
* Decode characters into bytes. Used by <a href="Utility.html#decode(java.lang.String, boolean)">decode()</a>
*/
private static class JavaReader extends FilterReader {
private static final class JavaReader extends FilterReader {
public JavaReader(final Reader in) {
super(in);
@ -88,10 +88,10 @@ public abstract class Utility {
}
/**
* Encode bytes into valid java identifier characters. Used by
* Encode bytes into valid Java identifier characters. Used by
* <a href="Utility.html#encode(byte[], boolean)">encode()</a>
*/
private static class JavaWriter extends FilterWriter {
private static final class JavaWriter extends FilterWriter {
public JavaWriter(final Writer out) {
super(out);
@ -437,7 +437,9 @@ public abstract class Utility {
case Const.NEW:
case Const.CHECKCAST:
buf.append("\t");
//$FALL-THROUGH$
index = bytes.readUnsignedShort();
buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : "");
break;
case Const.INSTANCEOF:
index = bytes.readUnsignedShort();
buf.append("\t<").append(constantPool.constantToString(index, Const.CONSTANT_Class)).append(">").append(verbose ? " (" + index + ")" : "");
@ -864,7 +866,7 @@ public abstract class Utility {
// Skip any type arguments to read argument declarations between '(' and ')'
index = signature.indexOf('(') + 1;
if (index <= 0) {
throw new ClassFormatException("Invalid method signature: " + signature);
throw new InvalidMethodSignatureException(signature);
}
while (signature.charAt(index) != ')') {
vec.add(typeSignatureToString(signature.substring(index), chopit));
@ -872,7 +874,7 @@ public abstract class Utility {
index += unwrap(CONSUMER_CHARS); // update position
}
} catch (final StringIndexOutOfBoundsException e) { // Should never occur
throw new ClassFormatException("Invalid method signature: " + signature, e);
throw new InvalidMethodSignatureException(signature, e);
}
return vec.toArray(Const.EMPTY_STRING_ARRAY);
}
@ -903,11 +905,11 @@ public abstract class Utility {
// Read return type after ')'
index = signature.lastIndexOf(')') + 1;
if (index <= 0) {
throw new ClassFormatException("Invalid method signature: " + signature);
throw new InvalidMethodSignatureException(signature);
}
type = typeSignatureToString(signature.substring(index), chopit);
} catch (final StringIndexOutOfBoundsException e) { // Should never occur
throw new ClassFormatException("Invalid method signature: " + signature, e);
throw new InvalidMethodSignatureException(signature, e);
}
return type;
}
@ -959,7 +961,7 @@ public abstract class Utility {
// Skip any type arguments to read argument declarations between '(' and ')'
index = signature.indexOf('(') + 1;
if (index <= 0) {
throw new ClassFormatException("Invalid method signature: " + signature);
throw new InvalidMethodSignatureException(signature);
}
while (signature.charAt(index) != ')') {
final String paramType = typeSignatureToString(signature.substring(index), chopit);
@ -985,7 +987,7 @@ public abstract class Utility {
// Read return type after ')'
type = typeSignatureToString(signature.substring(index), chopit);
} catch (final StringIndexOutOfBoundsException e) { // Should never occur
throw new ClassFormatException("Invalid method signature: " + signature, e);
throw new InvalidMethodSignatureException(signature, e);
}
// ignore any throws information in the signature
if (buf.length() > 1) {
@ -1172,7 +1174,7 @@ public abstract class Utility {
type = typeParams + typeSignaturesToString(signature.substring(index), chopit, ')');
index += unwrap(CONSUMER_CHARS); // update position
// add return type
type = type + typeSignatureToString(signature.substring(index), chopit);
type += typeSignatureToString(signature.substring(index), chopit);
index += unwrap(CONSUMER_CHARS); // update position
// ignore any throws information in the signature
return type;
@ -1237,12 +1239,12 @@ public abstract class Utility {
int index;
try {
if (signature.charAt(0) != '(') {
throw new ClassFormatException("Invalid method signature: " + signature);
throw new InvalidMethodSignatureException(signature);
}
index = signature.lastIndexOf(')') + 1;
return typeOfSignature(signature.substring(index));
} catch (final StringIndexOutOfBoundsException e) {
throw new ClassFormatException("Invalid method signature: " + signature, e);
throw new InvalidMethodSignatureException(signature, e);
}
}
@ -1286,10 +1288,10 @@ public abstract class Utility {
case '*':
return typeOfSignature(signature.substring(1));
default:
throw new ClassFormatException("Invalid method signature: " + signature);
throw new InvalidMethodSignatureException(signature);
}
} catch (final StringIndexOutOfBoundsException e) {
throw new ClassFormatException("Invalid method signature: " + signature, e);
throw new InvalidMethodSignatureException(signature, e);
}
}
@ -1469,8 +1471,8 @@ public abstract class Utility {
} else {
type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
// update our consumed count by the number of characters the for type argument
consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
wrap(Utility.CONSUMER_CHARS, consumedChars);
consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
wrap(CONSUMER_CHARS, consumedChars);
}
// are there more TypeArguments?
@ -1490,8 +1492,8 @@ public abstract class Utility {
} else {
type.append(typeSignatureToString(signature.substring(consumedChars), chopit));
// update our consumed count by the number of characters the for type argument
consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
wrap(Utility.CONSUMER_CHARS, consumedChars);
consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
wrap(CONSUMER_CHARS, consumedChars);
}
}
@ -1508,14 +1510,14 @@ public abstract class Utility {
// update our consumed count by the number of characters the for type argument
// note that this count includes the "L" we added, but that is ok
// as it accounts for the "." we didn't consume
consumedChars = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
wrap(Utility.CONSUMER_CHARS, consumedChars);
consumedChars = unwrap(CONSUMER_CHARS) + consumedChars;
wrap(CONSUMER_CHARS, consumedChars);
return type.toString();
}
if (signature.charAt(consumedChars) != ';') {
throw new ClassFormatException("Invalid signature: " + signature);
}
wrap(Utility.CONSUMER_CHARS, consumedChars + 1); // remove final ";"
wrap(CONSUMER_CHARS, consumedChars + 1); // remove final ";"
return type.toString();
}
case 'S':
@ -1536,9 +1538,9 @@ public abstract class Utility {
// The rest of the string denotes a '<field_type>'
type = typeSignatureToString(signature.substring(n), chopit);
// corrected concurrent private static field acess
// Utility.consumed_chars += consumed_chars; is replaced by:
final int temp = unwrap(Utility.CONSUMER_CHARS) + consumedChars;
wrap(Utility.CONSUMER_CHARS, temp);
// consumed_chars += consumed_chars; is replaced by:
final int temp = unwrap(CONSUMER_CHARS) + consumedChars;
wrap(CONSUMER_CHARS, temp);
return type + brackets.toString();
}
case 'V':
@ -1552,11 +1554,11 @@ public abstract class Utility {
}
private static int unwrap(final ThreadLocal<Integer> tl) {
return tl.get();
return tl.get().intValue();
}
private static void wrap(final ThreadLocal<Integer> tl, final int value) {
tl.set(value);
tl.set(Integer.valueOf(value));
}
}

View File

@ -217,11 +217,32 @@ public interface Visitor {
*/
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);
@ -230,7 +251,18 @@ public interface Visitor {
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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -28,12 +28,12 @@ import com.sun.org.apache.bcel.internal.ExceptionConst;
* <PRE>
* Stack: ..., arrayref -&gt; ..., length
* </PRE>
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public class ARRAYLENGTH extends Instruction implements ExceptionThrower, StackProducer, StackConsumer /* since 6.0 */ {
/**
* Get length of array
* Gets length of array
*/
public ARRAYLENGTH() {
super(com.sun.org.apache.bcel.internal.Const.ARRAYLENGTH, (short) 1);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -28,8 +28,10 @@ import com.sun.org.apache.bcel.internal.ExceptionConst;
* <PRE>
* Stack: ..., objectref -&gt; objectref
* </PRE>
*
* @LastModified: Sept 2025
*/
public class ATHROW extends Instruction implements UnconditionalBranch, ExceptionThrower {
public class ATHROW extends Instruction implements UnconditionalBranch, ExceptionThrower, StackConsumer {
/**
* Throw exception
@ -48,6 +50,7 @@ public class ATHROW extends Instruction implements UnconditionalBranch, Exceptio
public void accept(final Visitor v) {
v.visitUnconditionalBranch(this);
v.visitExceptionThrower(this);
v.visitStackConsumer(this);
v.visitATHROW(this);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -28,6 +28,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry;
import com.sun.org.apache.bcel.internal.classfile.Attribute;
@ -37,10 +38,11 @@ import com.sun.org.apache.bcel.internal.classfile.RuntimeInvisibleAnnotations;
import com.sun.org.apache.bcel.internal.classfile.RuntimeInvisibleParameterAnnotations;
import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleAnnotations;
import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleParameterAnnotations;
import jdk.xml.internal.Utils;
/**
* @since 6.0
* @LastModified: Jan 2020
* @LastModified: Sept 2025
*/
public class AnnotationEntryGen {
@ -53,7 +55,7 @@ public class AnnotationEntryGen {
* @param annotationEntryGens An array of AnnotationGen objects
*/
static Attribute[] getAnnotationAttributes(final ConstantPoolGen cp, final AnnotationEntryGen[] annotationEntryGens) {
if (annotationEntryGens.length == 0) {
if (annotationEntryGens == null && annotationEntryGens.length == 0) {
return Attribute.EMPTY_ARRAY;
}
@ -255,11 +257,7 @@ public class AnnotationEntryGen {
}
private List<ElementValuePairGen> copyValues(final ElementValuePair[] in, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
final List<ElementValuePairGen> out = new ArrayList<>();
for (final ElementValuePair nvp : in) {
out.add(new ElementValuePairGen(nvp, cpool, copyPoolEntries));
}
return out;
return Utils.streamOfIfNonNull(in).map(nvp -> new ElementValuePairGen(nvp, cpool, copyPoolEntries)).collect(Collectors.toList());
}
public void dump(final DataOutputStream dos) throws IOException {
@ -286,18 +284,20 @@ public class AnnotationEntryGen {
}
public final String getTypeName() {
return getTypeSignature();// BCELBUG: Should I use this instead?
return getTypeSignature(); // BCELBUG: Should I use this instead?
// Utility.signatureToString(getTypeSignature());
}
public final String getTypeSignature() {
// ConstantClass c = (ConstantClass)cpool.getConstant(typeIndex);
// ConstantClass c = (ConstantClass) cpool.getConstant(typeIndex);
final ConstantUtf8 utf8 = (ConstantUtf8) cpool.getConstant(typeIndex/* c.getNameIndex() */);
return utf8.getBytes();
}
/**
* Returns list of ElementNameValuePair objects
* Returns list of ElementNameValuePair objects.
*
* @return list of ElementNameValuePair objects.
*/
public List<ElementValuePairGen> getValues() {
return evs;

View File

@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -25,12 +24,15 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import com.sun.org.apache.bcel.internal.classfile.ArrayElementValue;
import com.sun.org.apache.bcel.internal.classfile.ElementValue;
import jdk.xml.internal.Utils;
/**
* @since 6.0
* @LastModified: Sept 2025
*/
public class ArrayElementValueGen extends ElementValueGen {
// J5TODO: Should we make this an array or a list? A list would be easier to
@ -46,7 +48,7 @@ public class ArrayElementValueGen extends ElementValueGen {
evalues = new ArrayList<>();
final ElementValue[] in = value.getElementValuesArray();
for (final ElementValue element : in) {
evalues.add(ElementValueGen.copy(element, cpool, copyPoolEntries));
evalues.add(copy(element, cpool, copyPoolEntries));
}
}
@ -55,15 +57,12 @@ public class ArrayElementValueGen extends ElementValueGen {
evalues = new ArrayList<>();
}
public ArrayElementValueGen(final int type, final ElementValue[] datums, final ConstantPoolGen cpool) {
public ArrayElementValueGen(final int type, final ElementValue[] elementValues, final ConstantPoolGen cpool) {
super(type, cpool);
if (type != ARRAY) {
throw new IllegalArgumentException("Only element values of type array can be built with this ctor - type specified: " + type);
}
this.evalues = new ArrayList<>();
for (final ElementValue datum : datums) {
evalues.add(ElementValueGen.copy(datum, cpool, true));
}
this.evalues = Utils.streamOfIfNonNull(elementValues).map(e -> copy(e, cpool, true)).collect(Collectors.toList());
}
public void addElement(final ElementValueGen gen) {

View File

@ -1,6 +1,5 @@
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -24,6 +23,8 @@ import com.sun.org.apache.bcel.internal.Const;
/**
* Denotes array type, such as int[][]
*
* @LastModified: Sept 2025
*/
public final class ArrayType extends ReferenceType {
@ -43,7 +44,7 @@ public final class ArrayType extends ReferenceType {
/**
* Convenience constructor for reference array type, e.g. Object[]
*
* @param className complete name of class (java.lang.String, e.g.)
* @param className complete name of class ({@link String}, for example)
* @param dimensions array dimensions
*/
public ArrayType(final String className, final int dimensions) {
@ -56,6 +57,7 @@ public final class ArrayType extends ReferenceType {
* @param type type of array (may be an array itself)
* @param dimensions array dimensions
*/
@SuppressWarnings("deprecation") //signature
public ArrayType(final Type type, final int dimensions) {
super(Const.T_ARRAY, "<dummy>");
if (dimensions < 1 || dimensions > Const.MAX_BYTE) {
@ -79,7 +81,7 @@ public final class ArrayType extends ReferenceType {
buf.append('[');
}
buf.append(basicType.getSignature());
super.setSignature(buf.toString());
this.signature = buf.toString();
}
/**

View File

@ -63,7 +63,7 @@ public final class BranchHandle extends InstructionHandle {
}
/**
* Set new contents. Old instruction is disposed and may not be used anymore.
* Sets new contents. Old instruction is disposed and may not be used anymore.
*/
@Override // This is only done in order to apply the additional type check; could be merged with super impl.
public void setInstruction(final Instruction i) { // TODO could be package-protected?

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -35,7 +35,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence;
* @see LDC
* @see INVOKEVIRTUAL
*
* @LastModified: Jan 2020
* @LastModified: Sept 2025
*/
public abstract class CPInstruction extends Instruction implements TypedInstruction, IndexedInstruction {
@ -104,7 +104,7 @@ public abstract class CPInstruction extends Instruction implements TypedInstruct
}
/**
* Set the index to constant pool.
* Sets the index to constant pool.
*
* @param index in constant pool.
*/

View File

@ -48,12 +48,12 @@ public class ClassElementValueGen extends ElementValueGen {
}
protected ClassElementValueGen(final int typeIdx, final ConstantPoolGen cpool) {
super(ElementValueGen.CLASS, cpool);
super(CLASS, cpool);
this.idx = typeIdx;
}
public ClassElementValueGen(final ObjectType t, final ConstantPoolGen cpool) {
super(ElementValueGen.CLASS, cpool);
super(CLASS, cpool);
// this.idx = cpool.addClass(t);
idx = cpool.addUtf8(t.getSignature());
}
@ -67,9 +67,9 @@ public class ClassElementValueGen extends ElementValueGen {
public String getClassString() {
final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(idx);
return cu8.getBytes();
// ConstantClass c = (ConstantClass)getConstantPool().getConstant(idx);
// ConstantClass c = (ConstantClass) getConstantPool().getConstant(idx);
// ConstantUtf8 utf8 =
// (ConstantUtf8)getConstantPool().getConstant(c.getNameIndex());
// (ConstantUtf8) getConstantPool().getConstant(c.getNameIndex());
// return utf8.getBytes();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -40,40 +40,37 @@ import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.util.BCELComparator;
/**
* Template class for building up a java class. May be initialized with an existing java class (file).
* Template class for building up a java class. May be initialized with an existing Java class (file).
*
* @see JavaClass
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public class ClassGen extends AccessFlags implements Cloneable {
private static BCELComparator bcelComparator = new BCELComparator() {
private static BCELComparator<ClassGen> bcelComparator = new BCELComparator<ClassGen>() {
@Override
public boolean equals(final Object o1, final Object o2) {
final ClassGen THIS = (ClassGen) o1;
final ClassGen THAT = (ClassGen) o2;
return Objects.equals(THIS.getClassName(), THAT.getClassName());
public boolean equals(final ClassGen a, final ClassGen b) {
return a == b || a != null && b != null && Objects.equals(a.getClassName(), b.getClassName());
}
@Override
public int hashCode(final Object o) {
final ClassGen THIS = (ClassGen) o;
return THIS.getClassName().hashCode();
public int hashCode(final ClassGen o) {
return o != null ? Objects.hashCode(o.getClassName()) : 0;
}
};
/**
* @return Comparison strategy object
*/
public static BCELComparator getComparator() {
public static BCELComparator<ClassGen> getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
*/
public static void setComparator(final BCELComparator comparator) {
public static void setComparator(final BCELComparator<ClassGen> comparator) {
bcelComparator = comparator;
}
@ -101,7 +98,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
private List<ClassObserver> observers;
/**
* Initialize with existing class.
* Constructs a new instance from an existing class.
*
* @param clazz JavaClass object (e.g. read from file)
*/
@ -118,15 +115,26 @@ public class ClassGen extends AccessFlags implements Cloneable {
final Attribute[] attributes = clazz.getAttributes();
// J5TODO: Could make unpacking lazy, done on first reference
final AnnotationEntryGen[] annotations = unpackAnnotations(attributes);
Collections.addAll(interfaceList, clazz.getInterfaceNames());
for (final Attribute attribute : attributes) {
if (!(attribute instanceof Annotations)) {
addAttribute(attribute);
final String[] interfaceNames = clazz.getInterfaceNames();
if (interfaceNames != null) {
Collections.addAll(interfaceList, interfaceNames);
}
if (attributes != null) {
for (final Attribute attribute : attributes) {
if (!(attribute instanceof Annotations)) {
addAttribute(attribute);
}
}
}
Collections.addAll(annotationList, annotations);
Collections.addAll(methodList, clazz.getMethods());
Collections.addAll(fieldList, clazz.getFields());
final Method[] methods = clazz.getMethods();
if (methods != null) {
Collections.addAll(methodList, methods);
}
final Field[] fields = clazz.getFields();
if (fields != null) {
Collections.addAll(fieldList, fields);
}
}
/**
@ -242,7 +250,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
}
}
@ -282,7 +290,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
return obj instanceof ClassGen && bcelComparator.equals(this, (ClassGen) obj);
}
// J5TODO: Should we make calling unpackAnnotations() lazy and put it in here?
@ -379,7 +387,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the class name.
* Return value as defined by given BCELComparator strategy. By default return the hash code of the class name.
*
* @see Object#hashCode()
*/
@ -478,7 +486,7 @@ public class ClassGen extends AccessFlags implements Cloneable {
}
/**
* Set major version number of class file, default value is 45 (JDK 1.1)
* Sets major version number of class file, default value is 45 (JDK 1.1)
*
* @param major major version number
*/
@ -492,11 +500,13 @@ public class ClassGen extends AccessFlags implements Cloneable {
public void setMethods(final Method[] methods) {
methodList.clear();
Collections.addAll(methodList, methods);
if (methods != null) {
Collections.addAll(methodList, methods);
}
}
/**
* Set minor version number of class file, default value is 3 (JDK 1.1)
* Sets minor version number of class file, default value is 3 (JDK 1.1)
*
* @param minor minor version number
*/
@ -515,17 +525,19 @@ public class ClassGen extends AccessFlags implements Cloneable {
}
/**
* Look for attributes representing annotations and unpack them.
* Unpacks attributes representing annotations.
*/
private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attrs) {
private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attributes) {
final List<AnnotationEntryGen> annotationGenObjs = new ArrayList<>();
for (final Attribute attr : attrs) {
if (attr instanceof RuntimeVisibleAnnotations) {
final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr;
rva.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false)));
} else if (attr instanceof RuntimeInvisibleAnnotations) {
final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr;
ria.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false)));
if (attributes != null) {
for (final Attribute attr : attributes) {
if (attr instanceof RuntimeVisibleAnnotations) {
final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr;
rva.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false)));
} else if (attr instanceof RuntimeInvisibleAnnotations) {
final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr;
ria.forEach(a -> annotationGenObjs.add(new AnnotationEntryGen(a, getConstantPool(), false)));
}
}
}
return annotationGenObjs.toArray(AnnotationEntryGen.EMPTY_ARRAY);

View File

@ -63,7 +63,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
}
}
@ -81,7 +81,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
}
/**
* Get CodeException object.<BR>
* Gets CodeException object.<BR>
*
* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
* has been called for the instruction list.
@ -120,7 +120,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
}
/*
* Set end of handler
* Sets end of handler
*
* @param endPc End of handled region (inclusive)
*/
@ -130,7 +130,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
}
/*
* Set handler code
* Sets handler code
*
* @param handlerPc Start of handler
*/
@ -140,7 +140,7 @@ public final class CodeExceptionGen implements InstructionTargeter, Cloneable {
}
/*
* Set start of handler
* Sets start of handler
*
* @param startPc Start of handled region (inclusive)
*/

View File

@ -44,7 +44,7 @@ public class ElementValuePairGen {
// Could assert nvp.getNameString() points to the same thing as
// constantPoolGen.getConstant(nvp.getNameIndex())
// if
// (!nvp.getNameString().equals(((ConstantUtf8)constantPoolGen.getConstant(nvp.getNameIndex())).getBytes()))
// (!nvp.getNameString().equals(((ConstantUtf8) constantPoolGen.getConstant(nvp.getNameIndex())).getBytes()))
// {
// throw new IllegalArgumentException("envp buggered");
// }
@ -86,7 +86,7 @@ public class ElementValuePairGen {
}
public final String getNameString() {
// ConstantString cu8 = (ConstantString)constantPoolGen.getConstant(nameIdx);
// ConstantString cu8 = (ConstantString) constantPoolGen.getConstant(nameIdx);
return ((ConstantUtf8) constantPoolGen.getConstant(nameIdx)).getBytes();
}

View File

@ -40,10 +40,8 @@ public class EnumElementValueGen extends ElementValueGen {
public EnumElementValueGen(final EnumElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
super(ENUM_CONSTANT, cpool);
if (copyPoolEntries) {
typeIdx = cpool.addUtf8(value.getEnumTypeString());// was
// addClass(value.getEnumTypeString());
valueIdx = cpool.addUtf8(value.getEnumValueString()); // was
// addString(value.getEnumValueString());
typeIdx = cpool.addUtf8(value.getEnumTypeString()); // was addClass(value.getEnumTypeString());
valueIdx = cpool.addUtf8(value.getEnumValueString()); // was addString(value.getEnumValueString());
} else {
typeIdx = value.getTypeIndex();
valueIdx = value.getValueIndex();
@ -55,7 +53,7 @@ public class EnumElementValueGen extends ElementValueGen {
* This ctor is used for deserialization
*/
protected EnumElementValueGen(final int typeIdx, final int valueIdx, final ConstantPoolGen cpool) {
super(ElementValueGen.ENUM_CONSTANT, cpool);
super(ENUM_CONSTANT, cpool);
if (super.getElementValueType() != ENUM_CONSTANT) {
throw new IllegalArgumentException("Only element values of type enum can be built with this ctor - type specified: " + super.getElementValueType());
}
@ -64,9 +62,9 @@ public class EnumElementValueGen extends ElementValueGen {
}
public EnumElementValueGen(final ObjectType t, final String value, final ConstantPoolGen cpool) {
super(ElementValueGen.ENUM_CONSTANT, cpool);
typeIdx = cpool.addUtf8(t.getSignature());// was addClass(t);
valueIdx = cpool.addUtf8(value);// was addString(value);
super(ENUM_CONSTANT, cpool);
typeIdx = cpool.addUtf8(t.getSignature()); // was addClass(t);
valueIdx = cpool.addUtf8(value); // was addString(value);
}
@Override
@ -90,9 +88,9 @@ public class EnumElementValueGen extends ElementValueGen {
public String getEnumTypeString() {
// Constant cc = getConstantPool().getConstant(typeIdx);
// ConstantClass cu8 =
// (ConstantClass)getConstantPool().getConstant(typeIdx);
// (ConstantClass) getConstantPool().getConstant(typeIdx);
// return
// ((ConstantUtf8)getConstantPool().getConstant(cu8.getNameIndex())).getBytes();
// ((ConstantUtf8) getConstantPool().getConstant(cu8.getNameIndex())).getBytes();
return ((ConstantUtf8) getConstantPool().getConstant(typeIdx)).getBytes();
// return Utility.signatureToString(cu8.getBytes());
}
@ -100,9 +98,9 @@ public class EnumElementValueGen extends ElementValueGen {
public String getEnumValueString() {
return ((ConstantUtf8) getConstantPool().getConstant(valueIdx)).getBytes();
// ConstantString cu8 =
// (ConstantString)getConstantPool().getConstant(valueIdx);
// (ConstantString) getConstantPool().getConstant(valueIdx);
// return
// ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes();
// ((ConstantUtf8) getConstantPool().getConstant(cu8.getStringIndex())).getBytes();
}
public int getTypeIndex() {
@ -118,8 +116,8 @@ public class EnumElementValueGen extends ElementValueGen {
final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(valueIdx);
return cu8.getBytes();
// ConstantString cu8 =
// (ConstantString)getConstantPool().getConstant(valueIdx);
// (ConstantString) getConstantPool().getConstant(valueIdx);
// return
// ((ConstantUtf8)getConstantPool().getConstant(cu8.getStringIndex())).getBytes();
// ((ConstantUtf8) getConstantPool().getConstant(cu8.getStringIndex())).getBytes();
}
}

View File

@ -23,7 +23,7 @@ package com.sun.org.apache.bcel.internal.generic;
/**
* Denote an instruction that may throw a run-time or a linking exception (or both) during execution. This is not quite
* the truth as such; because all instructions may throw an java.lang.VirtualMachineError. These exceptions are omitted.
* the truth as such; because all instructions may throw a {@link VirtualMachineError}. These exceptions are omitted.
*
* The Lava Language Specification specifies exactly which <i>RUN-TIME</i> and which <i>LINKING</i> exceptions each
* instruction may throw which is reflected by the implementers. Due to the structure of the JVM specification, it may

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -40,37 +40,34 @@ import com.sun.org.apache.bcel.internal.util.BCELComparator;
* to a field (which must of course be compatible with to the declared type).
*
* @see Field
* @LastModified: May 2021
* @LastModified: Sept 2025
*/
public class FieldGen extends FieldGenOrMethodGen {
private static BCELComparator bcelComparator = new BCELComparator() {
private static BCELComparator<FieldGen> bcelComparator = new BCELComparator<FieldGen>() {
@Override
public boolean equals(final Object o1, final Object o2) {
final FieldGen THIS = (FieldGen) o1;
final FieldGen THAT = (FieldGen) o2;
return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature());
public boolean equals(final FieldGen a, final FieldGen 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 Object o) {
final FieldGen THIS = (FieldGen) o;
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
public int hashCode(final FieldGen o) {
return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
}
};
/**
* @return Comparison strategy object
* @return Comparison strategy object.
*/
public static BCELComparator getComparator() {
public static BCELComparator<FieldGen> getComparator() {
return bcelComparator;
}
/**
* @param comparator Comparison strategy object
* @param comparator Comparison strategy object.
*/
public static void setComparator(final BCELComparator comparator) {
public static void setComparator(final BCELComparator<FieldGen> comparator) {
bcelComparator = comparator;
}
@ -81,8 +78,8 @@ public class FieldGen extends FieldGenOrMethodGen {
/**
* Instantiate from existing field.
*
* @param field Field object
* @param cp constant pool (must contain the same entries as the field's constant pool)
* @param field Field object.
* @param cp constant pool (must contain the same entries as the field's constant pool).
*/
public FieldGen(final Field field, final ConstantPoolGen cp) {
this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp);
@ -187,11 +184,11 @@ public class FieldGen extends FieldGenOrMethodGen {
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
return obj instanceof FieldGen && bcelComparator.equals(this, (FieldGen) obj);
}
/**
* Get field object after having set up all necessary values.
* Gets field object after having set up all necessary values.
*/
public Field getField() {
final String signature = getSignature();
@ -207,10 +204,7 @@ public class FieldGen extends FieldGenOrMethodGen {
}
public String getInitValue() {
if (value != null) {
return value.toString();
}
return null;
return Objects.toString(value, null);
}
@Override
@ -219,7 +213,7 @@ public class FieldGen extends FieldGenOrMethodGen {
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the field's name XOR
* Return value as defined by given BCELComparator strategy. By default return the hash code of the field's name XOR
* signature.
*
* @see Object#hashCode()
@ -295,7 +289,7 @@ public class FieldGen extends FieldGenOrMethodGen {
}
/**
* Set (optional) initial value of field, otherwise it will be set to null/0/false by the JVM automatically.
* Sets (optional) initial value of field, otherwise it will be set to null/0/false by the JVM automatically.
*/
public void setInitValue(final String str) {
checkType(ObjectType.getInstance("java.lang.String"));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -30,7 +30,7 @@ import com.sun.org.apache.bcel.internal.classfile.Attribute;
/**
* Super class for FieldGen and MethodGen objects, since they have some methods in common!
*
* @LastModified: May 2021
* @LastModified: Sept 2025
*/
public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAndTyped, Cloneable {
@ -67,8 +67,10 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
super(accessFlags);
}
protected void addAll(final Attribute[] attrs) {
Collections.addAll(attributeList, attrs);
protected void addAll(final Attribute[] attributes) {
if (attributes != null) {
Collections.addAll(attributeList, attributes);
}
}
/**
@ -93,7 +95,7 @@ public abstract class FieldGenOrMethodGen extends AccessFlags implements NamedAn
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
}
}

View File

@ -53,7 +53,6 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass {
* generated by Java 1.5, this answer is sometimes wrong (e.g., if the "clone()" method is called on an
* array). A better idea is to use the {@link #getReferenceType(ConstantPoolGen)} method, which correctly
* distinguishes between class types and array types.
*
*/
@Deprecated
public String getClassName(final ConstantPoolGen cpg) {
@ -89,6 +88,9 @@ public abstract class FieldOrMethod extends CPInstruction implements LoadClass {
if (rt instanceof ObjectType) {
return (ObjectType) rt;
}
if (rt instanceof ArrayType) {
return Type.OBJECT;
}
throw new ClassGenException(rt.getClass().getCanonicalName() + " " + rt.getSignature() + " does not represent an ObjectType");
}

View File

@ -25,7 +25,6 @@ package com.sun.org.apache.bcel.internal.generic;
* <PRE>
* Stack: ... -&gt; ...,
* </PRE>
*
*/
public class ICONST extends Instruction implements ConstantPushInstruction {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -37,7 +37,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence;
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic"> The
* invokedynamic instruction in The Java Virtual Machine Specification</a>
* @since 6.0
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public class INVOKEDYNAMIC extends InvokeInstruction {
@ -104,11 +104,11 @@ public class INVOKEDYNAMIC extends InvokeInstruction {
}
/**
* Since InvokeDynamic doesn't refer to a reference type, just return java.lang.Object, as that is the only type we can
* Since InvokeDynamic doesn't refer to a reference type, just return {@link Object}, as that is the only type we can
* say for sure the reference will be.
*
* @param cpg the ConstantPoolGen used to create the instruction
* @return an ObjectType for java.lang.Object
* @return an ObjectType for {@link Object}
* @since 6.1
*/
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -29,7 +29,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence;
/**
* Abstract super class for all Java byte codes.
*
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public abstract class Instruction implements Cloneable {
@ -461,7 +461,7 @@ public abstract class Instruction implements Cloneable {
public Instruction copy() {
Instruction i = null;
// "Constant" instruction, no need to duplicate
if (InstructionConst.getInstruction(this.getOpcode()) != null) {
if (InstructionConst.getInstruction(getOpcode()) != null) {
i = this;
} else {
try {

View File

@ -170,7 +170,7 @@ public final class InstructionConst {
public static final LocalVariableInstruction ISTORE_2 = new ISTORE(2);
/**
* Get object via its opcode, for immutable instructions like branch instructions entries are set to null.
* Gets object via its opcode, for immutable instructions like branch instructions entries are set to null.
*/
static final Instruction[] INSTRUCTIONS = new Instruction[256];

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -30,11 +30,11 @@ import com.sun.org.apache.bcel.internal.Const;
*
* @see Const
* @see InstructionConst
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public class InstructionFactory {
private static class MethodObject {
private static final class MethodObject {
final Type[] argTypes;
final Type resultType;
@ -53,10 +53,12 @@ public class InstructionFactory {
private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer";
// N.N. These must agree with the order of Constants.T_CHAR through T_LONG
private static final String[] shortNames = {"C", "F", "D", "B", "S", "I", "L"};
/**
* These must agree with the order of Constants.T_CHAR through T_LONG.
*/
private static final String[] SHORT_NAMES = {"C", "F", "D", "B", "S", "I", "L"};
private static final MethodObject[] appendMethodObjects = {
private static final MethodObject[] APPEND_METHOD_OBJECTS = {
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.STRING }),
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.OBJECT }), null, null, // indices 2, 3
new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.BOOLEAN }),
@ -484,7 +486,7 @@ public class InstructionFactory {
public Instruction createAppend(final Type type) {
final byte t = type.getType();
if (isString(type)) {
return createInvoke(appendMethodObjects[0], Const.INVOKEVIRTUAL);
return createInvoke(APPEND_METHOD_OBJECTS[0], Const.INVOKEVIRTUAL);
}
switch (t) {
case Const.T_BOOLEAN:
@ -495,10 +497,10 @@ public class InstructionFactory {
case Const.T_SHORT:
case Const.T_INT:
case Const.T_LONG:
return createInvoke(appendMethodObjects[t], Const.INVOKEVIRTUAL);
return createInvoke(APPEND_METHOD_OBJECTS[t], Const.INVOKEVIRTUAL);
case Const.T_ARRAY:
case Const.T_OBJECT:
return createInvoke(appendMethodObjects[1], Const.INVOKEVIRTUAL);
return createInvoke(APPEND_METHOD_OBJECTS[1], Const.INVOKEVIRTUAL);
default:
throw new IllegalArgumentException("No append for this type? " + type);
}
@ -515,7 +517,7 @@ public class InstructionFactory {
if (dest == Const.T_LONG && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) {
src = Const.T_INT;
}
final String name = "com.sun.org.apache.bcel.internal.generic." + shortNames[src - Const.T_CHAR] + "2" + shortNames[dest - Const.T_CHAR];
final String name = "com.sun.org.apache.bcel.internal.generic." + SHORT_NAMES[src - Const.T_CHAR] + "2" + SHORT_NAMES[dest - Const.T_CHAR];
Instruction i = null;
try {
i = (Instruction) Class.forName(name).getDeclaredConstructor().newInstance();;
@ -642,8 +644,10 @@ public class InstructionFactory {
int index;
int nargs = 0;
final String signature = Type.getMethodSignature(retType, argTypes);
for (final Type argType : argTypes) {
nargs += argType.getSize();
if (argTypes != null) {
for (final Type argType : argTypes) {
nargs += argType.getSize();
}
}
if (useInterface) {
index = cp.addInterfaceMethodref(className, name, signature);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -38,7 +38,7 @@ import com.sun.org.apache.bcel.internal.classfile.Utility;
* @see Instruction
* @see BranchHandle
* @see InstructionList
* @LastModified: May 2021
* @LastModified: Sept 2025
*/
public class InstructionHandle {
@ -118,7 +118,7 @@ public class InstructionHandle {
if (targeters == null) {
targeters = new HashSet<>();
}
// if(!targeters.contains(t))
// if (!targeters.contains(t))
targeters.add(t);
}
@ -135,15 +135,12 @@ public class InstructionHandle {
}
/**
* Get attribute of an instruction handle.
* Gets attribute of an instruction handle.
*
* @param key the key object to store/retrieve the attribute
*/
public Object getAttribute(final Object key) {
if (attributes != null) {
return attributes.get(key);
}
return null;
return attributes != null ? attributes.get(key) : null;
}
/**
@ -247,7 +244,7 @@ public class InstructionHandle {
}
/**
* Set the position, i.e., the byte code offset of the contained instruction.
* Sets the position, i.e., the byte code offset of the contained instruction.
*/
void setPosition(final int pos) {
i_position = pos;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -33,6 +33,7 @@ import java.util.NoSuchElementException;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.classfile.Constant;
import com.sun.org.apache.bcel.internal.util.ByteSequence;
import jdk.xml.internal.Utils;
/**
* This class is a container for a list of <a href="Instruction.html">Instruction</a> objects. Instructions can be
@ -46,7 +47,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence;
* @see Instruction
* @see InstructionHandle
* @see BranchHandle
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public class InstructionList implements Iterable<InstructionHandle> {
@ -60,23 +61,25 @@ public class InstructionList implements Iterable<InstructionHandle> {
* @return target position's instruction handle if available
*/
public static InstructionHandle findHandle(final InstructionHandle[] ihs, final int[] pos, final int count, final int target) {
int l = 0;
int r = count - 1;
/*
* Do a binary search since the pos array is orderd.
*/
do {
final int i = l + r >>> 1;
final int j = pos[i];
if (j == target) {
return ihs[i];
}
if (target < j) {
r = i - 1;
} else {
l = i + 1;
}
} while (l <= r);
if (ihs != null && pos != null) {
int l = 0;
int r = count - 1;
/*
* Do a binary search since the pos array is orderd.
*/
do {
final int i = l + r >>> 1;
final int j = pos[i];
if (j == target) {
return ihs[i];
}
if (target < j) {
r = i - 1;
} else {
l = i + 1;
}
} while (l <= r);
}
return null;
}
@ -513,7 +516,7 @@ public class InstructionList implements Iterable<InstructionHandle> {
}
/**
* Get instruction handle for instruction at byte code position pos. This only works properly, if the list is freshly
* Gets instruction handle for instruction at byte code position pos. This only works properly, if the list is freshly
* initialized from a byte array or setPositions() has been called before this method.
*
* @param pos byte code position to search for
@ -605,7 +608,7 @@ public class InstructionList implements Iterable<InstructionHandle> {
}
/**
* Get positions (offsets) of all instructions in the list. This relies on that the list has been freshly created from
* Gets positions (offsets) of all instructions in the list. This relies on that the list has been freshly created from
* an byte code array, or that setPositions() has been called. Otherwise this may be inaccurate.
*
* @return array containing all instruction's offset in byte code
@ -959,7 +962,7 @@ public class InstructionList implements Iterable<InstructionHandle> {
* @see MethodGen
*/
public void redirectExceptionHandlers(final CodeExceptionGen[] exceptions, final InstructionHandle oldTarget, final InstructionHandle newTarget) {
for (final CodeExceptionGen exception : exceptions) {
Utils.streamOfIfNonNull(exceptions).forEach(exception -> {
if (exception.getStartPC() == oldTarget) {
exception.setStartPC(newTarget);
}
@ -969,7 +972,7 @@ public class InstructionList implements Iterable<InstructionHandle> {
if (exception.getHandlerPC() == oldTarget) {
exception.setHandlerPC(newTarget);
}
}
});
}
/**
@ -981,16 +984,14 @@ public class InstructionList implements Iterable<InstructionHandle> {
* @see MethodGen
*/
public void redirectLocalVariables(final LocalVariableGen[] lg, final InstructionHandle oldTarget, final InstructionHandle newTarget) {
for (final LocalVariableGen element : lg) {
final InstructionHandle start = element.getStart();
final InstructionHandle end = element.getEnd();
if (start == oldTarget) {
Utils.streamOfIfNonNull(lg).forEach(element -> {
if (element.getStart() == oldTarget) {
element.setStart(newTarget);
}
if (end == oldTarget) {
if (element.getEnd() == oldTarget) {
element.setEnd(newTarget);
}
}
});
}
/**
@ -1120,7 +1121,7 @@ public class InstructionList implements Iterable<InstructionHandle> {
ih.setPosition(index);
pos[count++] = index;
/*
* Get an estimate about how many additional bytes may be added, because BranchInstructions may have variable length
* Gets an estimate about how many additional bytes may be added, because BranchInstructions may have variable length
* depending on the target offset (short vs. int) or alignment issues (TABLESWITCH and LOOKUPSWITCH).
*/
switch (i.getOpcode()) {
@ -1132,11 +1133,14 @@ public class InstructionList implements Iterable<InstructionHandle> {
case Const.LOOKUPSWITCH:
maxAdditionalBytes += 3;
break;
default:
// TODO should this be an error?
break;
}
index += i.getLength();
}
/*
* Pass 2: Expand the variable-length (Branch)Instructions depending on the target offset (short or int) and ensure that
* Pass 2: Expand the variable-length (Branch) Instructions depending on the target offset (short or int) and ensure that
* branch targets are within this list.
*/
for (InstructionHandle ih = start; ih != null; ih = ih.getNext()) {
@ -1152,8 +1156,7 @@ public class InstructionList implements Iterable<InstructionHandle> {
pos[count++] = index;
index += i.getLength();
}
bytePositions = new int[count]; // Trim to proper size
System.arraycopy(pos, 0, bytePositions, 0, count);
bytePositions = Arrays.copyOfRange(pos, 0, count); // Trim to proper size
}
/**

View File

@ -22,7 +22,7 @@
package com.sun.org.apache.bcel.internal.generic;
/**
* Denote that a class targets InstructionHandles within an InstructionList. Namely the following implementers:
* Denotes that a class targets InstructionHandles within an InstructionList.
*
* @see BranchHandle
* @see LocalVariableGen
@ -33,9 +33,12 @@ public interface InstructionTargeter {
// static final InstructionTargeter[] EMPTY_ARRAY = new InstructionTargeter[0];
/**
* Checks whether this targeter targets the specified instruction handle.
* Tests whether this targeter targets the specified instruction handle.
*
* @param instructionHandle the instruction handle to test.
* @return whether this targeter targets the specified instruction handle.
*/
boolean containsTarget(InstructionHandle ih);
boolean containsTarget(InstructionHandle instructionHandle);
/**
* Replaces the target of this targeter from this old handle to the new handle.

View File

@ -27,7 +27,6 @@ package com.sun.org.apache.bcel.internal.generic;
* <PRE>
* Stack: ..., value1.word1, value1.word2, value2.word1, value2.word2 -&gt; ..., result &lt;= -1, 0, 1&gt;
* </PRE>
*
*/
public class LCMP extends Instruction implements TypedInstruction, StackProducer, StackConsumer {

View File

@ -94,6 +94,8 @@ public class LDC extends CPInstruction implements PushInstruction, ExceptionThro
return Type.INT;
case com.sun.org.apache.bcel.internal.Const.CONSTANT_Class:
return Type.CLASS;
case com.sun.org.apache.bcel.internal.Const.CONSTANT_Dynamic:
return Type.OBJECT;
default: // Never reached
throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex());
}
@ -113,7 +115,10 @@ public class LDC extends CPInstruction implements PushInstruction, ExceptionThro
case com.sun.org.apache.bcel.internal.Const.CONSTANT_Class:
final int nameIndex = ((com.sun.org.apache.bcel.internal.classfile.ConstantClass) c).getNameIndex();
c = cpg.getConstantPool().getConstant(nameIndex);
return Type.getType(((com.sun.org.apache.bcel.internal.classfile.ConstantUtf8) c).getBytes());
return Type.getType(Type.internalTypeNameToSignature(((com.sun.org.apache.bcel.internal.classfile.ConstantUtf8) c).getBytes()));
case com.sun.org.apache.bcel.internal.Const.CONSTANT_Dynamic:
// Really not sure what to return here, maybe a BootstrapMethod instance but how do we get it?
return c;
default: // Never reached
throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex());
}
@ -129,7 +134,7 @@ public class LDC extends CPInstruction implements PushInstruction, ExceptionThro
}
/**
* Set the index to constant pool and adjust size.
* Sets the index to constant pool and adjust size.
*/
@Override
public final void setIndex(final int index) {

View File

@ -54,7 +54,7 @@ public class LineNumberGen implements InstructionTargeter, Cloneable {
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
}
}
@ -71,7 +71,7 @@ public class LineNumberGen implements InstructionTargeter, Cloneable {
}
/**
* Get LineNumber attribute.
* Gets LineNumber attribute.
*
* This relies on that the instruction list has already been dumped to byte code or that the 'setPositions' methods
* has been called for the instruction list.

View File

@ -85,7 +85,7 @@ public class LocalVariableGen implements InstructionTargeter, NamedAndTyped, Clo
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new Error("Clone Not Supported"); // never happens
throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -28,7 +28,7 @@ import com.sun.org.apache.bcel.internal.util.ByteSequence;
/**
* Abstract super class for instructions dealing with local variables.
*
* @LastModified: May 2021
* @LastModified: Sept 2025
*/
public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction, IndexedInstruction {
@ -162,7 +162,7 @@ public abstract class LocalVariableInstruction extends Instruction implements Ty
}
/**
* Set the local variable index. also updates opcode and length TODO Why?
* Sets the local variable index. also updates opcode and length TODO Why?
*
* @see #setIndexOnly(int)
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@ -27,6 +27,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Stack;
import java.util.stream.Collectors;
import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry;
@ -46,6 +47,7 @@ import com.sun.org.apache.bcel.internal.classfile.ParameterAnnotations;
import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleParameterAnnotations;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.util.BCELComparator;
import jdk.xml.internal.Utils;
/**
* Template class for building up a method. This is done by defining exception handlers, adding thrown exceptions, local
@ -57,7 +59,7 @@ import com.sun.org.apache.bcel.internal.util.BCELComparator;
*
* @see InstructionList
* @see Method
* @LastModified: Feb 2023
* @LastModified: Sept 2025
*/
public class MethodGen extends FieldGenOrMethodGen {
@ -102,19 +104,16 @@ public class MethodGen extends FieldGenOrMethodGen {
}
}
private static BCELComparator bcelComparator = new BCELComparator() {
private static BCELComparator<FieldGenOrMethodGen> bcelComparator = new BCELComparator<FieldGenOrMethodGen>() {
@Override
public boolean equals(final Object o1, final Object o2) {
final FieldGenOrMethodGen THIS = (FieldGenOrMethodGen) o1;
final FieldGenOrMethodGen THAT = (FieldGenOrMethodGen) o2;
return Objects.equals(THIS.getName(), THAT.getName()) && Objects.equals(THIS.getSignature(), THAT.getSignature());
public boolean equals(final FieldGenOrMethodGen a, final FieldGenOrMethodGen 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 Object o) {
final FieldGenOrMethodGen THIS = (FieldGenOrMethodGen) o;
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
public int hashCode(final FieldGenOrMethodGen o) {
return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
}
};
@ -127,9 +126,9 @@ public class MethodGen extends FieldGenOrMethodGen {
}
/**
* @return Comparison strategy object
* @return Comparison strategy object.
*/
public static BCELComparator getComparator() {
public static BCELComparator<FieldGenOrMethodGen> getComparator() {
return bcelComparator;
}
@ -206,9 +205,9 @@ public class MethodGen extends FieldGenOrMethodGen {
}
/**
* @param comparator Comparison strategy object
* @param comparator Comparison strategy object.
*/
public static void setComparator(final BCELComparator comparator) {
public static void setComparator(final BCELComparator<FieldGenOrMethodGen> comparator) {
bcelComparator = comparator;
}
@ -636,7 +635,7 @@ public class MethodGen extends FieldGenOrMethodGen {
*/
@Override
public boolean equals(final Object obj) {
return bcelComparator.equals(this, obj);
return obj instanceof FieldGenOrMethodGen && bcelComparator.equals(this, (FieldGenOrMethodGen) obj);
}
// J5TODO: Should paramAnnotations be an array of arrays? Rather than an array of lists, this
@ -790,7 +789,7 @@ public class MethodGen extends FieldGenOrMethodGen {
}
/**
* Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, before calling this method
* Gets method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, before calling this method
* (the same applies for max locals).
*
* @return method object
@ -888,7 +887,7 @@ public class MethodGen extends FieldGenOrMethodGen {
}
/**
* Return value as defined by given BCELComparator strategy. By default return the hashcode of the method's name XOR
* Return value as defined by given BCELComparator strategy. By default return the hash code of the method's name XOR
* signature.
*
* @see Object#hashCode()
@ -899,11 +898,7 @@ public class MethodGen extends FieldGenOrMethodGen {
}
private List<AnnotationEntryGen> makeMutableVersion(final AnnotationEntry[] mutableArray) {
final List<AnnotationEntryGen> result = new ArrayList<>();
for (final AnnotationEntry element : mutableArray) {
result.add(new AnnotationEntryGen(element, getConstantPool(), false));
}
return result;
return Utils.streamOfIfNonNull(mutableArray).map(ae -> new AnnotationEntryGen(ae, getConstantPool(), false)).collect(Collectors.toList());
}
/**
@ -1027,10 +1022,8 @@ public class MethodGen extends FieldGenOrMethodGen {
*
* @since 6.5.0
*/
public void removeRuntimeAttributes(final Attribute[] attrs) {
for (final Attribute attr : attrs) {
removeAttribute(attr);
}
public void removeRuntimeAttributes(final Attribute[] attributes) {
Utils.streamOfIfNonNull(attributes).forEach(this::removeAttribute);
}
public void setArgumentName(final int i, final String name) {
@ -1038,7 +1031,7 @@ public class MethodGen extends FieldGenOrMethodGen {
}
public void setArgumentNames(final String[] argNames) {
this.argNames = argNames;
this.argNames = Utils.createEmptyArrayIfNull(argNames, String[].class);
}
public void setArgumentType(final int i, final Type type) {
@ -1046,7 +1039,7 @@ public class MethodGen extends FieldGenOrMethodGen {
}
public void setArgumentTypes(final Type[] argTypes) {
this.argTypes = argTypes;
this.argTypes = argTypes != null ? argTypes : Type.NO_ARGS;
}
public void setClassName(final String className) { // TODO could be package-protected?
@ -1084,7 +1077,7 @@ public class MethodGen extends FieldGenOrMethodGen {
}
/**
* Set maximum number of local variables.
* Sets maximum number of local variables.
*/
public void setMaxLocals(final int m) {
maxLocals = m;
@ -1102,7 +1095,7 @@ public class MethodGen extends FieldGenOrMethodGen {
}
/**
* Set maximum stack size for this method.
* Sets maximum stack size for this method.
*/
public void setMaxStack(final int m) { // TODO could be package-protected?
maxStack = m;

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