disable spring autowire - spring

i ahave an app with struts2.2 and spring 3.1 and i want to disable spring autowire.
I googled a little bit and found that i have to put at <beans> tab default-autowire="no", but this doesn't seems to work.
Then i fount that i can declare this for every <bean> tag like this : <bean autowire="no">, but this does not seems to work either.
When i enabled spring debug logger i can see a lot aof messages like this :
INFO: DEBUG [http-thread-pool-8080(3)] (ConstructorResolver.java:739) - Autowiring by type from bean name 'com.common.actions.PopupAction' via constructor to bean named 'intermedService'
and the corresponding entry in applicationConfig.xml is :
<beans default-autowire="no"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="PopupAction" scope="prototype" class="com.common.actions.PopupAction" autowire="no">
<constructor-arg type="com.common.services.abs.iIntermedService" ref="intermedService"/>
<constructor-arg type="com.common.services.abs.iLocationService" ref="locationService"/>
<constructor-arg type="com.common.services.abs.iUserService" ref="userService"/>
<constructor-arg type="com.common.services.abs.iPhoneService" ref="phoneService"/>
</bean>
why does spring trying to autowire this action as long as i defined the dependency by hand here and i defined auto-wire="no"?
Or this message tells me that the wiring was made by type via constructor(as i wanted) and "Autowiring by type" means that from the 4 params he matched intermedService with my variable intermed service by type (and not by order or something else)?

The Struts 2 Spring plugin sets autowiring to "name" by default. Currently I don't believe the plugin allows "none" as a value, but you could try using "auto"--I suspect this will not help, as it is still an autowiring bean factory.
This has been brought up before; I don't recall any real resolution. I've brought it up again to see if it can be addressed in the next release where we doing some significant cleanup.
Edit There's also the struts.objectFactory.spring.autoWire.alwaysRespect constant which defaults to false; try setting it to true. I don't recall which sense of the boolean means which, or if it has the effect--looking in to it now.

A way to get around it (until it gets fixed) is to just name your fields/constructor arguments and your beans differently, so that spring can't match them.

I believe default-autowire="no" is enabled by default . i.e, if you don't specify default-autowire, it means default-autowire="no" . Try setting autowire-candidate="false" if you don't want this bean to be autowired http://static.springsource.org/spring/docs/2.5.x/reference/beans.html

Related

