Play Framework annotation order - java

When I call fooMethod, I want to process first class annotation (with First.class - in my project this checks if user is logged) and then method annotation (with Second.class - in my project this checks if uses has desired rights to access this specific method. So I need to ensure user is logged first). Is there a way to do that?
#With(First.class)
public class Foo{
#With(Second.class)
public static void fooMethod(){
}
}
Also I wonder why custum action ignores annotation. Code below doesn't process anotation #With(First.class).
public class Foo2 extends Action<CustomAnnotation> {
#Override
#With(First.class)
public Promise<Result> call(Http.Context context) throws Throwable {
return delegate.call(context);
}
}
}
Similar unanswered question: Java + Play Framework 2 with nested action compositions in the same class

In Play 2.4 there appears to be an option for this from the docs here:
Note: If you want the action composition annotation(s) put on a
Controller class to be executed before the one(s) put on action
methods set play.http.actionComposition.controllerAnnotationsFirst =
true in application.conf. However, be aware that if you use a third
party module in your project it may rely on a certain execution order
of its annotations.
The note is only present in the 2.4 docs, so presumably it doesn't work in previous versions.

It looks like at least in Java 8 you have an order in annotation of the same kind: Java Annotations Reflection Ordering.

Related

Understanding the use of 'Annotations'

I'm trying to understand the use of 'Annotations' a bit better.
I understand that:
How to access annotations in my code for example via this complete tutorial.
I can create methods to perform desired operations
To understand this better, I created a virtual problem as following:
There are Annotations TestAnnotation1, TestAnnotation2, TestAnnotation3(definition is available latter in the question). I wants to execute the methods of class MethodsExecutorClass as following:
When TestClass.java compiles then execute CommonMethod() and RetentionPolicySOURCEMethod()
When TestClass.class loads then execute CommonMethod() and RetentionPolicyCLASSMethod()
Whenever testMethod() method of TestClass.java executes then execute CommonMethod() and RetentionPolicyRUNTIMEMethod()
By this example I wants to understand following:
Can I instruct Java compiler (javac) or Java Runtime Environment (jvm) to execute a method in my class(e.g. CommonMethod()andRetentionPolicySOURCEMethod()methods ofMethodsExecutorClass`).
Can I delegate the monitoring (i.e. searching the methods/classes which are using my annotation etc.) to any other entity(which is available in Java SE).
I want to do something like #Override and #deprecated annotations. We don't do something extra. Although on Oracle javadoc site, here it is clearly mentioned that The Java platform has always had various ad hoc annotation mechanisms. and #deprecated is one of them. But I wondered If I can do something like this.
Definitions should look like as following:
MyAnnotations.java:
#Retention(RetentionPolicy.SOURCE)
public #interface TestAnnotation1
{
String className();
}
#Retention(RetentionPolicy.CLASS)
public #interface TestAnnotation2
{
String className();
}
#Retention(RetentionPolicy.RUNTIME)
public #interface TestAnnotation3
{
String className();
String methodName();
}
MethodsExecutorClass.java:
class MethodsExecutorClass
{
public static void CommonMethod()
{
System.out.println("In method: CommonMethod()");
}
public void RetentionPolicySOURCEMethod()
{
System.out.println("In method: RetentionPolicySOURCEMethod()");
//Also print annotation arguments e.g. Class name etc
}
public void RetentionPolicyCLASSMethod()
{
System.out.println("In method: RetentionPolicyCLASSMethod()");
//Also print annotation arguments e.g. Class name etc
}
public void RetentionPolicyRUNTIMEMethod()
{
System.out.println("In method: RetentionPolicyRUNTIMEMethod()");
//Also print annotation arguments e.g. Class name etc
}
}
TestClass.java:
#TestAnnotation1(TestClass.class)
#TestAnnotation2(TestClass.class)
class TestClass
{
#TestAnnotation2(TestClass.class, "testMethod()")
public void testMethod()
{
System.out.println("In method: testMethod()");
}
}
May you help me in achieving this? (Please no guess or assumptions, but presumptions would be also helpful).
I'm not sure if this can be achieve, but looking forward.
Annotations with retention policy RetentionPolicy.SOURCE are only available during compilation time of the code so your compiler should support your annotation to use it, otherwise it's not possible to handle the annotation. Usually, such annotations are used to detect possible problems at compilation time, for example, annotation #Override. That's why your first problem can't be implemented in usual ways.
Annotations with retention policy RetentionPolicy.CLASS are available only in .class files and can be used via JVMs. Please see this answer how it can be used. The second your problem also can't be implemented via standard ways.
Commonly used annotations are with retention policy RetentionPolicy.RUNTIME that are available via reflection mechanism in Java. But to solve your third problem you have to use some method invocation interceptors, for example, via Aspect Oriented Programming. After that you can get method's annotations via method.getDeclaredAnnotations().
Can I instruct Java compiler (javac) or Java Runtime Environment (jvm)
to execute a method in my class(e.g.
CommonMethod()andRetentionPolicySOURCEMethod()methods
ofMethodsExecutorClass`).
No, you can't.
Can I delegate the monitoring (i.e. searching the methods/classes
which are using my annotation etc.) to any other entity(which is
available in Java SE).
You can do it via AOP, for example, use the library AspectJ.

