Java reflection: annotation not found even if it's present - java

I'm using reflection for find a method in a class and the get the annotation "PermessiNecessari" that describe the type of the operation (CREATE, DELETE,...) that a method implements.
This is a piece of authorization check implementing a picketlink class PathAuthorizer.
I get a called url, i split it and from the url i find the class that implements the web service. Then I search for the method that it will be called and read what type of operation it use.
This is a piece of the searching-method :
Class facadeinterface = Class.forName(pm); // get the interface
Method metodo = getMetodoClasse(facadeinterface, metodoRest); // find method with #Path annotation
if(metodo != null){
PermessiNecessari rp = metodo.getAnnotation(PermessiNecessari.class);
if(rp != null){ // caso metodo con permessi
return checkPermessiModulo(m, rp);
}
if(metodo.isAnnotationPresent(NonProtetto.class)){
return true;
}
LOG.log(Level.WARNING, "Metodo trovato : {0}/{1}, ma non annotato!", new Object[]{metodoRest,metodo});
For istance, this is the checked class:
public interface VlpgmoduliManagerFacadeRemote
extends InterfacciaFacadeRemote<Vlpgmoduli>{
#POST
#javax.ws.rs.Path("getpermessimoduligruppo")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
#PermessiNecessari(operation = STANDARD_OP.READ)
public GridResponse<Vlpgmoduli> getPermessiModuliGruppo(MultivaluedMap<String, String> formParams,
String callback)
throws BadRequestException;
...
The method is found via #javax.ws.rs.Path annotation, but when i want to get "PermessiNecessari" annotation, this annotation is not found!
PS : in other classes this system works fine.
The method in the parent interface are not found too!
Tryed with another interface that extends the same interface and all the methods (the inherited too) are found.
This is my annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface PermessiNecessari {
Class resourceClass() default void.class;
String operation() default "";
String modulo() default "";
}
This is the method for searching the method that implement the web service:
private Method getMetodoClasse(Class facade, String metodo){
for(Method method : facade.getMethods()){
Path p = method.getAnnotation(Path.class);
if(p != null && ( p.value().equals(metodo) || p.value().equals("/"+metodo) )){
return method;
}
}
for (Class c : facade.getInterfaces()) {
for (Method method : c.getDeclaredMethods()) {
Path p = method.getAnnotation(Path.class);
if(p != null && ( p.value().equals(metodo) || p.value().equals("/"+metodo) )){
return method;
}
}
}
return null;
}
EDIT :
It's not a problem of annotation. I tryed with this check:
public boolean haAnnotazione(Method method, Class annotationType){
Annotation annotazioni[] = method.getAnnotations();
for(Annotation a : annotazioni){
if(a.annotationType().getName().equals(annotationType.getName())){
return true;
}
}
return false;
}
if I use a.annotationType().equals(annotationType) it returns false even if they are the same; if i use the name of the class, it works!
Maybe a classloader problem? The software run in Wildfly.

Solved!
It was a dependency error. There were 2 different dependencies version in the project, so the loaded annotations were really two different classes.
For the next time: check in your pom.xml for different dependencies if you have some cast exception or if two equal Class are not equal.
...really not solved, there is a classloader problem between class in EAR/lib and in WAR/lib, but this is another question

#PermessiNecessari must be of Runtime retention because compiler will remove not incluide information about that annotation into the bytecode if retention will be different.
That is why your annotation is not found upon runtime - it is not there.

Related

Accessing Reactive CRUD repository from MapStruct Mapper stuck in block()

I am somewhat new to Spring and have recently generated a JHipster monolith application with the WebFlux option. My current aim is to make it compatible with Firestore and implement some missing features like inserting document references. To do so, I am currently having the following structure:
A domain object class "Device" which holds a field String firmwareType;
A domain object class "FirmwareType"
A DTO object DeviceDTO which holds a field FirmwareType firmwareType;
Correspondingly, I also have the corresponding Repository (extending FirestoreReactiveRepository which extends ReactiveCrudRepository) and Controller implementations, which all work fine. To perform the conversion from a "full object" of FirmwareType in the DTO-object to a String firmwareTypeId; in the Device-object, I implemented a MapStruct Mapper:
#Mapper(unmappedTargetPolicy = org.mapstruct.ReportingPolicy.IGNORE, componentModel = "spring")
public abstract class DeviceMapper {
private final Logger logger = LoggerFactory.getLogger(DeviceMapper.class);
#Autowired
protected FirmwareTypeRepository fwTypeRepo;
public abstract Device dtoToDevice(DeviceDTO deviceDTO);
public abstract DeviceDTO deviceToDto(Device device);
public abstract List<DeviceDTO> devicesToDTOs(List<Device> devices);
public abstract List<Device> dtosToDevices(List<DeviceDTO> dtos);
public String map(FirmwareType value) {
if (value == null || value.getId() == null || value.getId().isEmpty()) {
return null;
}
return value.getId();
}
public FirmwareType map(String value) {
if (value == null || value.isEmpty()) {
return null;
}
return fwTypeRepo.findById(value).block(); // <<-- this gets stuck!
}
}
The FirmwareTypeRepository which is autowired as fwTypeRepo field:
#Repository
public interface FirmwareTypeRepository extends FirestoreReactiveRepository<FirmwareType> {
Mono<FirmwareType> findById(String id);
}
The corresponding map functions get called perfectly fine, but the fwTypeRepo.findById(..) call in the marked line (third-last line) seems to get stuck somewhere and never returns or throws an error. When the "fwTypeRepo" via its Controller-endpoint is called, it works without any issues.
I suppose it must be some kind of calling context issue or something? Is there another way to force a result by Mono synchronously than block?
Thanks for your help in advance, everyone!
Edit: At this point, I am sure it has something to do with Autowiring the Repository. It seems to not correctly do so / use the correct instance. While a customized Interface+Impl is called correctly, the underlying logic (from FirestoreReactive/ReactiveCrudRepository) doesn't seem to supply data correctly (also when #Autowire is used in other components!). I found some hints pointing at the package-structure but (i.e. Application class needs to be in a root package) but that isn't an issue.
Mapstruct is not reactive as i know so this approach won't work, you'll need mapstruct to return a mono that builds the object itself but that wouldn't make sense as it's a mapping lib which is only for doing blocking things.
Could try use 2 Mono/Mappers, 1 for each DB call and then just Mono.zip(dbCall1, dbCall2) and set the the mapped db call output into the other objects field.
var call1 = Mono.fromFuture(() -> db.loadObject1()).map(o -> mapper1.map(o));
var call2 = Mono.fromFuture(() -> db.loadObject2()).map(o -> mapper2.map(o));
Mono.zip(call1, call2)
.map(t -> {
var o1 = t.getT1();
var o2 = t.getT2();
o1.setField(o2);
});

Can an `ElementVisitor` be used to traverse the statements in the body of a method?

I'm trying to make a custom annotation that checks to see if a certain method is called in a method's body annotated with it. Something like:
#TypeQualifierDefault(ElementType.METHOD)
#Retention(RetentionPolicy.SOURCE)
#interface MutatingMethod {
}
interface Mutable {
void preMutate();
void postMutate();
// other methods
}
And then within a certain Mutable class we would have:
class Structure<T> implements Mutable {
#MutatingMethod
void add(T data) {
preMutate();
// actual mutation code
postMutate();
}
}
I want to be able to get warnings of some sort if the body of a method like add that is annotated with #MutatingMethod does not include calls to preMutate and postMutate. Can an ElementVisitor (javax.lang.model.element.ElementVisitor) be used to traverse the (possibly obfuscated) statements and method calls in the body of a method? If so what would that look like? If not what else can I use?
Just to clarify, I know this is impossible (or more difficult) to accomplish in runtime via bytecode decompilation, so this annotation is meant to only work during compilation via reflection (java.lang.reflect.* and javax.lang.model.*) and is not retained in class files.
You are free to modify the code however you want to get it to work, for example by introducing a new annotation called #MutableType that Structure and any other Mutable types must be annotated with it for this to work.
A cherry on top would be to assert that preMutate is called before postMutate and not after.
It shouldn't matter but I'm using Gradle and the IntelliJ IDEA IDE.
Any help is greatly appreciated; material on this is strangely scarce and/or inadequate on the web. I have been using publicly available sources to learn about this!
There are two modules,
java.compiler which contains the API for annotation processors and the simple abstraction you have already discovered.
The ElementVisitor abstraction does not support digging into the method’s code.
The jdk.compiler module, containing an extended API originally not considered to be part of the standard API and hence not included in the official API documentation prior to the introduction of the module system.
This API allows analyzing the syntax tree of the currently compiled source code.
When your starting point is an annotation processor, you should have a ProcessingEnvironment which was given to your init method. Then, you can invoke Trees.instance(ProcessingEnvironment) to get a helper object which has the method getTree(Element) you can use to get the syntax tree element. Then, you can traverse the syntax tree from there.
Most of these classes documented in the JDK 17 API do already exist in earlier versions (you might notice the “since 1.6”) even when not present in the older documentation. But prior to JDK 9 you have to include the lib/tools.jar of the particular JDK into your classpath when compiling the annotation processor.
(when writing a modular annotation processor)
import javax.annotation.processing.Processor;
module anno.proc.example {
requires jdk.compiler;
provides Processor with anno.proc.example.MyProcessor;
}
 
package anno.proc.example;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import com.sun.source.tree.*;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.util.Trees;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
#SupportedSourceVersion(SourceVersion.RELEASE_17) // adapt when using older version
#SupportedAnnotationTypes(MyProcessor.ANNOTATION_NAME)
public class MyProcessor extends AbstractProcessor {
static final String ANNOTATION_NAME = "my.example.MutatingMethod";
static final String REQUIRED_FIRST = "preMutate", REQUIRED_LAST = "postMutate";
// the inherited method does already store the processingEnv
// public void init(ProcessingEnvironment processingEnv) {
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Optional<? extends TypeElement> o = annotations.stream()
.filter(e -> ANNOTATION_NAME.contentEquals(e.getQualifiedName())).findAny();
if(!o.isPresent()) return false;
TypeElement myAnnotation = o.get();
roundEnv.getElementsAnnotatedWith(myAnnotation).forEach(this::check);
return true;
}
private void check(Element e) {
Trees trees = Trees.instance(processingEnv);
Tree tree = trees.getTree(e);
if(tree.getKind() != Kind.METHOD) { // should not happen as compiler handles #Target
processingEnv.getMessager()
.printMessage(Diagnostic.Kind.ERROR, ANNOTATION_NAME + " only allowed at methods", e);
return;
}
MethodTree m = (MethodTree) tree;
List<? extends StatementTree> statements = m.getBody().getStatements();
if(statements.isEmpty() || !isRequiredFirst(statements.get(0))) {
processingEnv.getMessager()
.printMessage(Diagnostic.Kind.MANDATORY_WARNING,
"Mutating method does not start with " + REQUIRED_FIRST + "();", e);
}
// open challenges:
// - accept a return statement after postMutate();
// - allow a try { body } finally { postMutate(); }
if(statements.isEmpty() || !isRequiredLast(statements.get(statements.size() - 1))) {
processingEnv.getMessager()
.printMessage(Diagnostic.Kind.MANDATORY_WARNING,
"Mutating method does not end with " + REQUIRED_LAST + "();", e);
}
}
private boolean isRequiredFirst(StatementTree st) {
return invokes(st, REQUIRED_FIRST);
}
private boolean isRequiredLast(StatementTree st) {
return invokes(st, REQUIRED_LAST);
}
// check whether tree is an invocation of a no-arg method of the given name
private boolean invokes(Tree tree, String method) {
if(tree.getKind() != Kind.EXPRESSION_STATEMENT) return false;
tree = ((ExpressionStatementTree)tree).getExpression();
if(tree.getKind() != Kind.METHOD_INVOCATION) return false;
MethodInvocationTree i = (MethodInvocationTree)tree;
if(!i.getArguments().isEmpty()) return false; // not a no-arg method
ExpressionTree ms = i.getMethodSelect();
// TODO add support for explicit this.method()
return ms.getKind() == Kind.IDENTIFIER
&& method.contentEquals(((IdentifierTree)ms).getName());
}
}
Annotation processors only process declarations, not bytecode. They can not be used to make assertions about the content of a method.
If it is important to you that these methods are always called, you may want to enforce this with a proxy rather than having boilerplate code in each method. For instance, you could use a bytecode engineering library such as Javassist to add the calls at runtime:
var f = new ProxyFactory();
f.setSuperclass(Foo.class);
f.setFilter(m -> m.isAnnotationPresent(MutatingMethod.class));
Class c = f.createClass();
Foo foo = c.newInstance();
((Proxy)foo).setHandler((self, m, proceed, args) -> {
self.preMutate();
proceed.invoke(self, args);
self.postMutate();
});
foo.setName("Peter"); // automatically calls preMutate and postMutate()
(code untested, since I don't have an IDE at hand)
Then, the methods are always called in the proper order, as long as you control the creation of the objects in question (which you can sort of enforce by making the super class abstract).

Is there a Maven plugin for checking annotations presence in code?

I need to ensure that, in specific classes (e.g. all classes extending some other class), fields annotated with e.g. #Deprecated are also annotated with #ThisOtherAnnotationMustBeHere.
#Deprecated
#ThisOtherAnnotationMustBeHere // this must be present if #Deprecated is also present; otherwise build should fail
private String field;
I need in general something to check for the presence of annotations.
I guess I could write a JUnit test for this using reflection, but I was wondering if there was a Maven solution to this.
Following #khmarbaise suggestion (thanks!) I've used archunit.org to write a unit test for this. In my case I needed to verify that join fields in JPA entities were annotated with a specific custom JsonAdapter
class CodeChecksTest {
#ArchTest
public static final ArchRule persistenceIdAnnotationRule = fields().that()
.areDeclaredInClassesThat().areAnnotatedWith(Entity.class).and()
.areAnnotatedWith(OneToOne.class).or()
.areAnnotatedWith(OneToMany.class).or()
.areAnnotatedWith(ManyToOne.class).or()
.areAnnotatedWith(ManyToMany.class)
.should(beAnnotatedForMyCustomAdapter());
private static ArchCondition<? super JavaField> beAnnotatedForMyCustomAdapter() {
return new ArchCondition<JavaField>("annotated with #JsonAdapter(MyCustomAdapter.class)") {
#Override
public void check(JavaField item, ConditionEvents events) {
final Optional<JsonAdapter> annotation = item.tryGetAnnotationOfType(JsonAdapter.class);
final boolean satisfied = annotation.isPresent() && annotation.get().value() == MyCustomAdapter.class;
// createMessage is a utility method
String message = createMessage(item,
(satisfied ? "is " : "is not ") + getDescription());
events.add(new SimpleConditionEvent(item, satisfied, message));
}
};
}
}

Spring AOP custom annotation, getting Null with annotation arguments

I am using this custom annotation for logging execution time, annotation could be present on method or class in which all public methods have it. Everything works fine, except in case of method level "LogExecutionTime logExecutionTime" comes null. This throws an NPE.
#Around("#annotation(logExecutionTime) || #within(logExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
final String name = joinPoint.toShortString();
final StopWatch stopWatch = new StopWatch(name);
stopWatch.start(name);
try {
return joinPoint.proceed();
} finally {
stopWatch.stop();
if (logExecutionTime.value()) {
logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeSeconds());
}
}
}
if I reverse the order-
#Around("#within(logExecutionTime) || #annotation(logExecutionTime)")
the behavior reverses and I get a valid object at method level and null at class level annotated methods.
I have worked around this by having 2 explicit methods and separating the two-
#Around("#within(logExecutionTime)")
public Object logExecutionTimeClassLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
return logExecutionTimeMethodLevel(joinPoint, logExecutionTime);
}
#Around("#annotation(logExecutionTime)")
public Object logExecutionTimeMethodLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
final String name = joinPoint.toShortString();
final StopWatch stopWatch = new StopWatch(name);
stopWatch.start(name);
try {
return joinPoint.proceed();
} finally {
stopWatch.stop();
if (logExecutionTime.value()) {
logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeMillis());
}
}
Was hoping to understand this behavior, when we use OR '||' with two pointcuts.
class level
#LogExecutionTime
#Component
public class CleanUpService implements ICleanUpService { ... }
method level
#Scheduled(fixedDelay = 100)
#LogExecutionTime(false)
public void processMessageQueue() { ... }
I came to run you example, and reproduce the same example as yours, when it come to runtime expression is same weird because when you specify the annotation on class level and you write this expression
#Around(" #within(logExecutionTime) || #annotation(logExecutionTime) ")
The point cut will evaluate to true for you class (event you annotation its available in joinPoint.getTarget().getClass().getAnnotations(), )
Now when it come to binding the variable the compiler check all your expressions that mean binding #within(logExecutionTime) to variable logExecutionTime and #annotation(logExecutionTime) to the same variable , if the method is not annotated it will ge null, => override the initial with, that cause all senarios you mention.
Try to put this expression #within(logExecutionTime) || #annotation(logExecutionTime) || #within(logExecutionTime)
and you'll get you variable not null which prove what i said, last #within(logExecutionTime) override what precedent
The key here is that the logic applied to select the point cut matching not the same when it come context-binding
Now when it come to AOP point-cut you must be careful and follow best practice as the spring team they mention here to avoid weird runtime results
Cheers
This cannot work, it does not even compile with the AspectJ compiler. Maybe in your IDE and with Spring AOP you do not see any warnings or errors, but I see:
ambiguous binding of parameter(s) logExecutionTime across '||' in pointcut
This means that it is not clear which annotation should be selected if e.g. both the class and the method contain an instance of that annotation. It is, as the error message said, ambiguous. But ambiguous parameter bindings across || are not permitted. They can also happen if you try to bind values from different "or" branches to a single parameter in an args() list.
I had the same problem. What you want is exactly same as Spring #Transcriptional behaves (I mean, class level or method level annotation with parameters). I used your solution but to get the class level parameter value (as the annotation object received null), I used reflection. I know it is a dirty solution! But I tried other solutions and couldn't find!
Her is the full code. This will call the advice code either the annotation is used on a class or a method. If the annotation is placed on both (class and method), the method takes the precedence.
#Aspect
#Configurable
#Component
public class DynamicValueAspect {
#Around(" #within(dynamicValueAnnotation) || #annotation(dynamicValueAnnotation))")
public Object process(ProceedingJoinPoint joinPoint, DynamicValue dynamicValueAnnotation) throws Throwable {
String annotationParameter;
if (dynamicValueAnnotation == null) { //class level annotation
annotationParameter = extractClassLevelAnnotationParameterValue(joinPoint);
} else {
annotationParameter = dynamicValueAnnotation.myAnnotationParameter();
}
System.out.println(" " + annotationParameter);//get the annotation parameter value
return joinPoint.proceed();
}
private String extractClassLevelAnnotationParameterValue(ProceedingJoinPoint joinPoint) {
Annotation[] classAnnotations = joinPoint.getTarget().getClass().getAnnotations();
for (Annotation annotation : classAnnotations) {
if (annotation.annotationType() == DynamicValue.class) {
return ((DynamicValue) annotation).myAnnotationParameter();
}
}
throw new RuntimeException("No DynamicValue value annotation was found");
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface DynamicValue {
String myAnnotationParameter();
}
Let's know if you got a cleaner solution!
The problem with your workaround appears when you annotate both a class and a method with the annotation, resulting in triggering both of them.
To prevent it declare the class level advice as:
#Around("!#annotation(LogExecutionTime) && #within(logExecutionTime)")

Picketlink: How to get annotation parameters and the name of the function decorated when using #Secures?

I'm trying to define and use a custom security binding type called BasicRolesAllowed, as has been demonstrated in the Picketlink quickstarts here.
The only different between my type the ones in the quickstart, is that my annotation has to accept an array of strings (we want to secure methods using not just one but possibly combinations of roles), and thus my annotation is defined thus:
public #interface BasicRolesAllowed {
String[] value() default {};
}
Following the quickstart, I've tried to define how this decorator authenticates as such:
#Secures
#BasicRolesAllowed
public boolean doAdminCheck(Identity identity, IdentityManager identityManager, RelationshipManager relationshipManager) throws Exception {
/*
Sample usage of #BasicRolesAllowed is like:
#BasicRolesAllowed(value = RoleConstants.CREATE_USER)
TODO: need to get these from the #BasicRolesAllowed annotation instance/usage
*/
String[] requiredRoles = {};// get these from annotation
boolean isAuthorized = true;
for (String role : requiredRoles)
isAuthorized = isAuthorized && hasRole(relationshipManager, identity.getAccount(), getRole(identityManager, role));
return isAuthorized;
}
And as can be seen in the snippet, the trick part is:
String[] requiredRoles = {};// get these from annotation
How do I get the string constants passed to the annotation on the decorated method so I can use them in looking up roles?
Some Hints:
There's an answer to a similar question here, but the problem is that in that solution; one needs to know the name of the decorated function or class - which in my case is impossible given that the decorator will be used just about anywhere, and I don't know how to get these via the method shown in the Picketlink quickstart.
Also, the solution only shows how to obtain the value passed to an annotation expecting only 1 string - maybe I could try using values(), but the above limitation still stands in my way.
Thanks in advance to anyone who can help.
Thanks to #pedroigor over at #picketlink (freenode), the solution can be gleaned from an example of such a use-case in the picketlink quickstart here. In that file, a method getAnnotation() is defined, which has the signature:
private <T extends Annotation> T getAnnotation(InvocationContext invocationContext, Class<T> annotationType)
So, using this method, I'm able to introspect and obtain the values passed to my annotation as can be seen in my new implementation of the roles checking method here:
#Secures
#BasicRolesAllowed
public boolean hasBasicRolesCheck(InvocationContext invocationContext, Identity identity, IdentityManager identityManager, RelationshipManager relationshipManager) throws Exception {
BasicRolesAllowed basicRolesAllowed = getAnnotation(invocationContext,BasicRolesAllowed.class);
String[] requiredRoles = basicRolesAllowed.value();// get these from annotation
boolean isAuthorized = true;
for (String role : requiredRoles)
isAuthorized = isAuthorized && hasRole(relationshipManager, identity.getAccount(), getRole(identityManager, role));
return isAuthorized;
}
The essential modifications being:
I had to pass an instance of the invocation context InvocationContext invocationContext by adding this as a parameter to my method definition (CDI magic takes care of all else I hear).
I then obtain the annotation instance by calling:
BasicRolesAllowed basicRolesAllowed = getAnnotation(invocationContext,BasicRolesAllowed.class);
And then get the values/parameters passed to the annotation thus:
String[] requiredRoles = basicRolesAllowed.value();// get these from annotation
This solves my problem :-)

Categories