Spring ConflictingBeanDefinitionException - spring

I have ProjectA defining a MyService class.
ProjectA contains multiple concrete services, for example: SomeService.
Now I have ProjectB, which is a spring boot project, having ProjectA as dependency.
ProjectB may add some functions to SomeService by defining its own public class SomeService extends project.a.SomeService {...}. The beans are scanned via #ImportResource("applicationContext.xml").
applicationContext.xml:
<beans ...>
<context:component-scan base-package="project">
<context:include-filter type="assignable"
expression="project.a.MyService" />
</context:component-scan>
</beans>
Main problem is: This leads to ConflictingBeanDefinitionException:
Annotation-specified bean name 'someService' for bean class
[project.a.SomeService] conflicts with existing,
non-compatible bean definition of same name and class [project.b.SomeService]
Although the exception is really clear, I have no idea how to solve it. After my research I'm relativley sure setAllowBeanDefinitionOverriding(true) should solve my problem. Maybe I just do it at the wrong time, but it never helped (also I think true is the default value).
My attempt:
I tried to avoid all scanning and register my beans by myself as well:
GenericApplicationContext ctx = (GenericApplicationContext) SpringApplication.run(ProjectBApplication.class, args);
ctx.getBeanFactory().registerSingleton("someService", new project.b.SomeService());
...
I can filter MyServices specifically this way but now I'm running in autowiring problems using SomeService in other (following!) beans.
Maybe I'm just registering the someService bean wrong?
I've already read about BeanPostProcessors, but I did not get how they could help me and where to use them correctly.
Keep in mind: any solution will fit, no matter if filtering MyService's in code, in xml, just tell spring to overwrite beans with more specific ones or what ever.

I figured out I just registered the bean wrong. Using
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(service);
context.registerBeanDefinition(beanName, beanDefinition);
solved the autowireing problem and at the moment every thing works fine.

Related

removing singleton beans from context during the test

I have an application written using spring-REST(spring version 4.1.x and am using spring test for testing it. One of the singleton bean is caching the state so that it can be used for subsequent call in the application. This is although causing the problem when I am running multiple tests as the same bean is being used across tests and subsequent test fails. My question is how do I reset the state in the teardown?
State is not accessible as its a private member of the class. Can we just remove the bean completely from the context? I am using annotated beans and autowiring wherever required.
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = ComponentTestConfig.class)
public class WebServiceComponentTest {
}
I tried to use the solution given in the following link
How can i remove a singleton spring bean from ApplicationContext?
but always faiuls with no bean definition found
((BeanDefinitionRegistry) beanFactory).removeBeanDefinition("myBean");
By the way test fails only when teardown called for resetting the bean state. Bean is found while it is being used by application.
If you want more fine-grained control over your testing application context, mirror your XML config files for testing. Point your test class to only load the XML files from your test directory rather than from your WebContent directory.
That way you can totally exclude the class that is causing you problems from your test context. So your test XML might look something like this:
<context:component-scan base-package =
"au.com.foo.pineapple",
"au.com.foo.dolphin",
"au.com.foo.controllers"
/>
<!--au.com.foo.building-->
and your WebContent XML file might look something like this:
<context:component-scan base-package =
"au.com.foo.pineapple",
"au.com.foo.dolphin",
"au.com.foo.building",
"au.com.foo.controllers"
/>
As M. Deinum pointed out, the safest way to achieve this is to use the #DirtiesContext annotation.
However, as also mentioned, using #DirtiesContext can result in longer test runs since the ApplicationContext will be removed from the ContextCache.
Another option -- a hack really -- is to use the ReflectionTestUtils class from spring-test to change the state of the private member in question.
Regards,
Sam (author of the Spring TestContext Framework)

Injected bean reset to NULL in the Aspect

I am new Spring AOP and Aspectj. I have seen various posts related to injected bean in an aspect being null and I have run into a similar problem. I am still not clear how I should proceed to get past the problem I am currently encountering.
Issue: Currently we are using Spring 3.2.3 and all injection is through Annotation. In my case, the dependent bean is injected properly by Spring but at the point of execution the injected bean is NULL. BTW, this doesn't happen all the time but what I can say is the stack trace when it fails and when it succeeds is slightly different. When the injected bean is not null (I can successfully use the injected bean service), the call to the before advice (in the aspect) always happens before the target method is called as it should.When the injected bean is NULL, the call to the aspect is from the first statement of the target method. At this point, I think another aspect is instantiated and has no reference to the injected bean. Here is the aspect I have created:
#Component
#Aspect
public class Enable{
private NameService nameService;
#Autowired
public void SetNameService(NameSerice service){
// service is injected properly
this.nameSerice = service;
}
#Before("* *.*(..)")
public void callBefore(JoinPoint jp){
//sometimes nameService is null and sometimes it not not
this.nameService.lookup(...);
}
}
Examining the various posts, one way to get around this (as suggested in the post) is to configure the aspect in the XML configuration file and use the factory-method ="aspectOf" and in the configuration inject the reference to the NameService bean as a property. Our whole project uses Annotation based injection (as stated earlier). Assuming I can still configure the above aspect in an XML configuration file, how can I get the reference NameService bean Id so that I can add it to the configuration. I also saw a post related to using Configurable annotation but I assume that is for objects created outside the Spring IOC.
Currently, the aspects are woven using Aspectj compile option in pom.xml. Our root-context.xml contains the entry context:annotation-config and the aspect is injected into Spring IOC because component-scan is turned on for the folder where the aspect resides. Any help will be appreciated
This is well common error when use aspects in spring, you should add
<context:spring-configured/>
and
<aop:aspectj-autoproxy />
also add
#Configurable
#Aspect
public class Enable
To your appContext.xml
aspectOf is another style to do the above but I prefer use the nature of context.
It might be too late to answer this question. But i have come across the same situation and i fixed it as below.
1) Have a setter and getter for "NameService" in your aspect class.
2) Mark "NameService" with #Component ("nameService")
3) Configure "nameService" in xml configuration using setter injection.
4) Re-Start your server after making changes.
This should resolve the problem of getting null for "NameService" in aspect.

