leangen / geantyref

Advanced generic type reflection library with support for working with AnnotatedTypes (for Java 8+)
Apache License 2.0
99 stars 15 forks source link

Inconsistent results when using TypeToken to get AnnotatedType in static and instance methods #8

Closed allurx closed 4 years ago

allurx commented 4 years ago

jdk version

1.8

example


package com.zyc;

import io.leangen.geantyref.TypeToken;

import java.lang.annotation.*;
import java.lang.reflect.AnnotatedParameterizedType;
import java.util.Arrays;
import java.util.List;

/**
 * @author zyc
 */
public class Test {

    @Target(ElementType.TYPE_USE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface Example {
    }

    public static void main(String[] args) {

        // Direct execution works
        AnnotatedParameterizedType annotatedParameterizedType = (AnnotatedParameterizedType) new TypeToken<List<@Example String>>() {
        }.getAnnotatedType();
        System.out.println(Arrays.toString(annotatedParameterizedType.getAnnotatedActualTypeArguments()[0].getDeclaredAnnotations()));

        // The static method works
        staticMethod();

        // The instance method does not work
        new Test().instanceMethod();
    }

    /**
     * static method
     */
    private static void staticMethod() {
        AnnotatedParameterizedType annotatedParameterizedType = (AnnotatedParameterizedType) new TypeToken<List<@Example String>>() {
        }.getAnnotatedType();
        System.out.println(Arrays.toString(annotatedParameterizedType.getAnnotatedActualTypeArguments()[0].getDeclaredAnnotations()));
    }

    /**
     * instance method
     */
    private void instanceMethod() {
        AnnotatedParameterizedType annotatedParameterizedType = (AnnotatedParameterizedType) new TypeToken<List<@Example String>>() {
        }.getAnnotatedType();
        System.out.println(Arrays.toString(annotatedParameterizedType.getAnnotatedActualTypeArguments()[0].getDeclaredAnnotations()));
    }

   @org.junit.Test
    public void test() {
        AnnotatedParameterizedType annotatedParameterizedType = (AnnotatedParameterizedType) new TypeToken<List<@Example String>>() {
        }.getAnnotatedType();
        System.out.println(Arrays.toString(annotatedParameterizedType.getAnnotatedActualTypeArguments()[0].getDeclaredAnnotations()));
    }
}

the expected result of the main method

[@com.zyc.Test$Example()]
[@com.zyc.Test$Example()]
[@com.zyc.Test$Example()]

the actual result of the main method

[@com.zyc.Test$Example()]
[@com.zyc.Test$Example()]
[]

junit result

[]

The test results are unexpected. Do you know where the problem is? thanks.

kaqqao commented 4 years ago

There's a couple of bugs in annotation parsing in JDK itself. You can find some more info here: http://stackoverflow.com/questions/39952812/why-annotation-on-generic-type-argument-is-not-visible-for-nested-type

I believe it was fixed in JDK 12, but I'm not 100% sure...

allurx commented 4 years ago

@kaqqao Oh, it turned out to be a jdk bug, I hope jdk can fix this bug as soon as possible. Thank you very much for your reply.

kaqqao commented 4 years ago

No worries :) Did you verify if it's fixed in newer JDK perhaps?

allurx commented 4 years ago

I just found this problem in jdk1.8. When I have time, I may download the latest jdk to verify this problem, but what confuses me is how to solve this problem if you have to use jdk1.8.

kaqqao commented 4 years ago

You can't fix it... But you can use TypeFactory to produce the types instead of using the TypeToken. Another way is to define all classes at the top level, that seems to dodge the bug. You might also need to declare the types produced by TypeToken as static class fields.

allurx commented 4 years ago

thanks.:smile: