geogeek
geogeek

Reputation: 1302

Get Spring Bean from AspectJ ProceedingJoinPoint

I'm looking to get the Spring Data Repository interface or the bean calling void delete(id) using AspectJ, the problem with that function is there is no argument or return type to guess the bean, is there any idea how to get the calling bean or the interface name from AspectJ ProceedingJoinPoint.

this is my actual code:

@Pointcut("execution(public * org.springframework.data.repository.Repository+.save(..)) || execution(public * org.springframework.data.repository.Repository+.delete(..)) && target(repository)") 
public void publicNonVoidRepositoryMethod(CrudRepository repository) {
}

@Around("publicNonVoidRepositoryMethod(CrudRepository repository)")
public Object publicNonVoidRepositoryMethod(ProceedingJoinPoint pjp , CrudRepository repository) throws Throwable {

.......
}

Upvotes: 0

Views: 1253

Answers (2)

Michal
Michal

Reputation: 2273

This is an old question but someone might find this helpful.

  • Declare pointcut for all delete methods on CrudRepository, PagingAndSortingRepository etc..:
  • When called from your code, you may pass on the entity itself
  • On the other hand, when invoked via Spring Data REST, the delete method is invoked with ID (Long in this example)

I'm using reflection to get to the bottom of the entity type in the latter scenario. Note: all my entities are implementing Identifiable interface to allow easy access to getId():

@Pointcut("execution(* org.springframework.data.repository.*.delete(..)) && args(entity)")
    public void repoDelete(Object entity) {}

@Around(value="repoDelete(entity)",argNames="entity")
public void onDelete(ProceedingJoinPoint pjp, Object entity) throws Throwable{
    String invoker = null; //this will become the type name
    Long entityId = 0L;
    if (entity.getClass().getName().equals("java.lang.Long")){
        entityId = (Long)entity;
        REFLECT: {
            // this returns a list of JPA repository-related interfaces
            Class[] interfaces = jp.getTarget().getClass().getInterfaces();
            for (Class iface: interfaces) {
               // one of them is your JPA repository
               if (iface.getName().startsWith("YOUR REPO PACKAGE")){
                    // the entity type can be accessed via generics
                    ParameterizedType pType = (ParameterizedType) iface.getGenericInterfaces()[0];
                    // this list contains two values - the entity type and the identifier type
                    Type[] typeArgs = pType.getActualTypeArguments();
                    for (Type t: typeArgs) {
                        if (t.getTypeName().startsWith("YOUR ENTITY PACKAGE")) {
                            invoker = t.getTypeName();
                            break REFLECT; 
                        }
                    }
                }
            }
        }
    } else {
        invoker = entity.getClass().getName();
        if (entity instanceof Identifiable) entityId = (Long) ((Identifiable) entity).getId();
    }

    // do whatever you need ... 
    pjp.proceed();
}

Upvotes: 1

Viktor Chvátal
Viktor Chvátal

Reputation: 463

You can add target parameter to get your repository that has been called:

@Aspect
@Component
public class SampleAspect {
    // Apply to all repositories in package repositories
    @After("execution(* repositories.*.delete(*)) && target(repository) && args(id)")
    public void afterEntityDelete(CrudRepository repository, Object id) {
    ...
    }
}

Upvotes: 1

Related Questions