Skip to content

Instantly share code, notes, and snippets.

@roberthunt
Created December 16, 2016 10:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roberthunt/78392cbca46eeb33c803ce0294f1e847 to your computer and use it in GitHub Desktop.
Save roberthunt/78392cbca46eeb33c803ce0294f1e847 to your computer and use it in GitHub Desktop.
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/**
* An Aspect which removes a specific annotation from a Spring Data JPA repository method. This was designed to remove
* the org.springframework.data.jpa.repository.QueryHints annotation when running tests with database drivers which
* don't support specific query hints (and throw exceptions causing the tests to fail).
*
* Note: make sure that AspectJ auto-proxy is enabled either via the @EnableAspectJAutoProxy annotation in the Java
* configuration or <aop:aspectj-autoproxy /> in the XML configuration.
*
* @author Robert Hunt
*/
@Aspect
public class JpaRepositoryAnnotationRemovingAspect
{
private static final Logger LOG = LoggerFactory.getLogger(JpaRepositoryAnnotationRemovingAspect.class);
private final Class<? extends Annotation> targetAnnotation;
public JpaRepositoryAnnotationRemovingAspect(Class<? extends Annotation> targetAnnotation)
{
this.targetAnnotation = targetAnnotation;
}
@Before("execution(public * org.springframework.data.jpa.repository.JpaRepository+.*(..))")
public void interceptRepositoryMethod(JoinPoint joinPoint)
{
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
try
{
// the "declaredAnnotations" field is lazily initialised so we need to call the method first which will initialise it
Method declaredAnnotationsMethod = Executable.class.getDeclaredMethod("declaredAnnotations");
declaredAnnotationsMethod.setAccessible(true);
declaredAnnotationsMethod.invoke(method);
// the "declaredAnnotations" field contains all of the method annotations
Field declaredAnnotationsField = Executable.class.getDeclaredField("declaredAnnotations");
declaredAnnotationsField.setAccessible(true);
Map<Class<? extends Annotation>, Annotation> declaredAnnotations = (Map<Class<? extends Annotation>, Annotation>) declaredAnnotationsField.get(method);
if (declaredAnnotations != null && declaredAnnotations.containsKey(targetAnnotation))
{
LOG.info("[{}] annotation was found on method [{}] and will be removed", targetAnnotation, method);
declaredAnnotations.remove(targetAnnotation);
}
}
catch (NoSuchMethodException | InvocationTargetException | NoSuchFieldException | IllegalAccessException e)
{
LOG.error("unable to access declaredAnnotations method and/or field on method [{}]", method);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment