Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotations with target TYPE_USE are missing from JavaField instances #1382

Open
ivan-p92 opened this issue Nov 20, 2024 · 6 comments
Open

Comments

@ivan-p92
Copy link

Hi,

While working on some ArchUnit checks (I find the tool really useful so far!), I found that annotations with a target of @Target(TYPE_USE) are ignored (for example with @Nullable from Jspecify).

To reproduce, I created my own annotation:

@Target({TYPE_USE})
@Retention(RUNTIME)
public @interface Foo {}

Inspecting an ArchUnit JavaField resulting from importing a class with a field annotated with this annotation, no JavaAnnotations are present.

When adding or using FIELD as target, the JavaAnnotation is present on the JavaField instance.

@Target({TYPE_USE, FIELD})
@Retention(RUNTIME)
public @interface Foo {}

It would be great if these annotations were imported!

@eskatos
Copy link

eskatos commented Jan 29, 2025

JSpecify is getting broad use in the wild and the lack of support for checking TYPE_USE annotations from Java 8 is getting in the way of adoption.

http://types.cs.washington.edu/jsr308/specification/java-annotation-design.pdf

Is this considered for an upcoming release of ArchUnit?

@janitza-mage
Copy link

Inspecting an ArchUnit JavaField resulting from importing a class with a field annotated with this annotation, no JavaAnnotations are present.

In this example, you would be annotating the field's type use, not the field itself. You cannot annotate the field itself because fields aren't declared as a valid target of the annotation. So ArchUnit's behavior is correct in this case. To see the annotation, you would have to query the field for its type, and then query the type for its annotations.

Note that type use annotations (allowed by TYPE_USE) are different from annotations present at the class definition that is used in the field's type. A type annotation would be something like List<@Foo String>. Also, since the type use is annotated, List<@Foo String> is different from List<@Bar String>, and neither class List nor class String knows of any of those annotations, since you aren't annotating the classes but the way in which their corresponding types are used. Nor is the field annotated here, because List<@Foo String> is different from @Foo List<String>.

The underlying problem, however, is that ArchUnit has JavaType which does not distinguish between type definition and type use, and seems to be unable to obtain the annotations for type uses, as @eskatos described.

@eskatos
Copy link

eskatos commented Feb 3, 2025

As a workaround one can use the reflect() functions from ArchUnit types to fallback to regular Java reflection in order to grab these annotations.

@ivan-p92
Copy link
Author

ivan-p92 commented Feb 3, 2025

@eskatos do you have an example perhaps? I tried the following, but it didn't yield any result:

class.reflect().getDeclaredField("myField").getType().getAnnotations()

@eskatos
Copy link

eskatos commented Feb 3, 2025

I did not try on a field but for a method return type I used:

JavaMethod method = ... arch unit;
method.reflect().getAnnotatedReturnType().getAnnotation(Foo.class);

For fields I expect this to work:

JavaClass clazz = ... arch unit;
clazz.reflect().getDeclaredField("myField").getAnnotatedType().getAnnotation(Foo.class);

@ivan-p92
Copy link
Author

ivan-p92 commented Feb 3, 2025

Ah, great, thanks, getAnnotatedType() does the trick! 👌 So the following is indeed a valid workaround:
clazz.reflect().getDeclaredField("myField").getAnnotatedType().getAnnotation(Nullable.class)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants