How to use Spring on a class situated in a library? - spring

Although I'm comfortable with other DI especially MacWire, I need for a project to deal with Spring.
I'm trying to integrate an external library of service that I am developing to a main application that uses Spring to instantiate its services. I'm wondering how can I do such that the code in the Library is treated the same as the code in the source with respect to Spring?
That is instantiating class in my library, from with within the main source of the project using Spring. Do I just give the path of the package to scan the bean from?

Spring configuration file help you to achieve DI. What I understand from question is, you are looking for a way to use Spring capabilities to instantiate a class. The way to instantiate bean remain same for external service or your own library code.
Say if you have classes like:
//External Library class
package com.test;
public class HelloWorld{
...
}
// Your class
package com.abc;
import com.test.HelloWorld;
public class MyClass{
HelloWorld obj;
...
}
Spring XML configuration file will look like,
<beans>
<!-- External library class -->
<bean id="helloWorld" class="com.test.HelloWorld" />
<!-- Your class -->
<bean id="myClass" class="com.abc.MyClass">
<property name="obj" ref="helloWorld"/>
</bean>
</beans>
I recommend you to refer 'Spring Dependency Injection' in Spring documentation..

Related

How to create AOP interceptors for Mule classes?

This is what I've tried so far and my interceptor is not triggered (no "TATATA" in my logs) :
My interceptor AopLoggingInterceptor.java :
package fr.mycompany.bus.flow.reco.ani.custom.interceptor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class AopLoggingInterceptor {
#Around("execution(* org.mule.api.transport.MessageReceiver.routeMessage(org.mule.api.MuleMessage))")
public Object addMonitor(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("TATATA Before");
Object object = pjp.proceed();
System.out.println("TATATA After");
return object;
}
}
META-INF/aop.xml :
<aspectj>
<aspects>
<aspect name="fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor" />
</aspects>
<weaver options="-verbose">
<!-- Weave types that are within the org.mule.* packages. -->
<include within="org.mule.*" />
</weaver>
</aspectj>
My Mule/Spring config file :
<?xml version="1.0" encoding="UTF-8"?>
<mule >
<spring:beans>
<context:component-scan base-package="fr.mycompany.bus" />
<context:annotation-config />
<aop:aspectj-autoproxy />
<!-- Aspect -->
<spring:bean name="aopLoggingInterceptor" class="fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor" />
</spring:beans>
</mule>
My Mule file config consists of one flow with one inbound endpoint, 2 outbound endpoints, loggers and transformers (valid flow widely tested).
VM args :
-XX:PermSize=128M -XX:MaxPermSize=256M -javaagent:D:\path\to\mule\opt\aspectjweaver-1.6.11.jar
Extract from mule file starting in Eclipse which shows weaving is created :
[MuleApplicationClassLoader#2934847] info AspectJ Weaver Version 1.6.11 built on Tuesday Mar 15, 2011 at 15:31:04 GMT
[MuleApplicationClassLoader#2934847] info register classloader org.mule.module.launcher.MuleApplicationClassLoader#2934847
[MuleApplicationClassLoader#2934847] info using configuration /D:/BusToolBox/workspaces/dev/.mule/apps/bus-esb-mrc-reco-ani/classes/META-INF/aop.xml
[MuleApplicationClassLoader#2934847] info register aspect fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor
EDIT
It works nicely with a class included in my project, but not with mule classes :
[MuleApplicationClassLoader#6ad5934d] debug generating class 'fr.mycompany.bus.flow.reco.ani.custom.transformer.CustomerDetailToSiebelRecoAniOutputTransformer$AjcClosure1'
EDIT 2
Here is the best result I can get (by using <context:load-time-weaver />), the loading process tries to look for more classes loaded by difference classloaders is , but it results in :
ERROR 2014-08-08 16:00:46,802 [main] org.mule.module.launcher.application.DefaultMuleApplication: null
java.lang.IllegalStateException: ClassLoader [org.mule.module.launcher.MuleApplicationClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar
If I try to use spring-instrument-3.2.1.RELEASE.jar, I get same result as before (only main classloader is seen). Does it mean there is no hope with Mule ?
Have a look at this example for using Mule and Spring AOP. The example shows how to invoke Around advice for a component, but should be similar for the interceptor.
There is something very important when working with Spring AOP. In spring aop documentation is stated:
Use the simplest thing that can work. Spring AOP is simpler than using
full AspectJ as there is no requirement to introduce the AspectJ
compiler / weaver into your development and build processes. If you
only need to advise the execution of operations on Spring beans, then
Spring AOP is the right choice. If you need to advise objects not
managed by the Spring container (such as domain objects typically),
then you will need to use AspectJ. You will also need to use AspectJ
if you wish to advise join points other than simple method executions
(for example, field get or set join points, and so on).
So if you want that your AopLoggingInterceptor is invoked for MessageReceiver method calls, that is not going to work because the MessageReceiver object is not managed by the Spring container. The Spring container doesn't "see" this objects.
In other words Spring-AOP cannot add an aspect to anything that is not created by the Spring factory. I found that statement here.

Bootstrap a Spring #Configuration class from another Maven module in a multi-module project

Before the spiel, I think the question essentially boils down to this:
How can I instantiate correctly #Configuration beans from an application's XML-based configuration?
In an attempt to modularize my project and follow something of a clean architecture, I have created a Maven project composed of three modules. There is a "web" module an "interface" module and a "core" module and both web and core use Spring's Java-based configuration.
The web module declares in it's POM a runtime dependency on the core module and a compile-time dependency on the interface module. The core module is the implementation of the interface module, the latter being composed of only Java interfaces and DTOs. (This is an attempt to program to interface modules.)
When I start the web module I want all the Spring-managed beans from the core module to become known to the web module's application context. I've had some success doing this the "XML-way" by creating an XML file in the core module that looks like this:
// This xml snippet is part of the "core" module
<beans>
<context:annotation-config />
<context:component-scan base-package="com.acme.core"/>
</beans>
... and referencing this in the web module configuration like so:
// The configuration of the "web" module
#Configuration
#ImportResource("classpath*:come/acme/configuration/spring/*.xml")
public class RootConfig {}
It works but I'm not happy with the solution because I want all the configuration for the core module to be done the Java way.
So to that end, I note that Spring says one can do the following:
...#Configuration classes may be declared as normal definitions within Spring XML files:
<beans>
<context:annotation-config/>
<bean class="com.acme.configuration.spring.CoreConfig"/>
</beans>
That would be (almost) ideal if it worked because the XML file in the core module would be very lean and essentially just bootstrapping the meaty configuration in CoreConfig. However it doesn't work for me and the web module cannot find any of the beans that are defined in the core module. I think this might be because if the beans are instantiated then they are done so in a different application context or maybe because CoreConfig, being marked with #Configuration, is special and instantiating it this way from the XML file doesn't trigger the creation of the other beans it defines.
Incidentally, I'd rather have a way to do this without any XML configuration but referencing com.acme.configuration.spring.AppConfig directly from the web module is not possible since there is no compile time dependency on the code. (Sigh) Modularizing is so far proving to be more trouble than it's worth...
The following works when specified in the config class of the "Web" module in my example:
#Configuration
#ComponentScan(basePackages={"com.acme.configuration"})
public class RootConfig {}
In fact, it is what #M. Deinum said to do in a comment on the question. In this example, all com.acme.configuration packages, regardless of whether they might be in another Maven module, will be picked up and processed correctly. It is necessary then, by convention, that all configuration classes of other modules be placed in com.acme.configuration. With this approach there is no need for any XML configuration file to "bootstrap" the configuration as I was trying to do.

Registering Spring beans without Component Scanning

I have MySimpleController and I need to extract this controller to a common library.
package xxx.mypackage;
#Controller
class MySimpleController{}
This library has a different package name, yyy.newpackage which is different than previous xxx.mypackage. Because of this, It is not suitable for component scanning.
Here is the question: Is there a way to register this controller without component scanning? I just want to include my jar and expecting my controller properly. I have seen some definitions in META-INF folder but could not be sure that this is the correct way.
Create configuration for whole 3rd party library
#Configuration
public class CustomConfig {
#Bean
public MySimpleController mySimpleController(){
return new MySimpleController();
}
}
and import this configuration without scanning
#Import(CustomConfig.class)
My sample is in JavaConfig, but this apply to xml configuration too.
add this controller as a bean with the new package in your applicationCOntext. By doing so, it would be the only bean loaded through the xml config whereas everything else is through your component scan.
<beans>
<bean name="myBean" class="yy.MySimpleController"/>
</beans>

How to import Java-config class into XML-config so that both contexts have beans?

I have a project where I need to bootstrap #Configuration java-config classes into the XML configuration.
To do that, I'm reading that I also need to include the following bean definition (along with the bean definitions of the classes annotated with #Configuration).
<bean class="org.springframework.config.java.process.ConfigurationPostProcessor" />
But, I end up receiving the following error:
Caused by: java.lang.ClassNotFoundException: org.springframework.config.java.process.ConfigurationPostProcessor
I have to assume I'm missing a jar somewhere, but my various web searches hasn't resulted in an answer yet. Any help would be greatly appreciated. Thanks.
EDIT: Evidently, I was reading old documentation, which is no longer current. Let me back up. My project contains older XML-based configuration. The newer code is all using 'Java-config'. With that said, the contexts are apparently completely separate. I'd like to 'import' a java-config class into the XML configuration, so that both contexts have those particular beans. Does anyone know how I can do that?
This actually ended up being fairly simple. To get a Java-config bean definition into the xml-config, simply define the Java-config class as a bean within the XML-config. There are no extra jars necessary.
#Configuration
public class SomeJavaConfig {
#bean
... [bean definition]
}
inside the XML-config, you define this class as a bean.
<!-- needed to pick up the annotated java-config -->
<context:annotation-config />
<!-- Importing java-config class, which are annotated with #Configuration -->
<bean name="SomeJavaConfig" class="[fully qualified path].SomeJavaConfig" />
The XML-config, which may be part of a different context, now has all the bean definitions defined within the JavaConfig class.
UPDATED - to included Alan Franzoni's comment below in the answer.
Alternatively to annotation-config you can use component-scan. Then you do not have to include the Configuration Bean in XML:
<context:component-scan base-package="[fully qualified package path]" />
See Difference between <context:annotation-config> vs <context:component-scan> for more details.
Should be in:
spring-javaconfig-<version>.jar

Automatic mock instantiation in a Spring JUnit test

I have a Spring XML bean definition that I want to write integration tests for. The XML bean definition is part of a larger application context where several such files are included using <import>. Inside the definition, I reference several beans that are coming from other files.
For my integration test I would like to instantiate the definition standalone and use Mockito mocks for all other beans. Until now, I am using something like this:
FooIntegrationTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class FooIntegrationTest {
#Autowired private ClassUnderTest underTest;
#Autowired private MockedClass mock;
#Test
public void testFoo() {
}
}
FooIntegrationTest-context.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="part-to-test.xml" />
<bean id="mockedClassReferencedByName" class="org.mockito.Mockito" factory-method="mock" c:classToMock="SomeMockedClass" />
<bean class="org.mockito.Mockito" factory-method="mock" c:classToMock="OtherMockedClassReferencedByType" />
<bean class="org.mockito.Mockito" factory-method="mock" c:classToMock="MockedClass" />
...
</beans>
I would like to automate the rather tedious mocking section: Ideally, I would like to have all beans that are not found in the application context to be mocked automatically. The part-to-test.xml uses #Autowired as well as beans that are set by using name references. I only use XML bean definition files, and neither use #Configuration classes nor #Component annotations.
I have looked into how to use a custom context loader in #ContextConfiguration(loader=...), but I have not yet found an appropriate extension point for doing so. Sprinockito does not seem to adress this problem.
Is there some other project out there that already solves this problem? If not, where would I extend Spring to create the mocks automatically?
Here is a short article with a code example. A BeanDefinitionRegistryPostProcessor implementation generates a mock object for each lacking bean definition. The generation part is done with a MocksFactory, here is an example for such a factory.
Just in case anyone is still interested in this question, I have extended the code in the article mentioned by Yves Martin with inheritance, support for #Inject, etc... and created a Github project here: https://github.com/rinoto/spring-auto-mock

Resources