Can we replace Springframework annotations (#CacheConfig, #Cacheable, #CachePut) in the XMl file?

I am implementing a module with Spring Cache mechanism. The module is generic and can cache different type of entities. So I don't want to change the Java code and want the user to configure the applicationcontext.xml file accordingly. He can put the name of the different types of entities within the applicationcontext.xml and the code should work. For e.g. -
<context:annotation-config/>
<cache:annotation-driven cache-manager="cacheManager"/>
<context:component-scan base-package="com.nokia.oss.sure.adapter"/>
<bean id="NetworkEntityService" class="com.nokia.oss.sure.adapter.cache.NetworkEntityServiceImpl"/>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" name="NetworkEntity"/>
</set>
</property>
</bean>
He may change NetworkEntity to ServiceEntity and so on.
So in the Java code I need to mention -
#CacheConfig(cacheNames={"NetworkEntity"})
Or I can put the same for every method -
#CachePut(cacheNames="NetworkEntity", key="#entity.sureName")
public Entity addEntity(Entity entity) {
return entity;
}
But as I stated earlier, I don't want to put the cache name "NetworkEntity" in the Java code, but want to put the same in the applicationcontext.xml file. Is it possible?
Furthermore is it possible to omit all the annotations in the Java file? If I just use AbstractApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml"); is it possible to mention in the applicationContext.xml file what are the methods where I want to apply the #Cacheable annotation for e.g.
I searched a lot, couldn't find it anywhere.
Thanks
Nirmalya
I found out the answer. We can put the following in the applicationContext.xml -
<!-- define caching behavior -->
<cache:advice id="cacheAdviceInterface" cache-manager="cacheManager">
<cache:caching cache="NetworkEntity">
<cache:cacheable method="getEntity"/>
<cache:cache-put method="putEntity"/>
</cache:caching>
</cache:advice>
In that case we don't need to put the #CacheConfig, #CachePut etc annotations within the Java file.

ClassPathXmlApplicationContext created from several config files overrides beans with the same types and different ids

I have multiple spring config xml files which are being used to create one global context like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.context.support.ClassPathXmlApplicationContext" id="global.context">
<constructor-arg index="0">
<list>
<value>classpath:config/common/main-springconfig.xml</value>
<value>classpath:config/me/main-springconfig.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
I create context like this:
private static final String springContext = "global.context";
private static final String beanRefContext = "classpath*:global-config.xml";
private ConfigurableApplicationContext springApplicationContext;
ClassPathXmlServiceLocator()
{
BeanFactoryLocator beanFactoryLocator = ContextSingletonBeanFactoryLocator.getInstance(beanRefContext);
springApplicationContext = (ConfigurableApplicationContext) beanFactoryLocator.
useBeanFactory(springContext).getFactory();
}
The problem is that each config has defenition of bean with the same type: some.package.BeanType, but when context is fully instantiated there is only one bean of that type is available.
There is a note in ClassPathXmlApplicationContext javadoc:
In case of multiple config locations, later bean definitions will override ones defined in earlier loaded files. This can be leveraged to deliberately override certain bean definitions via an extra XML file.
But does it mean that even beans with different ids defined in separate config files will be overriden? How can I overcome this issue?
Finally, I found the root cause of the problem. Spring have been working correctly all the time. The problem was in third party class (so called: some.package.BeanType).

Mule invoke message processor

I came across "invoke" element (link) that can be used to invoke java methods from inside the flow. It seemed a perfect solutions for me, since I don't want to use Callable and entry points resolvers and I want to pass extra parameter to the method.
<invoke object-ref="yourBean"
method="yourMethod"
methodArguments="#[message.inboundProperties['inboundPropertyName']]" />
<set-property propertyName="outboundPropertyName"
value="#[payload]" />
I did something like the code above. My question is: how should I create "yourBean"?
I tried to create:
<spring:bean name="yourBean" class="class"/>
but got:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'yourBean' is defined
I also have other beans defined in my tag, but others seemed to work. Does anyone have similar issue?
EDIT:
When I deleted other beans definitions besides "yourBean" everything started to work, but when I add more beans definitions I got following error when I tried to use "yourBean":
Exception stack is:
1. null (java.lang.NullPointerException)
org.mule.processor.InvokerMessageProcessor:280 (null)
2. null (java.lang.NullPointerException). Message payload is of type: String (org.mule.api.MessagingException)
org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor:35 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.ht
ml)
--------------------------------------------------------------------------------
Root Exception stack trace:
java.lang.NullPointerException
at org.mule.processor.InvokerMessageProcessor.transformArgument(InvokerMessageProcessor.java:280)
at org.mule.processor.InvokerMessageProcessor.evaluateArguments(InvokerMessageProcessor.java:200)
at org.mule.processor.InvokerMessageProcessor.process(InvokerMessageProcessor.java:164)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
Which for me seems like the "yourBean" is not instantiated. But why?
My bean definitions:
<bean id="yourBean" class="com.example.BpmService"/>
<bean id="StatusUpdateContext" class="javax.xml.bind.JAXBContext" factory-method="newInstance">
<constructor-arg>
<array>
<value type="java.lang.Class">
com.example.OrderStatusUpdate
</value>
</array>
</constructor-arg>
</bean>
EDIT: Ok, id/name both some to work for Mule invoke. I have had no problems using invoke with multiple bean definitions. This sounds more like an issue with your beans, which you are not sharing, and/or Spring than Mule invoke.

Access to a method of an abstract class in Camel Context version (2.9.1) with Spring DSL

