There are 3 projects that use CDI. Project A has an Interceptor for transaction control.
Project B uses Project A to save data in a database. When I run these unit tests, everything passes.
Project C uses Project B for integration tests. These tests fails when it finds the #AroundInvoke annotation from Interceptor.
What is going wrong? The interceptor is only in Project B beans.xml.
The exception stacktrace doesn't clear up my mind. It only show a jassist error. Debugging, I found that the problem comes from boostrap.deploybeans() inside Weld. So, I commented the #AroundInvoke in the interceptor class and everything goes fine with tests, but the insert on database. I think that happens because I removed the interceptor that creates transaction for inserts.
The code:
1) There is a project A which defines an annotation and an interceptor for this annotation. Example:
/Annotation/
#InterceptorBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface Transactional {
}
/Interceptor/
#Interceptor
#Transactional
public class TransactionalInterceptor implements Serializable {
…
#AroundInvoke
public Object intercept(InvocationContext context) throws Exception {
…
}
…
}
I think this project must have an empty /META-INF/beans.xml.
2) There is another project B that uses the interceptor from project A. Example:
public class ProjectBClass {
…
#Transactional
public void interceptorMethod() {
…
}
…
}
So I think this project must have a /META-INF/beans.xml that enables the interceptor. Example:
<beans>
<interceptors>
<class>br.com.company.projecta.TransactionalInterceptor</class>
</interceptors>
</beans>
3) Finally, there's a project C that uses the method from project B. Example:
public class ProjectCClass {
…
private ProjectBClass projectBClass;
…
public void testerMethod() {
…
this.projectBClass.interceptorMethod();
…
}
…
}
I am not sure if it must have a /META-INF/beans.xml.
4) In this same project, there is an integration test which tests the method. Example:
public class ProjectCClassTest {
…
#Test
public void test() {
ProjectCClass projectCClass = new ProjectCClass();
projectCClass.testerMethod();
…
Assert.assertEquals(…);
}
…
}
You need META-INF/beans.xml in all projects (packaged as .jar)
You should not instantiate the classes yourself. If you do, they are not CDI managed. Let CDI instantiated them. For example look here.
Related
So the package I'm trying to use is here:
https://github.com/spring-projects/spring-batch-extensions/tree/master/spring-batch-excel
and on that page is the spring bean configuration for that package. I'm new to spring, and I don't understand how to actually write code that uses the bean.
The config looks like this:
#Bean
public PoiItemReader excelReader() {
PoiItemReader reader = new PoiItemReader();
reader.setResource(new ClassPathResource("/path/to/your/excel/file"));
reader.setRowMapper(rowMapper());
return reader;
}
#Bean
public RowMapper rowMapper() {
return new PassThroughRowMapper();
}
So if I have another class called reader somewhere, how do I use this bean configuration to get the lines from the excel file that PoiItemReader gets from .setRowMapper()?
The row mapper has a list of arrays that split the values in the excel rows, but I don't know how to get that list.
Do I call the excelReader() method?
PoiItemReader doesn't have any useful methods associated with it, so I don't think I'm supposed to do that.
From your code snippet, it looks like you're using #Configuration on the class that declares your beans.
Using Java Configuration is one of the ways to define your beans so that spring will understand them and inject property at runtime.
An alternative way is using annotations like #Service, #Component, #Controller and so forth (an answer provided by maneesh)
So the first thing to understand in Spring is that there are many ways of configuration (there is also an old-way, using XML and Groovy based configuration).
Now when you write a spring application, usually you use Spring Beans from other Spring Beans.
So, if you configure bean A to have a reference on Bean B, Spring will inject it for you. Example:
public class A {
private B b;
public A(B b) {
this.b = b;
}
public void doSomething() {
b.foo();
}
}
public class B {
public void foo() {...}
}
The "java config" way for defining these beans can look like this:
#Configuration
public class MyConfiguration {
#Bean
public A a(B b) {
return new A(b);
}
#Bean
public B b() {
return new B();
}
}
In your example, you've used an alternative syntax for Configurations (line reader.setRowMapper(rowMapper());:
#Configuration
public class MyConfiguration {
#Bean
public A a() {
return new A(b());
}
#Bean
public B B() {
return new B();
}
}
It looks like from A you just call a method that creates B. But it is not quite like that, in fact, spring is supposed to wrap your configuration in some kind of runtime proxy so that, for example, if you call b() many times (for many beans), it will always return the same instance, because B has a singleton scope. All-in-all Configuration classes should be considered like a Java DSL to create beans and not a regular code.
Now the last question to consider is where all this configuration gets started. The answer to this really depends on the environment you're running it. Usually, spring is already integrated into existing projects that run on-top of tomcat or other servers, or if it's a Spring Boot application it already provides "well known" integration ways. So you might just ask someone from your project (I assume it's not a homework or something) how does your application is integrated with spring, it's beyond the scope of this question.
you should declare #Service or #Component over the class where you want to read file, and use #Autowired annotation to use PoiItemReader
#Service
public class SomeclassName {
#Autowired
private PoiItemReader excelReader;
public void somemethod() {
//do some reading stuff here using excelReader
}
}
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'm having problems trying to unit test a maven multi-module project with Spring.
I've 4 modules:
application-core
application-data
application-service
application-web
This is my test, its in the application-core module:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:/config/application-context.xml")
public class TicketTest {
#Mock
ITicketDAO ticketDAO;
#Autowired
#InjectMocks
ITicketCore ticketCore;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testRegisterTicket_Ticket_NotUsed_isValid() {
Long ticketNumber = 0L;
when(ticketDAO.getTicket(anyLong())).thenReturn(null);
final boolean isValidTicket = ticketCore.validateTicket(ticketNumber);
assertTrue(isValidTicket);
}
}
And here is the implementation:
#Component
#Scope("prototype")
public class TicketCore implements ITicketCore{
private ITicketDAO ticketDao;
#Autowired
public TicketCore(ITicketDAO ticketDao) {
this.ticketDao = ticketDao;
}
#Override
public boolean validateTicket(Long ticketNumber) {
ITicket ticket = ticketDao.getTicket(ticketNumber);
return ticket != null;
}
}
Interface:
public interface ITicketDAO {
ITicket getTicket(Long ticketNumber);
}
Implementation of ITicketDAO its on the application-data module:
#Service
public class TicketDAO implements ITicketDAO {
#Override
public ITicket getTicket(Long ticketNumber) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
}
I'm having problems testing this code because the context doesn't find the implementation of ITicketDAO. It's seems obvious, because when the test are running, JUnit doesn't care about putting in the classpath the "others modules".
Spring throws BeanCreationException for obvious reasons.
Am I right?
So I would like to test my project without Spring getting in the tests' way.
What could I do to get my tests run w/o any problem???
I've created dummy classes in the test folder/packages, and it works, but...
I would eventually have ALL the external implementations in my application-core module's test folder.
There is a better way?
Thanks in advance.
UPDATE:
application-data
application-service
application-web
all of them depends on application-core. Spring successfully inject TicketCore(application-core). What I want is to give Spring "something" (a dummy class) to inject in ITicketDAO just to run the test.
<beans>
<context:component-scan base-package="ve.gov.imat.transimat" />
<context:annotation-config />
<aop:config proxy-target-class="true" />
</beans>
Pretend that each Maven module is a completely separate project. Put tests specifically of each module's code inside it, and add integration tests in the module where all of the dependencies necessary to run them have been included.
You haven't provided any information on the dependencies between your modules, but it appears that the problem you're running into is that you need some implementation of an interface for testing purposes, but your production bean is defined in another module. This is what mocking frameworks like EasyMock and Mockito are for; they allow you to write simple placeholder implementations so that you can test TicketCore specifically, and it's a good idea to use them even when the real implementation is available so that you can be sure you're just testing one component at a time.
In TicketTest, you're correctly defining your Mockito mock for ITicketDAO, but your TicketCore is still trying to autoacquire the bean from Spring, even though you haven't registered it. Either manually register your bean into the test context, or place the definition for the mock in an #Configuration in src/test.
If I've understood you well your problem is your context file references a class you don't have available in your test classpath.
In principle tests shouldn't need the implementation of any collaborator to work, only the one of the sut.
One solution is to create an application-test-context.xml file under your test/resources folder to be used in your test instead of the production one. Within this file you can create the mocks of your collaborators
<!-- Mock service for splitting jobs -->
<bean factory-bean="mockControl" factory-method="createMock"
primary="true">
<constructor-arg value="net.compart.docpilot.model.service.JobSplitService" />
</bean>
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.
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