diff --git a/src/main/java/org/apache/bcel/Const.java b/src/main/java/org/apache/bcel/Const.java index ba5acc9d71..1729403ea1 100644 --- a/src/main/java/org/apache/bcel/Const.java +++ b/src/main/java/org/apache/bcel/Const.java @@ -2834,7 +2834,7 @@ public final class Const { /** * The signature characters corresponding to primitive types, e.g., SHORT_TYPE_NAMES[T_INT] = "I" */ - private static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V", + public static final String[] SHORT_TYPE_NAMES = {ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "Z", "C", "F", "D", "B", "S", "I", "J", "V", ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE}; /** diff --git a/src/main/java/org/apache/bcel/generic/LDC.java b/src/main/java/org/apache/bcel/generic/LDC.java index 85f1c7c219..eba856e946 100644 --- a/src/main/java/org/apache/bcel/generic/LDC.java +++ b/src/main/java/org/apache/bcel/generic/LDC.java @@ -108,7 +108,7 @@ public Object getValue(final ConstantPoolGen cpg) { case org.apache.bcel.Const.CONSTANT_Class: final int nameIndex = ((org.apache.bcel.classfile.ConstantClass) c).getNameIndex(); c = cpg.getConstantPool().getConstant(nameIndex); - return Type.getType(((org.apache.bcel.classfile.ConstantUtf8) c).getBytes()); + return Type.getType(Type.internalTypeNameToSignature(((org.apache.bcel.classfile.ConstantUtf8) c).getBytes())); default: // Never reached throw new IllegalArgumentException("Unknown or invalid constant type at " + super.getIndex()); } diff --git a/src/main/java/org/apache/bcel/generic/Type.java b/src/main/java/org/apache/bcel/generic/Type.java index e8e4cc3103..34798c3482 100644 --- a/src/main/java/org/apache/bcel/generic/Type.java +++ b/src/main/java/org/apache/bcel/generic/Type.java @@ -25,6 +25,7 @@ import org.apache.bcel.classfile.ClassFormatException; import org.apache.bcel.classfile.InvalidMethodSignatureException; import org.apache.bcel.classfile.Utility; +import org.apache.commons.lang3.StringUtils; /** * Abstract super class for all possible java types, namely basic types such as int, object types like String and array @@ -180,7 +181,7 @@ public static String getSignature(final java.lang.reflect.Method meth) { public static Type getType(final Class cls) { Objects.requireNonNull(cls, "cls"); /* - * That's an amzingly easy case, because getName() returns the signature. That's what we would have liked anyway. + * That's an amazingly easy case, because getName() returns the signature. That's what we would have liked anyway. */ if (cls.isArray()) { return getType(cls.getName()); @@ -365,6 +366,24 @@ public int hashCode() { return type ^ signature.hashCode(); } + static String internalTypeNameToSignature(final String internalTypeName) { + if (StringUtils.isEmpty(internalTypeName) || StringUtils.equalsAny(internalTypeName, Const.SHORT_TYPE_NAMES)) { + return internalTypeName; + } + switch (internalTypeName.charAt(0)) { + case '[': + return internalTypeName; + case 'L': + case 'T': + if (internalTypeName.charAt(internalTypeName.length() - 1) == ';') { + return internalTypeName; + } + return 'L' + internalTypeName + ';'; + default: + return 'L' + internalTypeName + ';'; + } + } + /** * boolean, short and char variable are considered as int in the stack or local variable area. Returns {@link Type#INT} * for {@link Type#BOOLEAN}, {@link Type#SHORT} or {@link Type#CHAR}, otherwise returns the given type. diff --git a/src/test/java/org/apache/bcel/generic/TypeTestCase.java b/src/test/java/org/apache/bcel/generic/TypeTestCase.java index a2632151de..242e1004cb 100644 --- a/src/test/java/org/apache/bcel/generic/TypeTestCase.java +++ b/src/test/java/org/apache/bcel/generic/TypeTestCase.java @@ -16,9 +16,16 @@ */ package org.apache.bcel.generic; -import static org.junit.jupiter.api.Assertions.assertEquals; - +import org.apache.bcel.Repository; +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class TypeTestCase { @Test @@ -32,4 +39,63 @@ public void testBCEL243() { assertEquals(expectedValue, actualValue, "Type.getType"); } + @ParameterizedTest + @ValueSource(strings = { + // @formatter:off + "java/io/Externalizable", + "java/io/ObjectOutputStream", + "java/io/Serializable", + "java/lang/Cloneable", + "java/lang/RuntimeException", + "java/lang/String", + "java/lang/System", + "java/lang/Throwable", + "java/net/URI", + "java/sql/Statement", + "java/util/ArrayList", + "java/util/Calendar", + "java/util/EnumMap", + "java/util/HashSet", + "java/util/Iterator", + "java/util/LinkedList", + "java/util/List", + "java/util/Map", + "java/util/concurrent/ConcurrentMap", + "java/util/concurrent/ExecutorService", + "org/apache/bcel/classfile/JavaClass", + "org/apache/bcel/classfile/Method", + "org/apache/bcel/classfile/Synthetic", + "org/apache/bcel/generic/ConstantPoolGen", + "org/apache/bcel/generic/MethodGen"}) + // @formatter:on + public void testLDC(final String className) throws Exception { + final JavaClass jc = Repository.lookupClass(className); + final ConstantPoolGen cpg = new ConstantPoolGen(jc.getConstantPool()); + for (final Method method : jc.getMethods()) { + final Code code = method.getCode(); + if (code != null) { + final InstructionList instructionList = new InstructionList(code.getCode()); + for (final InstructionHandle instructionHandle : instructionList) { + instructionHandle.accept(new EmptyVisitor() { + @Override + public void visitLDC(LDC obj) { + assertNotNull(obj.getValue(cpg)); + } + }); + } + } + } + } + + @Test + public void testInternalTypeNametoSignature() { + assertEquals(null, Type.internalTypeNameToSignature(null)); + assertEquals("", Type.internalTypeNameToSignature("")); + assertEquals("TT;", Type.internalTypeNameToSignature("TT;")); + assertEquals("Ljava/lang/String;", Type.internalTypeNameToSignature("Ljava/lang/String;")); + assertEquals("[Ljava/lang/String;", Type.internalTypeNameToSignature("[Ljava/lang/String;")); + assertEquals("Ljava/lang/String;", Type.internalTypeNameToSignature("java/lang/String")); + assertEquals("I", Type.internalTypeNameToSignature("I")); + assertEquals("LT;", Type.internalTypeNameToSignature("T")); + } }