Within a route defined in camel context I would like to access a method of an abstract class that is contained in a 3rd party library I am using.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="objectFactory" class="org.example.Factory" abstract="true"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
...
<marshal>
<rss/>
</marshal>
<marshal>
<string/>
</marshal>
<to uri="jms:feeds"/>
<to uri="file:/tmp/output"/>
<!-- That is the point in the route where I would like to pass the URL of
the folder the files have been written to a static method of an abstract
class in order to instantiate an object
-->
</route>
...
The above snippet shows the route definition in Spring DSL and the definition of the abstract bean. I have tried using the <bean> tag to achieve what I want, but this always ends with a org.springframework.beans.factory.BeanIsAbstractException. Is there no way to just simply access a static method of an abstract class within a camelcontext?
If the method is a static method, you can possible refer to it in the Camel DSL directly
<bean type="org.example.Factory" method="myMethod"/>
Mind that this requires a fairly recent version of Camel where we added support for invoking static methods directly.
I think the easiest way to use an abstract class is to define your own class that extends the abstract class and then call this. You can then use the normal bean syntax like Claus mentioned. In this case non static methods will also work.

What's the difference between #Autowired and getting a bean from the application context?

I have a dao unit test that is declared as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:spring/applicationContext.xml"})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#Transactional
public class RegisterDaoTest extends AbstractTransactionalJUnit4SpringContextTests {
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:/spring/applicationContext.xml");
private IRegisterDao registerDao = applicationContext.getBean(IRegisterDao.class);
When I run the unit test, all pass and I can see the db getting recreated in between unit test executions.
My test db is defined as follows:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:test;sql.syntax_ora=true;create=true"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
<jdbc:script location="file:Artifacts/Hsql Version Scripts/install/droptables.sql" separator=";"/>
<jdbc:script location="file:Artifacts/Hsql Version Scripts/install/install.sql" separator="/;"/>
</jdbc:initialize-database>
But when I change my test to use #Autowired, defined below, it does not execute the init db scripts.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:spring/applicationContext.xml"})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#Transactional
public class RegisterDaoTest extends AbstractTransactionalJUnit4SpringContextTests {
/*
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:/spring/applicationContext.xml");
private IRegisterDao registerDao = applicationContext.getBean(IRegisterDao.class);
*/
#Autowired
private IRegisterDao registerDao;
I don't see what the difference is. I have two applicationContext.xmls, one in the main and one in the test (so I can override the db with the test db)
To me, it should execute the same. Am I missing something?
Thanks,
By default, a Spring context will pay no attention to #Autowired annotations. In order to process them, the context needs to have a AutowiredAnnotationBeanPostProcessor bean registered in the context.
<context:annotation-config/>
registers one of these for you (along with a few others), so you do need it (unless you register AutowiredAnnotationBeanPostProcessor yourself, which is perfectly valid).
If you don't like having #Autowired in your code, then you can explicitly inject properties in the XML using , which just moves the clutter from one place to another.
If your context is extremely simple, then you can use implicit autowiring, as described here. Essentially, this tells Spring to autowire automatically by property name or type. This required very little configuration, but it very quickly gets out of control - it's automatic nature means it's hard to control, and gives you very little flexibility.
In general #Autowired really is the best option.
With application context, you are injecting the bean by yourself.
Annotation wiring isn’t turned on in the Spring container by default. So, before you
can use annotation-based autowiring, you'll need to enable it in your Spring configuration.
The simplest way to do that is with the
<context:annotation-config>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
...
</beans>
Hope this helps.
These two scenarios are very different: in the first case you've got TWO application contexts: one created by test spring framework and one created manually by you for each test. Spring test framework uses #ContextConfiguration to determine which context files are to be loaded. If subsequent tests use the same context files, the context is not recreated, it is reused. That's why your db is initialized only once if you don't additionally create a new context manually.
If you do need to reinitialize the db for each test, you should trigger it manually for example in #Before method. You may also try annotation #DirtiesContext on your test, next to #ContextConfiguration.
To make it clear: you should not create context manually if using spring test framework. #Autowired is the correct approach but you need to find other means to reinitialize your database before each test.

Resources