Get Annotation Parameter with AspectJ - aspectj

I read many question in this forum but nothing works.
public #interface MyAnnotation {
String value() default "";
Class[] exceptionList;
}
#MyAnnotation(value="hello", exceptionList={TimeOutException.class})
public void method() {}
#Aspect
public class MyAspect {
#Around("#annotation(MyAnnotation)")
public Object handle(ProceedingJoinPoint joinPoint, MyAnnotation myAnnotation) {
System.out.println(myAnnotation.exceptionList); // should print out TimeOutException
}
}
How can I get the value and the exceptionList of the #MyAnnotation while executing the advice?
I'm using Spring 4.0.6, AspectJ 1.7.4

The solution for this is making sure the advice method's parameter name match the parameter name in AspectJ expression. In my case, the advice method should look like this:
#Aspect
public class MyAspect {
#Around("#annotation(myAnnotation)")
public Object handle(ProceedingJoinPoint joinPoint, MyAnnotation myAnnotation) {
System.out.println(myAnnotation.exceptionList); // should print out TimeOutException
}
}

You are already almost there. Probably.
You are using the correct way to retrieve the annotation, so you have the values available.
Your problem - if I interpret the very minimalistic problem description(!) you only provide via the comment in your code snippet(!) correctly - is the (wrong) assumption that sticking an array of the type Class into System.out.println() will print out the names of the Classes it contains. It does not. Instead it prints information about the reference:
[Ljava.lang.Class;#15db9742
If you want the names of the Classes, you will have to iterate over the elements of that array and use .getName(), .getSimpleName() or one of the other name providing methods of Class.
Further information on how to print elements of an array is here:
What's the simplest way to print a Java array?
Granted, this whole answer could be entirely besides the point if the problem is that you are getting null values from the annotation fields. But since you have not provided an adequate problem description ("nothing works" is not a problem description!), we can only guess at what your problem is.

Related

Aspect does not trigger around repositories in my application

I want to trigger my aspect for classes annotated with repositories and belonging to my packages, for example this one:
//com.foo.myapp.bar.repositories.dao
#Repository
public class MyRepo extends JpaRepository<MyEntity, String>{
My classes are jpa repositories created like this:
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "firstManagerFactory",
transactionManagerRef = "firstTransactionManager",
basePackages = {"com.foo.myapp.bar.repositories.first.dao"}
)
public class DbConfig {
My aspect is the following but only activates if I leave the repository() pointcut, but if I also specify application packages it doesn't work:
#Pointcut("within(#org.springframework.stereotype.Repository *)")
private void repositoryInvocation() {
// Method is empty as this is just a Pointcut, the implementations are in the advices.
}
#Pointcut("within(com.foo.myapp..*)")
public void applicationPackage() {
// Method is empty as this is just a Pointcut, the implementations are in the advices.
}
#Around("repositoryInvocation() && applicationPackage()") //this && doesn't work, I have to remove the second one
public Object aspectTriggers(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed();
return result;
}
What am I missing?
edit:
I think I got it: problem is that the implementation of the repository does not belong to my application package, but to spring's SimpleJPARepository. It's like the aspect is only working on the implementation, totally ignoring the interface.
I think you do not want
#Pointcut("within(#org.springframework.stereotype.Repository *)")
but rather
#Pointcut("#within(org.springframework.stereotype.Repository)")
Be careful with your pointcut syntax, the two are not the same:
within() describes a package or class name you want to scope/limit your pointcut to.
#within() looks for a type (class) with the given annotation.
You want the latter, not the former.
Edit: On a second thought, actually I see no obvious reason why the first version should not work, even though it is a bit more complicated than the second.
But you said that you had problems with the second pointcut anyway. Are you 100% sure that your repository class really is in a com.foo.myapp (sub) package? No typo in either the package name or the pointcut? Actually, without trying and only looking at it, it should work otherwise.

Interface query parameter parsing?

I believe this is not possible, but I just wanted to verify.
I would like to do something like...
#Path("/awesome")
public class MyRestResource {
#GET
public void coolQuery(#QueryParam("user") User) {
// ...
}
}
public interface User {
String name();
Address address();
}
(Please don't comment on the example... it's completely made-up and not my use case.)
I imagine this is not possible because Jersey/JAX-RS generally requires a static method public static T valueOf(String input) which obviously is not possible with interfaces.
That said, is there any work-around for this to have a query parameter be an interface? And if so, how do you specify the parser / parsing logic?
Thanks
According to the documentation there are more ways than just the static valueOf method:
Be a primitive type;
Have a constructor that accepts a single String argument;
Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String) and java.util.UUID.fromString(String));
Have a registered implementation of javax.ws.rs.ext.ParamConverterProvider JAX-RS extension SPI that returns a javax.ws.rs.ext.ParamConverter instance capable of a "from string" conversion for the type. or
Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2 or 3 above. The resulting collection is read-only.
The solution using a ParamConverterProvider should work in this case.

