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

Detect TYPE_USE annotations for extended or implemented classes #662

Closed
raner opened this issue Mar 15, 2022 · 7 comments
Closed

Detect TYPE_USE annotations for extended or implemented classes #662

raner opened this issue Mar 15, 2022 · 7 comments

Comments

@raner
Copy link

raner commented Mar 15, 2022

My use case requires me to collect classes that have a TYPE_USE annotation on an extended or implemented type (i.e., after the extends or implements keyword).

For example:

import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE_USE;

public interface Interface {}

@Target(TYPE_USE)
@interface Special {}

class Implementation implements @Special Interface
{
  //...
}

ClassGraph appears to be able to process TYPE_USE annotation in many other scenarios but not the case where the annotation marks an extended or implemented type.

@lukehutch
Copy link
Member

@raner Thanks for the request. I don't even know what this sort of annotation is called. Was this annotation feature released as part of type annotation support?

Here is where type annotations are added to classes after extends or implements:

} else if (targetType == 0x10) {

So this should work... I'll write a unit test and try to figure out what's wrong...

@lukehutch
Copy link
Member

OK, I figured out where this is breaking down...

If you use

class Implementation<X> implements @Special Interface

then you can get the annotated implements class by calling scanResult.getClassInfo("Implementation").getTypeSignature() to get the type signature as a ClassTypeSignature, then .getSuperclassSignature().getTypeAnnotationInfo() to get the annotated type. (Incidentally this uncovered a toString() bug for the returned ClassTypeSignature, which I'll fix.)

However in this case, for the example you gave, the class has no generic type signature, because it's not a generic class. In this case, I have no idea where to store the type annotations for the superclass or interface -- these are usually attached to a type signature. And classes don't have a non-generic type descriptor like methods or fields do. The type annotation can't be attached to scanResult.getClassInfo("Implementation").getSuperclass() because that returns a ClassInfo for the superclass, which has nothing to do with the specific implementing class, Implementation.

I think the right thing to do in this case is to add a .getTypeDescriptor() and .getTypeDescriptorOrTypeSignature() to ClassInfo, to match FieldInfo and MethodInfo, then if the type signature doesn't exist, the type annotations can be added to the type descriptor instead. I'll have to simulate the type descriptor for the class based on the superclass and implemented interfaces. But since there is no type descriptor and no type signature, the superclass and interfaces could get out of order relative to the type annotation info contained in the class attributes -- so the result could put the wrong annotation on the wrong class, if there are multiple classes between the superclass and any implemented interfaces. So maybe this is not the right approach...

Any ideas as to what to do here? Do I need to add a special API here just to get the type annotations on superclasses and interfaces?

@raner
Copy link
Author

raner commented Mar 18, 2022

Thanks for looking into this, Luke. I think I'll have to familiarize a little bit more with how these annotations work under the hood; sounds like I opened quite the can of worms there ;-) I hope I can come up with some suggestions in the next couple of days.

@lukehutch
Copy link
Member

OK, I fixed this... I added a method ClassInfo@getTypeSignatureOrTypeDescriptor() that will try to get the ClassTypeSignature of the class, if it is a generic class, and if not, it synthesizes a new "class descriptor" (basically a class signature without any generic information), which the type annotations of the class can be added to. You should be able to get all the annotation info from the returned ClassTypeSignature.

This will be in the next release. Thank you for the request, and sorry it took so long!

@lukehutch
Copy link
Member

Released in 4.8.142. Thank you!

@raner
Copy link
Author

raner commented Mar 26, 2022

Thank you, Luke! This should solve my use case. Thanks for coming up with a solution so quickly!

@lukehutch
Copy link
Member

You're welcome!

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

2 participants