I'm trying to use a generic interface and generic class in an aspect for Spring framework using spring aop, i want to set the parent interface for any class annotated with @EntityController:
@Component
@MongoProfile
@Aspect
public class EntityMongoControllerAspect<T> {
@DeclareParents(value="@EntityController *",defaultImpl=EntityMongoController.class)
private IEntityController<T> iEntityController;
}
but eclipse always throws me the exception:
java.lang.IllegalStateException
at org.aspectj.weaver.ResolvedTypeMunger.<init>(ResolvedTypeMunger.java:69)
at org.aspectj.weaver.MethodDelegateTypeMunger.<init>(MethodDelegateTypeMunger.java:61)
at org.aspectj.weaver.bcel.AtAjAttributes.handleDeclareParentsAnnotation(AtAjAttributes.java:852)
at org.aspectj.weaver.bcel.AtAjAttributes.readAj5ClassAttributes(AtAjAttributes.java:384)
at org.aspectj.weaver.bcel.BcelObjectType.ensureAspectJAttrib ... ob.java:241)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:53)
Compile error: IllegalStateException thrown: Use generic type, not raw type
my entityMongoController code is:
public class EntityMongoController<T1> {
...
}
so how i can achieve this? or there is another alternative? you must take into mind that i'm using spring profiles, so using native aspectj is not an alternative.
Let us for a moment assume that native AspectJ is not a show-stopper for you if you follow Spring's documentation on how to integrate it into your Spring project. In this case you could do something like this (I am using native AspectJ syntax because the annotation-style @AspectJ syntax has many disadvantages from a readability/expressivity point of view):
Interface with embedded aspect providing default implementation:
package de.scrum_master.app;
public interface IEntityController<T> {
public void setEntity(T entity);
public T getEntity();
static aspect EntityControllerAspect {
private T IEntityController.entity;
public void IEntityController.setEntity(T entity) { this.entity = entity; }
public T IEntityController.getEntity() { return entity; }
declare parents : @EntityController * implements IEntityController;
}
}
Annotated class with sample main
method showing the effect:
package de.scrum_master.app;
import java.lang.reflect.Method;
@EntityController
public class MyAnnotatedController<T> {
public void doSomething() {
System.out.println("Doing something");
}
public static void main(String[] args) {
// Use class type directly so as to call its method
MyAnnotatedController<String> annotatedTextController = new MyAnnotatedController<>();
annotatedTextController.doSomething();
// Print all declared methods (should also show interface methods introduced via ITD)
for (Method method : annotatedTextController.getClass().getDeclaredMethods()) {
if (!method.getName().startsWith("ajc$"))
System.out.println(method);
}
// Prove that class type is compatible with interface type
IEntityController<String> entityTextController = annotatedTextController;
entityTextController.setEntity("foo");
// Would not work here because generic interface type is type-safe:
// entityTextController.setEntity(123);
System.out.println("Entity value = " + entityTextController.getEntity());
// Create another object and directly assign it to interface type
IEntityController<Integer> entityNumberController = new MyAnnotatedController<>();
entityNumberController.setEntity(123);
// Would not work here because generic interface type is type-safe:
// entityNumberController.setEntity("foo");
System.out.println("Entity value = " + entityNumberController.getEntity());
}
}
Console output:
Doing something
public static void de.scrum_master.app.MyAnnotatedController.main(java.lang.String[])
public java.lang.Object de.scrum_master.app.MyAnnotatedController.getEntity()
public void de.scrum_master.app.MyAnnotatedController.setEntity(java.lang.Object)
public void de.scrum_master.app.MyAnnotatedController.doSomething()
Entity value = foo
Entity value = 123
Feel free to ask further questions if you do not understand my code snippets.