Method with #Transactional called on target not on proxy instance

I'm currently migrating one of my projects form "self configured spring" to spring boot. while most of the stuff is already working I have a problem with a #Transactional method where when it is called the context is not present as set before due to a call to the "target" instance instead of the "proxy" instance (I'll try to elaborate below).
First a stripped down view of my class hierarchy:
#Entity
public class Config {
// fields and stuff
}
public interface Exporter {
int startExport() throws ExporterException;
void setConfig(Config config);
}
public abstract class ExporterImpl implements Exporter {
protected Config config;
#Override
public final void setConfig(Config config) {
this.config = config;
// this.config is a valid config instance here
}
#Override
#Transactional(readOnly = true)
public int startExport() throws ExporterException {
// this.config is NULL here
}
// other methods including abstract one for subclass
}
#Scope("prototype")
#Service("cars2Exporter")
public class Cars2ExporterImpl extends ExporterImpl {
// override abstract methods and some other
// not touching startExport()
}
// there are other implementations of ExporterImpl too
// in all implementations the problem occurs
the calling code is like this:
#Inject
private Provider<Exporter> cars2Exporter;
public void scheduleExport(Config config) {
Exporter exporter = cars2Exporter.get();
exporter.setConfig(config);
exporter.startExport();
// actually I'm wrapping it here in a class implementing runnable
// and put it in the queue of a `TaskExecutor` but the issue happens
// on direct call too. :(
}
What exactly is the issue?
In the call to startExport() the field config of ExporterImpl is null although it has been set right before.
What I found so far:
With a breakpoint at exporter.startExport(); I checked the id of the exporter instance shown by eclipse debugger. In the debbug round while writing this post it is 16585. Continuing execution into the call/first line of startExport() where i checked the id again (of this this time) expecting it to be the same but realizing that it is not. It is 16606 here... so the call to startExport() is done on another instance of the class... in a previous debug round i checked to wich instance/id the call to setConfig() is going... to the first on (16585 in this case). This explains why the config field is null in the 16606 instance.
To understand what happens between the line where i call exporter.startExport(); and the actuall first line of startExport() i clicked into the steps between those both lines in eclipse debugger.
There i came to line 655 in CglibAopProxy that looks like this:
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
checking the arguments here i found that proxy is the instance with id 16585 and target the one with 16606.
unfortunately I'm not that deep into springs aop stuff to know if that is how it should be...
I just wonder why there are two instances that get called on diffrent methods. the call to setConfig() goes to the proxy instance and the call do startExport() reaches the target instance and thus does not have access to the config previously set...
As mentioned the project has been migrated to spring boot but we where before already using the Athens-RELEASE version of spring platform bom. From what i can tell there where no special AOP configurations before the migration and no explicitly set values after the migration.
To get this problem fixed (or at least somehow working) i already tried multiple things:
remove #Scope from the sub class
move #Transactional from method level to class
override startExport() in subclass and put #Transactional here
add #EnableAspectJAutoProxy to application class (i wasn't even able to log in - no error message)
set spring.aop.proxy-target-class to true
the above in diffrent combinations...
Currently I'm out of clues on how to get this back working...
Thanks in advance
*hopes someone can help*
Spring Boot tries to create a cglib proxy, which is a class based proxy, before you probably had an interface based (JDK Dynamic Proxy).
Due to this a subclass of your Cars2ExporterImpl is created and all methods are overridden and the advices will be applied. However as your setConfig method is final that cannot be overridden and as a result that method will be actually called on the proxy instead on the proxied instance.
So either remove the final keyword so that CgLib proxy can be created or explicitly disable class based proxies for transactions. Add #EnableTransationManagement(proxy-target-class=false) should also do the trick. Unless there is something else triggering class based proxies that is.

