From 56b192d71d0f0e9c354932c3dcb378d07a8bbb98 Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Mon, 7 Nov 2022 15:51:29 +0100 Subject: [PATCH 1/3] Add MethodInfo.isConstructor() --- core/src/main/java/org/jboss/jandex/ClassInfo.java | 4 ++-- core/src/main/java/org/jboss/jandex/IndexReaderV2.java | 3 +-- core/src/main/java/org/jboss/jandex/Indexer.java | 8 +++----- core/src/main/java/org/jboss/jandex/MethodInfo.java | 8 ++++++++ core/src/main/java/org/jboss/jandex/Utils.java | 2 ++ .../test/java/org/jboss/jandex/test/BasicTestCase.java | 6 ++++++ 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/org/jboss/jandex/ClassInfo.java b/core/src/main/java/org/jboss/jandex/ClassInfo.java index ec618fa7..f0f23cd5 100644 --- a/core/src/main/java/org/jboss/jandex/ClassInfo.java +++ b/core/src/main/java/org/jboss/jandex/ClassInfo.java @@ -711,9 +711,9 @@ public final List unsortedMethods() { * @return the list of constructors declared in this class */ public final List constructors() { - List constructors = new ArrayList(1); + List constructors = new ArrayList<>(1); for (MethodInfo method : methods()) { - if ("".equals(method.name())) { + if (method.isConstructor()) { constructors.add(method); } } diff --git a/core/src/main/java/org/jboss/jandex/IndexReaderV2.java b/core/src/main/java/org/jboss/jandex/IndexReaderV2.java index db5f51ab..b0c0ff7a 100644 --- a/core/src/main/java/org/jboss/jandex/IndexReaderV2.java +++ b/core/src/main/java/org/jboss/jandex/IndexReaderV2.java @@ -77,7 +77,6 @@ final class IndexReaderV2 extends IndexReaderImpl { private static final int AVALUE_ARRAY = 12; private static final int AVALUE_NESTED = 13; private static final int HAS_ENCLOSING_METHOD = 1; - private final static byte[] INIT_METHOD_NAME = Utils.toUTF8(""); private final PackedDataInputStream input; private final int version; @@ -825,7 +824,7 @@ private MethodInternal[] readClassMethods(PackedDataInputStream stream, ClassInf methods[i] = method; if (version < 11 && method.parameterTypesArray().length == 0 - && Arrays.equals(INIT_METHOD_NAME, method.nameBytes())) { + && Arrays.equals(Utils.INIT_METHOD_NAME, method.nameBytes())) { clazz.setHasNoArgsConstructor(true); } } diff --git a/core/src/main/java/org/jboss/jandex/Indexer.java b/core/src/main/java/org/jboss/jandex/Indexer.java index 17600a83..01dbec8a 100644 --- a/core/src/main/java/org/jboss/jandex/Indexer.java +++ b/core/src/main/java/org/jboss/jandex/Indexer.java @@ -248,8 +248,6 @@ public final class Indexer { private final static int HAS_RUNTIME_INVISIBLE_PARAM_ANNOTATION = 17; private final static int HAS_RUNTIME_INVISIBLE_TYPE_ANNOTATION = 18; - private final static byte[] INIT_METHOD_NAME = Utils.toUTF8(""); - private static class InnerClassInfo { private InnerClassInfo(DotName innerClass, DotName enclosingClass, String simpleName, int flags) { this.innerClass = innerClass; @@ -396,7 +394,7 @@ private void processMethodInfo(DataInputStream data) throws IOException { MethodInfo method = new MethodInfo(currentClass, name, MethodInternal.EMPTY_PARAMETER_NAMES, parameters, returnType, flags); - if (parameters.length == 0 && Arrays.equals(INIT_METHOD_NAME, name)) { + if (parameters.length == 0 && Arrays.equals(Utils.INIT_METHOD_NAME, name)) { currentClass.setHasNoArgsConstructor(true); } methodParameterNames = debugParameterNames = null; @@ -938,7 +936,7 @@ private void adjustMethodParameters() { } private static boolean isEnumConstructor(MethodInfo method) { - return method.declaringClass().isEnum() && Arrays.equals(INIT_METHOD_NAME, method.methodInternal().nameBytes()); + return method.declaringClass().isEnum() && method.isConstructor(); } private void resolveTypeAnnotations() { @@ -1015,7 +1013,7 @@ private static void setTypeParameters(AnnotationTarget target, Type[] typeParame } private boolean isInnerConstructor(MethodInfo method) { - if (!Arrays.equals(INIT_METHOD_NAME, method.methodInternal().nameBytes())) { + if (!method.isConstructor()) { return false; } diff --git a/core/src/main/java/org/jboss/jandex/MethodInfo.java b/core/src/main/java/org/jboss/jandex/MethodInfo.java index ba1af2a6..e83dfa9c 100644 --- a/core/src/main/java/org/jboss/jandex/MethodInfo.java +++ b/core/src/main/java/org/jboss/jandex/MethodInfo.java @@ -21,6 +21,7 @@ import java.io.UnsupportedEncodingException; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -578,6 +579,13 @@ public final boolean isSynthetic() { return Modifiers.isSynthetic(methodInternal.flags()); } + /** + * @return {@code true} if this method is a constructor + */ + public boolean isConstructor() { + return Arrays.equals(Utils.INIT_METHOD_NAME, methodInternal.nameBytes()); + } + /** * Returns a string representation describing this field. It is similar although not * necessarily identical to a Java source code expression representing this field. diff --git a/core/src/main/java/org/jboss/jandex/Utils.java b/core/src/main/java/org/jboss/jandex/Utils.java index e5348bcd..d0c32236 100644 --- a/core/src/main/java/org/jboss/jandex/Utils.java +++ b/core/src/main/java/org/jboss/jandex/Utils.java @@ -31,6 +31,8 @@ * @author Jason T. Greene */ class Utils { + static final byte[] INIT_METHOD_NAME = Utils.toUTF8(""); + static byte[] toUTF8(String string) { return string.getBytes(StandardCharsets.UTF_8); } diff --git a/core/src/test/java/org/jboss/jandex/test/BasicTestCase.java b/core/src/test/java/org/jboss/jandex/test/BasicTestCase.java index a77a1760..a48b951b 100644 --- a/core/src/test/java/org/jboss/jandex/test/BasicTestCase.java +++ b/core/src/test/java/org/jboss/jandex/test/BasicTestCase.java @@ -621,6 +621,7 @@ private void verifyDummy(Index index, boolean v2features) { assertEquals("somethingelse", overrideValue.asString()); assertNotNull(method); + assertFalse(method.isConstructor()); assertEquals(3, method.annotations().size()); assertEquals(MethodAnnotation1.class.getName(), method.annotation(DotName.createSimple(MethodAnnotation1.class.getName())).name().toString()); @@ -638,6 +639,7 @@ private void verifyDummy(Index index, boolean v2features) { assertNotNull(nested); MethodInfo nestedConstructor1 = nested.method("", PrimitiveType.INT); assertNotNull(nestedConstructor1); + assertTrue(nestedConstructor1.isConstructor()); assertEquals(1, nestedConstructor1.parametersCount()); assertEquals(1, nestedConstructor1.parameterTypes().size()); assertEquals(1, nestedConstructor1.parameters().size()); @@ -645,6 +647,7 @@ private void verifyDummy(Index index, boolean v2features) { MethodInfo nestedConstructor2 = nested.method("", PrimitiveType.BYTE); assertNotNull(nestedConstructor2); + assertTrue(nestedConstructor2.isConstructor()); // synthetic param counts here assertEquals(1, nestedConstructor2.parametersCount()); assertEquals(1, nestedConstructor2.parameterTypes().size()); @@ -681,11 +684,13 @@ private void verifyDummy(Index index, boolean v2features) { assertNotNull(enumClass); MethodInfo enumConstructor1 = enumClass.method("", PrimitiveType.INT); assertNotNull(enumConstructor1); + assertTrue(enumConstructor1.isConstructor()); assertEquals(1, enumConstructor1.parametersCount()); assertEquals("noAnnotation", enumConstructor1.parameterName(0)); MethodInfo enumConstructor2 = enumClass.method("", PrimitiveType.BYTE); assertNotNull(enumConstructor2); + assertTrue(enumConstructor2.isConstructor()); assertEquals(1, enumConstructor2.parametersCount()); assertEquals("annotated", enumConstructor2.parameterName(0)); @@ -699,6 +704,7 @@ private void verifyDummy(Index index, boolean v2features) { assertNotNull(enumWithGenericConstructorClass); MethodInfo ctor = enumWithGenericConstructorClass.firstMethod(""); assertNotNull(ctor); + assertTrue(ctor.isConstructor()); assertEquals(1, ctor.parametersCount()); assertEquals(Type.Kind.PARAMETERIZED_TYPE, ctor.parameterType(0).kind()); assertEquals("java.util.List", ctor.parameterType(0).asParameterizedType().name().toString()); From 05a23b4e52678049bff1290c1c5aaf2a6536928c Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Mon, 7 Nov 2022 16:13:42 +0100 Subject: [PATCH 2/3] Fix parsing type annotations on constructors of inner classes --- .../main/java/org/jboss/jandex/Indexer.java | 17 ++++- ...AnnotationOnInnerClassConstructorTest.java | 72 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 core/src/test/java/org/jboss/jandex/test/TypeAnnotationOnInnerClassConstructorTest.java diff --git a/core/src/main/java/org/jboss/jandex/Indexer.java b/core/src/main/java/org/jboss/jandex/Indexer.java index 01dbec8a..7c80f535 100644 --- a/core/src/main/java/org/jboss/jandex/Indexer.java +++ b/core/src/main/java/org/jboss/jandex/Indexer.java @@ -1108,7 +1108,19 @@ private void resolveTypeAnnotation(AnnotationTarget target, TypeAnnotationState if (skipBridge(typeAnnotationState, method)) { return; } - method.setReturnType(resolveTypePath(returnType, typeAnnotationState)); + if (!method.isConstructor()) { + method.setReturnType(resolveTypePath(returnType, typeAnnotationState)); + } else { + // create a synthetic `ClassType` for the purpose of resolving the type path, + // which would fail on a `VoidType` if the path points to a nested type + // (this happens on inner class constructors with type annotations) + Type newType = new ClassType(method.declaringClass().name()); + newType = resolveTypePath(newType, typeAnnotationState); + returnType = returnType.copyType(newType.annotationArray()); + // fixup, `resolveTypePath` sets `typeAnnotationState.target` to the synthetic `ClassType` + typeAnnotationState.target.setTarget(returnType); + method.setReturnType(returnType); + } } } else if (typeTarget.usage() == TypeTarget.Usage.EMPTY && target instanceof RecordComponentInfo) { RecordComponentInfo recordComponent = (RecordComponentInfo) target; @@ -1277,6 +1289,9 @@ private void updateTypeTarget(AnnotationTarget enclosingTarget, TypeAnnotationSt if (skipBridge(typeAnnotationState, method)) { return; } + if (method.isConstructor()) { + return; + } } break; } diff --git a/core/src/test/java/org/jboss/jandex/test/TypeAnnotationOnInnerClassConstructorTest.java b/core/src/test/java/org/jboss/jandex/test/TypeAnnotationOnInnerClassConstructorTest.java new file mode 100644 index 00000000..3720cce8 --- /dev/null +++ b/core/src/test/java/org/jboss/jandex/test/TypeAnnotationOnInnerClassConstructorTest.java @@ -0,0 +1,72 @@ +package org.jboss.jandex.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.Index; +import org.jboss.jandex.MethodInfo; +import org.jboss.jandex.Type; +import org.jboss.jandex.TypeTarget; +import org.jboss.jandex.test.util.IndexingUtil; +import org.junit.jupiter.api.Test; + +public class TypeAnnotationOnInnerClassConstructorTest { + @MyAnnotation("top-level") + TypeAnnotationOnInnerClassConstructorTest() { + } + + class InnerClass { + @MyAnnotation("inner") + public InnerClass() { + } + + class InnerInnerClass { + @MyAnnotation("inner-inner") + public InnerInnerClass() { + } + } + } + + @Test + public void test() throws IOException { + Index index = Index.of(TypeAnnotationOnInnerClassConstructorTest.class, InnerClass.class, + InnerClass.InnerInnerClass.class); + test(index); + test(IndexingUtil.roundtrip(index)); + } + + private void test(Index index) { + testConstructor(index.getClassByName(TypeAnnotationOnInnerClassConstructorTest.class), "top-level"); + testConstructor(index.getClassByName(InnerClass.class), "inner"); + testConstructor(index.getClassByName(InnerClass.InnerInnerClass.class), "inner-inner"); + + for (AnnotationInstance annotation : index.getAnnotations(MyAnnotation.DOT_NAME)) { + assertTrue(annotation.target().kind() == AnnotationTarget.Kind.METHOD + || annotation.target().kind() == AnnotationTarget.Kind.TYPE); + + if (annotation.target().kind() == AnnotationTarget.Kind.TYPE) { + TypeTarget typeAnnotationTarget = annotation.target().asType(); + assertEquals(AnnotationTarget.Kind.METHOD, typeAnnotationTarget.enclosingTarget().kind()); + assertTrue(typeAnnotationTarget.enclosingTarget().asMethod().isConstructor()); + assertEquals(Type.Kind.VOID, typeAnnotationTarget.target().kind()); + } + } + } + + private void testConstructor(ClassInfo clazz, String annotationValue) { + assertEquals(1, clazz.constructors().size()); + + MethodInfo ctor = clazz.constructors().get(0); + assertTrue(ctor.hasAnnotation(MyAnnotation.DOT_NAME)); + assertEquals(annotationValue, ctor.annotation(MyAnnotation.DOT_NAME).value().asString()); + + Type ctorType = ctor.returnType(); + assertTrue(ctorType.hasAnnotation(MyAnnotation.DOT_NAME)); + assertEquals(annotationValue, ctorType.annotation(MyAnnotation.DOT_NAME).value().asString()); + } +} From 75372c1d30a1b233778b95e93d85b0861eb17640 Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Mon, 7 Nov 2022 16:19:11 +0100 Subject: [PATCH 3/3] Fix formatting of some text files --- CODE_OF_CONDUCT.md | 3 +-- README.md | 2 +- SECURITY.md | 2 +- dco.txt | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1005c14a..959700e3 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,3 @@ - # Contributor Covenant Code of Conduct ## Our Pledge @@ -129,4 +128,4 @@ For answers to common questions about this code of conduct, see the FAQ at [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html [Mozilla CoC]: https://github.com/mozilla/diversity [FAQ]: https://www.contributor-covenant.org/faq -[translations]: https://www.contributor-covenant.org/translations \ No newline at end of file +[translations]: https://www.contributor-covenant.org/translations diff --git a/README.md b/README.md index 6ad62a97..746057ee 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Jandex is a space efficient Java class file indexer and offline reflection library. See the [documentation](https://smallrye.io/jandex/). -# Getting Help +## Getting Help Issues can be reported in [GitHub Issues](https://github.com/smallrye/jandex/issues). diff --git a/SECURITY.md b/SECURITY.md index aa324d13..7cb47fe4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -8,4 +8,4 @@ Please report any suspected security vulnerability in this project to Red Hat Pr To report an issue in any Red Hat branded website or online service, please contact Red Hat Information Security at site-security@redhat.com. -https://access.redhat.com/security/team/contact \ No newline at end of file +https://access.redhat.com/security/team/contact diff --git a/dco.txt b/dco.txt index 0cdce0c3..8201f992 100644 --- a/dco.txt +++ b/dco.txt @@ -34,4 +34,4 @@ By making a contribution to this project, I certify that: are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. \ No newline at end of file + this project or the open source license(s) involved.