I have some methods advised by two aspects, one is using the spring AOP support and the other is a BeanPostProcessor (MethodValidationPostProcessor specifically) which advises all method with #Validation annotation. With my unit tests I am trying to force throwing an error by breaking the method contract, but sometimes the validation is in place (the advise imposed by the above mentioned post processor) and sometimes does not work. Does anybody have experienced something similar.
Here is a small snippet of what I am trying to do:
Aspect code:
#Aspect
#Component
public final class LoggingAspect {
#Before(value = "execution(public * * (..)) && #annotation(loggable)",
argNames = "joinPoint, loggable")
public void before(JoinPoint joinPoint, Loggable loggable) {
//logging here...
}
}
Annotation (Loggable Code)
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Loggable {...}
Interface being annotated with #Validated annotation (Here's a link with related info).
#Validated
public interface Dao<T, K> {
T findById(#NotNull K id);
T persist(#NotNull T object);
}
A base class implementing this interface:
public abstract class BaseDao implements DAO {
#Loggable
public T persist(T object){...}
}
And a subclass with a particular behavior:
public final class UserDao extends BaseDao {
#Loggable
public T findById(User object){...}
}
And the spring context at last something like this
<aop:aspectj-autoproxy/>
<context:annotation-config/>
<context:component-scan base-package="com.my.package"/>
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
I am testing by calling both methods with null as the argument, but in some occasions I received an IllegalArgumentException: attempt to create saveOrUpdate event with null entity instead of the MethodConstraintViolationException supposedly raised by the
instead MethodValidationInterceptor which advises/intercepts all public method for #Validated annotated interfaces.
EDIT: I am using spring 3.1, Hibernate Validator 4.2 (as required by spring) and aspectj 1.7.
EDIT 2: I did some more digging around the test code, and I found out there is something strange related to the MethodValidationPostProcessor or the MethodValidationInterceptor. I disabled the aop-autoproxy and remove the LoggerAspect during testing, and still there is some problem that in some occasion the Validation resulted in what I expected and in some other situations where even though it is supposed to fails the MethodValidationInterceptor or the MethodValidator fails to catch the errors in the calls.
Digging around I found out the problem was related to where I put the annotations. Sorry for the inconvenience.
Related
I have a created an annotation that verifies whether certain security aspects are correct.
For example, #RequireClientCertificate, with an Aspect implementation RequireClientCertificateAspect that verifies whether the correct HTTP header is indeed passed in to the Spring REST controller.
This works totally fine, IF the RequireClientCertificateAspect is actually loaded, i.e. if its package is mentioned somewhere in #ComponentScan().
However, if someone forgets to add this package to #ComponentScan, or the aspect is moved to another package, or someone (accidentally) removes the package from #ComponentScan, the aspect bean isn't loaded, and the aspect is completely not applied.
I have this annotation in a common library, shared by several microservices, so it's easy for one of the microservices to accidentally get it wrong. In that case, no checking of the client certificate would be performed.
Question: How can I enforce that, if the #RequireClientCertificate annotation is used, its corresponding Aspect implementation is also loaded?
Simplified usage example:
#Controller
#RequestMapping(value = "/v1.0", produces = MediaType.APPLICATION_JSON_VALUE)
#RequireClientCertificate
public class SomeApiController {
#ResponseBody
#PostMapping("/get-token/")
public ResponseEntity<Token> getToken() {
return ResponseEntity.ok(...get token...);
}
}
Simplified version of the aspect:
#Aspect
#Component
public class RequireClientCertificateAspect {
#Around("execution(* (#RequireClientCertificate *).*(..))")
public Object requireClientCertificateAspectImplementation(ProceedingJoinPoint joinPoint) throws Throwable {
... verify request header ...
try {
return joinPoint.proceed();
finally {
... some other things I need to check ...
}
}
}
Things I've tried/considered:
I can detect 'usage' of the annotation by adding a static field with an initializer to the interface. For example:
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface RestFactoryGatewaySecurityContext {
static public final boolean dummy = SomeClass.checkAspectIsLoaded();
}
However, such initializers are called very early, and I don't think Spring DI is 'up and running' far enough at that stage that I could even reliably determine whether the aspect bean is loaded.
Another option is to use #Autowired to inject the RequireClientCertificateAspect bean on the main app class explicitly. If somehow the bean isn't on the component scan, this will prevent Spring from instantiating the app.
So that does work, but requires someone to explicitly add this 'dummy' autowire, which in itself is easy to forget, in addition to being a bit 'ugly'.
If you use spring boot you can create your own starter.
Create file META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.MyCustomConfiguration
Then just add any validation you want to your configuration
#Configuration
public class MyCustomConfiguration{
}
You can #Autowired your RequireClientCertificateAspect into it, which will cause error if it isn't defined.
You can create method with #PostConstruct and do any validation you want.
If you went so far as creating custom starter, you can just initialize your bewns there.
More about it you can read here
I am working on a Java EE 7 (on wildfly 9.0.2) application and I stumbled on an article http://www.oracle.com/technetwork/articles/java/intondemand-1444614.html. Mainly about:
Premature Extensibility Is the Root of Some Evil
This makes sense in certain cases I have encountered. I have changed some classes to a no interface view. The implementation itself is not a problem, testing however is.
For example I have these 2 classes.
#Stateless
public class SomeBean {
public String getText()
{
return "Test text";
}
}
And
#Stateless
public class SomeOtherBean {
#Inject
private SomeBean someBean;
public String getText()
{
return someBean.getText();
}
}
I want somehow that the someBean property is overwritten with preferably a mocked object. Without altering the SomeBean and SomeOtherBean class. I have tried some examples, but they didn't work for example:
https://github.com/arquillian/arquillian-showcase/tree/master/extensions/autodiscover/src/test/java/org/jboss/arquillian/showcase/extension/autodiscover
Has anyone encountered this before and have a solution?
I ended up using 2 solutions.
Solution 1: Use mockito for internal or smaller tests
For testing a particular class Mockito is really useful, as it supports dependency injection.
#RunWith(MockitoJUnitRunner.class)
public class SomeOtherBeanTest {
#Mock
private SomeBean someBean;
#InjectMocks
private SomeOtherBean someOhterBean;
#Before
public void setUp() {
Mockito.when(someBean.getText()).thenReturn("Overwritten!");
}
#Test
public void testGetText() throws Exception {
assertEquals("Overwritten!", someOhterBean.getText());
}
}
Solution 2: Use #Produces and #Alternatives for mocking external services (e.g. mocking OAuth2 server) or larger test (e.g. integration testing)
First I create a new #Alternative annotation:
#Alternative
#Stereotype
#Retention(RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public #interface CDIMock {}
Then add this as stereotype to the arquillian beans.xml deployment:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
<alternatives>
<stereotype>com.project.CDIMock</stereotype>
</alternatives>
</beans>
After that create a new #Producer method in a seperate class:
public class SomeBeanMockProducer {
#Produces #CDIMock
public static SomeBean produce() {
SomeBean someBean = Mockito.mock(SomeBean.class);
Mockito.when(someBean.getText()).thenReturn("mocked");
return someBean;
}
}
Add the SomeBeanMockProducer class to the arquillian deployment and you should have it working.
An alternative to this solution is using #Specializes and extending the SomeBean implementation. In my opinion this doesn't give me enough control like the #Alternative + Mocking solution (#CDIMock in my example).
For example, lets say I SomeBean has methods that calls remote servers. If I add a method to this and forget to #override this in the #Specializes class it will make a real remote call, this won't be the case with Mocking.
It is kind of obvious that substituting a Mock or other specialized object for an injected no-interface class is more difficult, since that is exactly what you wanted by not declaring an interface for the bean.
Having said that, if you are not running a CDI container (e.g. doing POJO unit tests) I think using Mockito is the easiest way.
If you want to do it the "pure CDI" way within a container, you can use the Alternative and Specialization mechanisms of CDI, as described in the Java EE 6 tutorial.
#Specializes
public class SomeBeanMock extends SomeBean {
#Overrides
public String getText()
{
return "mock";
}
}
Of course you can only use mocks that subclass the original bean (since you have no interface) and you are limited to the usual visibility rules. Changing/mocking private field or methods would require reflection or bytecode manipulation (which is what Mockito does behind the scenes).
I've created a simple annotation (#ProfilePerformace) which combined with the magic of AspectJ should measure the performance of any method or class I annotate and print the results to Slf4j. It seams to work for all un-annotated methods but doesn't seam to work for methods which have another annotation present for example #Transaction or #PostContruct. Any ideas of why this is happening would be great.
I'm using Spring 4.2.2 and AsjectJWeaver:1.8.7 which is pulled in by Spring-Aspects.
Annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#Inherited
#Documented
public #interface ProfilePerformance {
}
Aspect
#Aspect
#Component
public class ProfilePerformanceAspect {
private static final Logger log = LoggerFactory.getLogger(ProfilePerformanceAspect.class);
#Around(value = "#within(ProfilePerformance) || #annotation(ProfilePerformance)")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
String methodName = signature.getMethod().getName();
StopWatch stopWatch = new StopWatch(methodName);
stopWatch.start(methodName);
Object output = pjp.proceed();
stopWatch.stop();
log.info("Class [{}] Method [{}] Execution Time [{}ms]", pjp.getTarget().getClass().getSimpleName(), methodName,
stopWatch.getTotalTimeMillis());
return output;
}
Example of code which works:
#ProfilePerformance
public void delete(Item item) {...}
Example of a method which doesn't work:
#Transactional
#ProfilePerformance
public void update() {...}
Edit:
After doing some more digging I found these two posts on the Spring forum which seam to point to the same problem.
Using-multiple-aspects-annotations-at-the-same-time-requires-annotating-interfaces
Spring Jira SPR-6083
It looks like it's possible there is an issue applying both annotations due to the fact my annotation (#ProfilePerformance) is applied using aop:aspectj-autoproxy/ and #Transactional is applied using tx:annotation-driven. In essence by the time my annotation comes to be applied the method has already been proxied to in order to apply #Transactional so my Aspect doesn't match.
I've applied the work around which is posted in the link above but I'd really like to understand if I'm doing this properly as this approach smells a bit funny.
Workaround
<!-- Use this instead of "tx:annotation-driven" so that we can register other Aspects on #Transactional methods. -->
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor">
<bean class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
</property>
</bean>
</property>
I am having trouble getting multiple aspects to fire in a specific order. I am using the RequestProcessor to do certain things on every incoming request on my controllers, which have a certain parameter
Then I have some specific annotations that I will be adding to only certain methods within my controllers.
FYI I am using Eclipse, Tomcat, Maven and spring with java/annotation based configs. I use Tomcat and the WebApplicationInitializer to load my context, dispatcher, listeners etc. I have no web.xml. I can post that or the pom.xml if needed too.
The problem I am getting is that a method that satisfies both the ProcessRequest pointcut and the someAnnotation pointcut is firing the someAnnotation method first even though the order is specified to fire ProcessRequest first. There is some properties set in the ProcessRequest that is needed in some other annotations.
Here is a simplified version of my code.
Spring Config Class
#Configuration // Enable Spring Annotation Configuration. Equivalent to <context:annotation-config/>
#EnableAspectJAutoProxy
#EnableCaching // Enable Spring caching
#EnableWebMvc // Enable Spring MVC Annotation. Equivalent to <mvc:annotation-driven />.
#ComponentScan(basePackages = {"xxx.yyy.zzz"}) // Scan for Spring Components. Equivalent to <context:component-scan>
public class WebAppConfig extends WebMvcConfigurerAdapter {
// Other Bean logic here
#Bean
public RequestProcessor requestProcessor() {
return new RequestProcessor();
}
#Bean
public AnnotationAspect annotationAspect() {
return new AnnotationAspect();
}
}
Aspect #1
#Aspect
#Order(0)
public class RequestProcessor {
#Pointcut("execution(* xxx.yyy.zzz.api..*.*(xxx.yyy.zzz.objects.api.Request,..)) && args(request)")
public void pointcut(Request<?> request) {}
#Before("pointcut(request)")
public void processRequest(Request<?> request) throws IOException, BadSignatureException {
// Some logic here that is independent of other and needs to run before other aspect which references annotation
}
}
Aspect #2
#Aspect
#Order(1)
public class AnnotationAspect {
#Before("#annotation(xxx.yyy.zzz.annotation.SomeAnnotation)")
public void someAnnotation() {
// Log for this annotation
}
// Some other annotation methods here
}
Also tried this format implements Ordered
#Aspect
public class RequestProcessor implements Ordered {
#Override
public int getOrder() {
return 0;
}
#Pointcut("execution(* xxx.yyy.zzz.api..*.*(xxx.yyy.zzz.objects.api.Request,..)) && args(request)")
public void pointcut(Request<?> request) {}
#Before("pointcut(request)")
public void processRequest(Request<?> request) throws IOException, BadSignatureException {
// Some logic here that is independent of other and needs to run before other aspect which references annotation
}
}
I read over this post and some others but couldn't find anything relevant that worked.
Ordering aspects with Spring AOP && MVC
****UPDATE****
So I have been reading through the AspectJ docs on declaring precedence so I thought I would give it a whirl. I created a simple aspect that only declares precedence and it works just fine.
Here is my Precedence Aspect:
public aspect AspectPrecedence {
declare precedence : RequestProcessor, SomeAspect;
}
I am not going to submit this as answer just yet because I would like to understand why the annotation or "implements Ordered" are not functioning properly in my project.
Any insight would be greatly appreciated. Thanks!
****UPDATE 2****
For reference this works locally in my eclipse environment and seemed to work when deployed to AWS via WAR file.
#Aspect
#DeclarePrecedence("RequestProcessor, SomeAspect")
public class RequestProcessor {
#Pointcut("execution(* xxx.yyy.zzz.api..*.*(xxx.yyy.zzz.objects.api.Request,..)) && args(request)")
public void pointcut(Request<?> request) {}
#Before("pointcut(request)")
public void processRequest(Request<?> request) throws IOException, BadSignatureException {
// Some logic here that is independent of other and needs to run before other aspect which references annotation
}
}
When using Eclipse with AspectJ support that automatically enables compile time weaving in your IDE. Which means the aspects get woven into your byte code, opposed to Spring which uses proxies to apply aspects.
Using an aspect to declare precedence or using #DeclarePrecedence will only work when using either compile or load time weaving (the latter can be enabled by specifying <context:load-time-weaver/> depending on your container might require some additional configuration). However both should work (you might need to specify the AspectJ compiler as a compiler for the #Aspect classes instead of the default java compiler).
#Order and Ordered only work for the proxy based solution and are ignored by AspectJ.
I think the problem could be that you're using LTW with AspectJ instead AOP with Spring, as #Order is defined for Spring, the container(AspectJ) is not able to determine the ordering of both the advices, so try one of these:
Try flipping the order of #Aspect and #Order annotations
You can try the annotation #DeclarePrecedence from AspectJ and then configuring your aspects into the aop.xml
<aspects>
<aspect name="your.package.RequestProcessor"/>
<aspect name="your.package.AnnotationAspect"/>
<concrete-aspect name="my_aspect_configuration_precedence"
precedence="*..*RequestProcessor, *"/>
</aspects>
I don't know if it's going to work but expect to give you a pointer on that
I am using Spring AOP (with AspectJ annotation style support) and want to execute code if a method is annotated with a specific annotation (WsTransaction).
Here is my aspect:
#Aspect
#Component
public class ExampleAspect {
#Pointcut("execution(* example.*.ws.*.*(..))")
public void isWebService() {}
#Pointcut("#annotation(example.common.ws.WsTransaction)")
public void isAnnotated() {}
#Before("isWebService() && isAnnotated()")
public void before() {
System.out.println("before called");
}
}
This is an example class where I expect it to run:
package example.common.ws;
#Endpoint
public class SomeEndpoint {
#WsTransaction() // I want advice to execute if this annotation present
#PayloadRoot(localPart = "SomeRequest", namespace = "http://example/common/ws/")
public SomeResponse methodToBeCalled(SomeRequest request) {
// Do stuff
return someResponse;
}
}
When I change #Before to only use isWebService() it is called but when I try it with isWebService() && isAnnotated() or just isAnnotated() nothing seems to happen.
I have <aop:aspectj-autoproxy/> in my Spring config.
The endpoint is created by Spring (using component-scan).
The annotation's retention policy is runtime.
Spring version is 3.0.3.RELEASE
I am not sure what is wrong or what I can try to debug.
Update: It seems Spring AOP doesn't pickup #Endpoint annotated classes
Update 2: AopUtils.isAopProxy(this) and AopUtils.isCglibProxy(this) are both false (Even when using <aop:aspectj-autoproxy proxy-target-class="true"/>)
Firstly I had to use <aop:aspectj-autoproxy proxy-target-class="true"/> to use class-based (CGLIB) proxies (instead of Java interface-based proxies).
Secondly (and this is where I got stuck) I had to specify the above in the contextConfigLocation of the servlet handling the SOAP requests (MessageDispatcherServlet) instead of the root application context.
I guess there may be some issue with the pointcut declaration.
#Pointcut("#annotation(example.common.ws.WsTransaction)")
See this link for possible solution