Creating Custom Java Compiler Errors Without Using Annotations

Is there a way to add processors to the compiler without making annotations?
Basically, I would like for the build to fail if a user did not implement an interface correctly (ie. postconditions are not fulfilled). At compile time, I would like to check if a class implements an interface, and if it does, run some code to check if the implementation is correct.
For example, I would like to ensure that classes that implement getErrorMoniker() return a string in camelCase.
public interface MyError {
public String getErrorMoniker();
}
public class MyErrorImplemented1 {
#Override
public String getErrorMoniker() { return "goodErrorMoniker"; }
}
public class MyErrorImplemented2 {
#Override
public String getErrorMoniker() {
return "BADERRORMONIKER"; // I would like a compile error here
}
}
Any suggestions would be appreciated.
A processor annotated with #SupportedAnnotationTypes("*") should in theory be able to processs all source files as it also applies to an empty set of annotations. From the documentation:
If there are no annotation types present, annotation processing still occurs but only universal processors which support processing "*" can claim the (empty) set of annotation types.
Although you goal to check for return values probably won't work, since this happens compile time, not runtime.

Create a Java Annotation with IDE contextual behaviour

I've created an Annotation
/**
* Highlights this method is declared in XML
*/
public #interface FromXML {
}
I'm using this on methods that look like this:
#FromXML
public void onSomethingClick(View v){
}
The v variable is needed by the Android reflection system to call this method.
However the input var v is unused, so my IDE warns me of this. I like this warning and want it on for the rest of my code.
To hide the warning I could do
#SuppressWarnings("unused")
#FromXML
public void onSomethingClick(View v){
}
or I could add a param tag
But I would rather that the IDE (eclipse) reads my #FromXML annotation and doesn't give me the warning.
I know you can't extend an Annotation, but thats basically what I want to do.
Is there a way I can add my annotation to be recognised as a 'suppress warnings' annotation.
or
Is there a way to code my annotation to 'act like' suppress warnings?
You can always create a plugin for Eclipse, that would scan through the source and find these annotations in your case #FromXML and add an extra annotation in your case #SuppressWarnings.
You could create a Command for it and when that command is fired you would run this plugin.
Creating Eclipse Plugin
Hope this helps.
UPDATE - IT WAS A FLUKE CANNOT BE DONE USING THIS (TRIED IT):
Or Using AspectJ for removing the warnings
Adding warnings in Eclipse using AspectJ
This tutorial uses AspectJ for adding warnings to eclipse if developer uses System.out.println() in the code. So the reverse can be done to remove the warning when annotation is present.
UPDATE 2: There is a way in Eclipse to create custom annotation processor or editting the bundeled annotation processor (that generates the unused variable warning). So will have to tweak that processor in a custom way.
Some great links:
Tutorials for Eclipse Annotation processor development
Java Development Tools - Annotation Processing Tools
I think you could create an interface defining this method. That way, your class will override the method and there should not be any warning.
FromXML.java:
public #interface FromXML {
}
MyInterface.java:
public interface MyInterface {
#FromXML
public void onSomethingClick(View v);
}
MyClass.java
public MyClass implements MyInterface {
#Override
#FromXML
public void onSomethingClick(View v){
}
}
EDIT :
Another solution could be to define your method as abstract. Indeed, as I understand your code, your methods are just declaration (Implementations are in a XML file). So, your problem is more a design problem than an IDE problem (your IDE is just right about the warning). The reality is that your method is abstract and is defined somewhere else.
Thus, defining your method as abstract will solve the problem but you'll have to make the class abstract:
public abstract class MyClassUsingOnSomethingClick {
/*
* All the class implementation can be here as the normal class.
*/
#FromXML
public abstract void onSomethingClick(View v);
}
I know you'll say that this solution make it impossible to create object easily but you'll have two solutions then:
1 - Create your objects inline:
MyClassUsingOnSomethingClick a = new MyClassUsingOnSomethingClick() {
#Override
#FromXML
public void onSomethingClick(View v) {}
};
2 - Create a factory method in your abstract MyClassUsingOnSomethingClick:
public static final MyClassUsingOnSomethingClick createEmptyMyClassUsingOnSomethingClick() {
return new MyClassUsingOnSomethingClick() {
#Override
#FromXML
public void onSomethingClick(View v) {}
};
}
// and then, create with: :
MyClassUsingOnSomethingClick a = MyClassUsingOnSomethingClick.createEmptyMyClassUsingOnSomethingClick();
Even is I understand that you would prefer a faster solution, I believe that this solution is the cleanest because:
It respects the Object Oriented Programming philosophy.
It is not specific to an IDE.
It avoids Annotation Processing Tool (which, in my opinion should be used very wisely)
Ok I can't do this in any easy way or form.
Looking at the annotation package http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/package-summary.html
I can't extend an annotation:
Why is not possible to extend annotations in Java?
I can't implement another annotation java.lang.Override
I can't mimic / mock / pretend to be #Override
If I add #Override to my #FromXML it is NOT inherited down the chain.
The only way would be to create an Eclipse plugin that recognises my annotation and stops the warning. Shame because I can't find an easy way to do this.
I also went down the route of creating an interface for my #FromXML entry points, this was very nice and communicated my Activity was of a type and therefore I didn't need the annotation anymore, perhaps this design change is the answer.

How can I change annotations/Hibernate validation rules at runtime?

If have a Java class with some fields I want to validate using Hibernate Validator.
Now I want my users to be able to configure at runtime which validations take place.
For example:
public class MyPojo {
...
#NotEmpty
String void getMyField() {
...
}
...
}
Let's say I want to remove the NotEmpty check or replace it with Email or CreditCardNumber, how can I do it? Is it even possible? I guess it comes down to changing annotations at runtime...
You can't do it normally.
Here's what I've done to get more dynamic validations working via Hibernate Validator.
Extend the ClassValidator class.
Override the getInvalidVaues(Object myObj) method. First, call super.getInvalidValues(myObj), then add the hook to your customized validation.
Instantiate your custom validator and call getInvalidValues to validate. Any hibernate annotated validations will kick off at this point, and your custom dynamic validations (anything not supported by annotations) will kick off as well.
Example:
public class MyObjectValidator extends ClassValidator<MyObject>
{
public MyObjectValidator()
{
super(MyObject.class);
}
public InvalidValue[] getInvalidValues(MyObject myObj)
{
List<InvalidValue> invalids = new ArrayList<InvalidValue>();
invalids.addAll(Arrays.asList(super.getInvalidValues(myObj)));
// add custom validations here
invalids.addAll(validateDynamicStuff(myObj));
InvalidValue[] results = new InvalidValue[invalids.size()];
return invalids.toArray(results);
}
private List<InvalidValue> validateDynamicStuff(MyObject myObj)
{
// ... whatever validations you want ...
}
}
So your custom validation code can contain logic like "Do this validation, if the user configured it, otherwise do that one", etc. You may or may not be able to leverage the same code that powers the hibernate validations, but either way, what you are doing is more involved that the 'normal' use case for hibernate validator.
Actually it is possible in hibernate validator 4.1. Just read the documentation about programatic constraint creation.
I don't think you'll be able to remove or change the annotation, it's part of the class definition. You can build a new class, which is possible at runtime but a little involved. Hibernate may support programmatic access to the validations and allow you to override the annotation, I don't know the API that well. Hibernate does a bit of runtime class building itself... that might be a good place to learn how to do it if you're interested.

Categories

Resources