use GwtCreateResource to provide text programatically

I would like my uiBinder to use a ClientBundle which will provide some runtime customized labels. Kind of a TextResource but not from a text file !
I tried with GwtCreateResource but from the DevGuide it seems like it's not possible. Am I right ? (create() and name() are the only methods available)
What I would like to achieve is something like this:
client bundle:
public interface MyWidgetResources extends ClientBundle {
GwtCreateResource<WidgetLabels> labels();
#Source("lol.css")
CssResource style();
}
labels class:
public final class MyWidgetLabels {
public String title() {
return load("mywidget-title");
}
public String banner() {
return load("mywidget-banner");
}
private String load(String key) {
// load from external..
}
}
uiBinder:
<ui:with type="com.package.MyWidgetResources" field="res"/>
<gwt:SimplePanel>
<gwt:Label text="{res.labels.title}"></gwt:Label>
<gwt:Label text="{res.labels.banner}"></gwt:Label>
</gwt:SimplePanel>
My code looks like this already but res.label.title does not work because GwtCreateResource can only serve as class instantiator (res.labels.create().title()).
Is there a solution for me ? Maybe with a custom ResourceGenerator ?
As long as MyWidgetLabels can be created by GWT.create, you can put anything you want into that type, and you can make it behave however you'd like. You will need the create reference in your uibinder as you suggested at the end of the post to actually build the object, so your lines will look about like this:
<gwt:Label text="{res.labels.create.title}"></gwt:Label>
Each . separated piece (except the first, which is a ui:field/#UiField) is a no-arg method to be called - you declared labels() in MyWidgetResources, create() already existed in GwtCreateResource, and you created title() in your own MyWidgetLabels type.
Since that first piece is a ui:field/#UiField, you could have another that references res.labels.create as something like labels so that later you could instead say:
<gwt:Label text="{labels.title}"></gwt:Label>
Finally, yes, you could build your own ResourceGenerator which would enable you to do whatever you wanted to emit the type in question, as long as you extended the ResourcePrototype type and had a getName() method.

Groovy getProperty() on a static member

This question is probably going to illustrate a lack of knowledge on my part about how Groovy classes work, but I have tried to figure this out on my own with no luck. I want to create a getProperty() method on a class so I can reference member variables in a Groovyish way. This is NOT the same as just making them public because I do want some logic done when they are referenced. Basically, I'm trying to create a configuration Groovy class that uses ConfigSlurper:
class Configuration implements GroovyObject {
private static ConfigObject config = new ConfigSlurper().parse(new File("testing.conf").toURI().toURL())
//This method is illegal, but it illustrates what I want to do
public static String getProperty(String prop){
config.getProperty(prop)
}
}
If the above class were legal, I could then reference config items like so:
Configuration.dbUser
instead of this, which would require making the ConfigObject available:
Configuration.config.dbUser
I know, it would be worlds easier to just make the config object public, but knowing how to do this (or know why it's impossible) would help me understand Groovy a little better.
The only way I can get it to work is via the metaClass:
class Configuration {
private static ConfigObject config = new ConfigSlurper().parse( "foo = 'bar'" )
}
Configuration.metaClass.static.propertyMissing = { name ->
delegate.config[ name ]
}
println Configuration.foo
There may be a better way however...

Is it possible to find all classes annotated with #MyAnnotation using a GWT GeneratorContext?

While creating classes using Generators, it's possible to discover all subclasses of a type. You can find this technique for example in the GWT Showcase source (see full code):
JClassType cwType = null;
try {
cwType = context.getTypeOracle().getType(ContentWidget.class.getName());
} catch (NotFoundException e) {
logger.log(TreeLogger.ERROR, "Cannot find ContentWidget class", e);
throw new UnableToCompleteException();
}
JClassType[] types = cwType.getSubtypes();
I would like to do something similar, but instead of extending a class (or implementing an interface)
public class SomeWidget extends ContentWidget { ... }
, could I also do this by annotating Widgets?
#MyAnnotation(...)
public class SomeWidget extends Widget { ... }
And then finding all Widgets that are annotated with #MyAnnotation? I couldn't find a method like JAnnotationType.getAnnotatedTypes(), but maybe I'm just blind?
Note: I was able to make it work with the Google Reflections library, using reflections.getTypesAnnotatedWith(SomeAnnotation.class), but I'd prefer using the GeneratorContext instead, especially because this works a lot better when reloading the app in DevMode.
Yes - easiest way is to iterate through all types, and check them for the annotation. You might have other rules too (is public, is non-abstract) that should also be done at that time.
for (JClassType type : oracle.getTypes()) {
MyAnnotation annotation = type.getAnnotation(MyAnnotation.class);
if (annotation != null && ...) {
// handle this type
}
}
The TypeOracle instance can be obtained from the GeneratorContext using context.getTypeOracle().
Note that this will only give you access to types on the source path. That is, only types currently available based on the modules being inherited and <source> tags in use.