#Autowired in bean not in spring context

I am new to springs. Is there an alternative for autowired to be used in a ordinary java bean which is not present in spring context.
You can do so by using Spring #Configurable with some AspectJ magic.
If you need a detailed explanation, here is the link.
And here is a brief overview of how it can be achieved.
First you have some bean that you want injected somewhere:
#Component
public class InjectedClass {
// ...
}
Then, you have a class that is not spring-container managed, that you want to instantiate. You want autowiring to work with this class. You mark it as a #Configurable.
#Configurable
public class NonContainerManagedClass {
#Autowired
private InjectedClass injected;
// ...
}
Now you need to tell spring that you want this non-container managed autowiring to work. So you put the following in your spring configuration.
<context:load-time-weaver />
<context:spring-configured />
Now, since this kind of thing requires modification of the bytecodes of your #Configurable class. So you tell Tomcat to use a different classloader. You can do so by creating a context.xml in your application's META-INF diretory and putting the following in there.
<Context path="/youWebAppName">
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
useSystemClassLoaderAsParent="false"/>
</Context>
Now, Tomcat needs to find that classloader. You can ensure that by putting Spring's spring-tomcat-weaver.jar (probably named org.springframework.instrument.tomcat-<version>.jar) in your tomcat installation's lib directory, and voila, the aspectj magic starts working. For classes that are annotated with #Configurable annotation, the #Autowired dependencies are resolved automatically; even if the instances are created outside of the spring-container.
This is probably the only way to make that work with Spring, in a clean manner. Make sure that you have appropriate dependencies in your classpath.
Another way would be to use the full AspectJ functionality and providing custom aspects around all your constructors and handling the dependency-injection yourself.

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

Inject Spring beans into EJB3

I'm trying to inject Spring beans into an EJB using #Interceptors(SpringBeanAutowiringInterceptor.class) but I cannot get it working with the beanRefContext.xml examples I've seen.
Here's my EJB:
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class AlertNotificationMethodServiceImpl implements
AlertNotificationMethodService {
#Autowired
private SomeBean bean;
}
I've provided a beanRefContext.xml as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="...">
<!-- Have also tried with ClassPathXmlApplicationContext -->
<bean id="context"
class="org.springframework.web.context.support.XmlWebApplicationContext">
<property name="configLocations" value="/config/app-config.xml" />
</bean>
</beans>
But, it seems to be recreating the beans instead of obtaining the existing ApplicationContext. I end up with the following exception because one of my beans is ServletContextAware.
java.lang.IllegalArgumentException: Cannot resolve ServletContextResource
without ServletContext
When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?
I also tried changing my web.xml so the contextConfigLocation points to the beanRefContext.xml, hoping it'd load my Spring config but I end up with the same exception as above.
Does anyone know how to do this properly? The examples I've seen seem to use the same method I'm using which I assume means the beans are being recreated when the Interceptor is invoked (or is that how it's supposed to work and I've misunderstood).
When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?
Yes, and this is in fact what it does. It uses the ContextSingletonBeanFactoryLocator mechanism, which in turn manages a number of ApplicationContext instances as static singletons (yes, even Spring has to resort to static singletons sometimes). These contexts are defined in beanRefContext.xml.
Your confusion seems to stem from the expectation that these contexts have any relation to your webapp's ApplicationContext - they don't, they're entirely separate. So your webapp's ContextLoader is creating and managing a context based on the bean definitions in app-config.xml, and the ContextSingletonBeanFactoryLocator creates another one. They won't communicate unless you tell them to. The EJBs cannot get hold of the webapp's context, since EJBs sit outside of that scope.
What you need to do is to move the beans that need to be used by your EJBs out of app-config.xml and into another bean definition file. This extracted set of bean definitions will form the basis of a new ApplicationContext which will (a) be accessed by the EJBs, and (b) will act as the parent context of your webapp's context.
In order to activate the parent-child link between your webapp's context and the new context, you need to add an additional <context-param> to your web.xml called parentContextKey. The value of this parameter should be the name of the context defined in beanRefContext.xml (i.e. context, in your example).
The beans that stay behind in the webapp's context will be able to reference the beans in the parent context, as will the EJBs. However, the EJBs will not be able to reference anything in the webapp's context.
Also, you cannot use XmlWebApplicationContext in beanRefContext.xml, since that class requires awareness of the webapp, and ContextSingletonBeanFactoryLocator cannot supply that awareness. You should stick with ClassPathXmlApplicationContext there.

Resources