Convert XML bean definition with parent to Java with annotations - spring

I have an application using a framework that provides certain Spring beans via XML files in the framework. The configuration of my application is currently done partly in XML but mostly with Spring annotations.
Some of the XML bean definitions have parents referring to beans supplied by the framework, e.g.
<bean id="MyBean" parent="FrameworkBean">
<property name="context">
<map merge="true">
<entry key="SomeKey" value-ref="SomeValue" />
</map>
</property>
</bean>
FramwworkBean is defined in an XML file in the framework. There is a chain of bean inheritance. At each step some entries are added to the context:
<bean id="FrameworkBean" parent="AbstractBean">
<map merge="true">...
<bean id="AbstractBean" abstract="true" class="ClassWithContext"/>
I understand the result of all this is construction of a ClassWithContext
instance with a map containing all the entries up the chain.
Is it possible to write Java code to do the same, without duplicating code from the framework XML files?
#Bean("MyBean") ClassWithContext myBean() {
return ??? // code that uses "FrameworkBean" somehow
}
The XML bean definition has no dependency on the type of AbstractBean.
If MyBean can be created by Java code, can that code be written to be equally type-agnostic? Or should I just leave this in XML?

If your "FrameworkBean" is not abstract bean you can try the following:
#Bean
public SomeType myBean(#Qualifier("FrameworkBean") FrameworkBeanType frameworkBean) {
SomeType type = getSomeType();
type.setFrameworkBean(frameworkBean);
return type;
}

Related

Grails initialization

In my Grails app, I need access to configuration exposed by a Java class similar to the below
public class Config {
private Properties properties = new Properties();
static load(String path) {
File configFile = new File(path);
FileReader fileReader = new FileReader(configFile);
properties.load(fileReader);
}
String getProperty(String name) {
properties.getProperty(name);
}
}
I trigger the initialisation of this class in the first line of Bootstrap.groovy by calling Config.load("/conf.properties"). However, the initialization of various Spring beans needs properties that are exposed by Config, but by the time Bootstrap.groovy is executed, Spring initialization has already completed.
So I need to find a way to call Config.load() before construction of the Spring beans, is this possible? I guess there might be an event handler available in /script/_Events.groovy that I could invoke it from, but I'm not sure which handlers are available.
Unfortunately, changing the source code of Config.java isn't an option, and neither is eliminating my usage of this class.
You could try declaring a suitable bean in web-app/WEB-INF/applicationContext.xml, which is the definition of the root web application context as opposed to the GrailsApplication's internal context.
<bean id="initConfig" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="com.example.Config" />
<property name="targetMethod" value="load" />
<property name="arguments">
<list><value>/conf.properties</value></list>
</property>
</bean>
and modify the grailsApplication bean to depend on that:
<bean id="grailsApplication" depends-on="initConfig" class="...">

Spring id-reference not working as expected

I'm working my way through the Spring Framework reference documentation with some very basic application code. So far, I've created an ApplicationContext from an XML file and loaded some beans. I believe I understand this process pretty well. I've loaded some basic beans with attributes based on fundamental types and found that straight-forward.
I'm now working on a composite bean with other beans as its attributes. So far, I've been able to set these attributes using a direct reference to a bean and an inner bean. However, when I try to get the idref element to work (see http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/beans.html#beans-idref-element) I get the following exception:
java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.example.BasicBean] for property 'idRef': no matching editors or conversion strategy found
Code snippets below:
Application Context XML
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="id-bean" class="com.example.BasicBean" scope="singleton">
<property name="value" value="31"/>
</bean>
<bean id="ref-bean" class="com.example.BasicBean" scope="singleton">
<property name="value" value="37"/>
</bean>
<bean id="cb" class="com.example.CompositeBean" scope="singleton">
<property name="id" ref="id-bean"/> <!-- works -->
<property name="inner"> <!-- works -->
<bean class="com.example.BasicBean">
<property name="value" value="43"/>
</bean>
</property>
<property name="idRef"> <!-- exception thrown -->
<idref bean="ref-bean"/>
</property>
</bean>
</beans>
Java App Code
public void main()
{
context = new ClassPathXmlApplicationContext("beans.xml");
CompositeBean cb = context.getBean("cb", CompositeBean.class);
}
Java Bean Code
public class CompositeBean
{
private BasicBean id;
private BasicBean idRef;
private BasicBean inner;
// Default constructor exists
// Setters, getters for each attribute exist
...
}
public class BasicBean
{
private int value;
// Default constructor exists
// Setters, getters for each attribute exist
...
}
Version info: I'm using Eclipse IDE (Kepler), Maven 3.1, Java 7 (1.7.45), Spring 3.2.4
Any thoughts on what I'm doing wrong?
Thanks #Farid for pointing out that I was mis-using the idref attribute in this instance. As the Spring doco points out (which I'd read several times and still missed this) it's designed for passing the id of a bean around a container and not the actual bean. So, stick to the first two means above (ref and inner bean) for passing a bean around.

Can I combine #controller and XML bean mapping in spring?

I currently have a #Controller declared in spring and have a bunch of mappings done like so:
#RequestMapping(value = "foo", method = RequestMethod.GET)
public ModelAndView foo() {
ModelAndView mav = new ModelAndView(
"myjsp");
return mav;
}
However every time I want to add a simple JSP mapping I need to recompile and build a new war and deploy.
This isnt so bad except sometimes other members of the team have requests and it would be easier if they can just go into the test env and create the mapping themselves without having to recompile.
I know that you can do similar mapping using xml but can I do this at the same time that I have the #Controller defined?
Like in the example above how could I define that mapping in XML rather than in java?
or say I needed foo2 to map to myjsp2.jsp
I am using spring MVC 3.2
Look into BeanNameUrlHandlerMapping which allows you specify url patterns for controllers in your configuration. Documentation
Example
<beans>
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/editaccount.form" class="org.springframework.web.servlet.mvc.SimpleFormController">
<property name="formView" value="account"/>
<property name="successView" value="account-created"/>
<property name="commandName" value="account"/>
<property name="commandClass" value="samples.Account"/>
</bean>
<beans>

Spring Injection can not find variable in resource file

I have a resource file created in my project. I want to inject values from resource file into spring bean. i defined the place holder for resource file in the applicacationContext.xml.
<context:property-placeholder location="file:///${MRAPOR_PROPPATH}mRapor.properties" />
I can inject values to beans which is declared in the applicationContext.xml like :
<bean
id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean" >
<property
name="jndiName"
value="${database.jndiName}" />
<property
name="lookupOnStartup"
value="false" />
<property
name="cache"
value="true" />
<property
name="proxyInterface"
value="javax.sql.DataSource" />
</bean>
This works well. However, i can not inject values if i declare beans with spring annotations.
#Component("SecurityFilter")
public class SecurityFilter implements Filter {
public static final String USER = "USER_SESSION_KEY";
public static final String CENTRIFY_USERNAME_KEY = "REMOTE_USERNAME";
#Value("${url.logout}")//I get error here !!!!
private String logoutUrl;
//proper setters and getters.
}
Do you have any idea why i can not access values inside the beans declared using annotations.
Here is my exception
weblogic.application.ModuleException:
at weblogic.servlet.internal.WebAppModule.startContexts(WebAppModule.java:1510)
at weblogic.servlet.internal.WebAppModule.start(WebAppModule.java:482)
at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:425)
at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52)
at weblogic.application.internal.flow.ModuleStateDriver.start(ModuleStateDriver.java:119)
Truncated. see log file for complete stacktrace
Caused By: java.lang.IllegalArgumentException: Could not resolve placeholder 'url.logout' in string value [${url.logout}]
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:173)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:125)
at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer$PlaceholderResolvingStringValueResolver.resolveStringValue(PropertyPlaceholderConfigurer.java:255)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:748)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:745)
Are you sure that the instance of SecurityFilter that actually filters requests is managed by Spring?
By default Filters declared in web.xml are instantiated by servlet container, therefore they are not managed by Spring and Spring annotations such as #Value won't work in them.
However, Spring provides special support for your use case - you can delegate filtering to a component managed by Spring using DelegatingFilterProxy. Declare it in web.xml as follows:
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>...</filter-mapping>
DelegatingFilterProxy will delegate request filtering to a bean named SecurityFilter (as in your #Component).
The #Value is processed by the java compiler whereas the the XML is parsed by Spring Bean Processor - these are two very different things... Why do you assume that should work in the same manner?
Edit: I read up on it and it seems to actually be possible using the Spring EL, you only have to prefix with # instead of $:
private #Value( "#{application.url.logout}" ) String logoutUrl;
Cheers,

What is difference between these 2 Spring Annotation and XML config

What is difference between these 2 Spring Annotation and XML config
1) Annotation Based
#Configuration
#EnableWebMvc
public class MyWebConfig{
//
}
2) XML Based
<mvc:annotation-driven />
I can not see any other difference than xml and annotation.
and When to use which one ?
#Treydone wrote some examples plus expressed subjective opinion about Java based config being better.
I disagree with this statement, because there is no functional difference between Java based configuration and XML configuration, it's only matter of habit which one will you use. Some say traditional XML namespace config is better, others say Java based configuration (which is in Spring since 3.0) is the next level of IoC in Spring.
BTW Annotation based configuration is not the same as Java based one - you wrote example from the latter, so I assume you are choosing between XML and Java configs.
I think you should read:
Spring reference manual about Java based config basic concepts and Enabling MVC
some blog posts: this and this
and then decide which one is the best for you.
P.S. Annotation based configuration is IMO worse choice than these two as it moves some depedency information directly into ordinary classes.
Annotations based configuration is easier and more readable to build than the equivalent in xml. For instance setting a property as map in xml looks like this:
<property name="maps">
<map>
<entry key="Key 1" value="1" />
<entry key="Key 2" value-ref="PersonBean" />
<entry key="Key 3">
<bean class="com.mkyong.common.Person">
<property name="name" value="mkyongMap" />
<property name="address" value="address" />
<property name="age" value="28" />
</bean>
</entry>
</map>
</property>
In a java configuration file, this looks like this:
Map<String, Object> maps = ...
maps.put()...
....setMaps(maps);
There are many others pros:
Add a bean from an instance of an anonymous inner type
See the errors during the compilation, before starting your Spring context and your tomcat...
Add some conditions in your bean construction
For instance:
#Bean
public ViewResolver internalResourceViewResolver() {
ClassLoader classLoader = getClass().getClassLoader();
if (ClassUtils.isPresent("org.apache.tiles.TilesContainer", classLoader)) {
TilesViewResolver viewResolver = new TilesViewResolver();
return viewResolver;
} else {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
Many others....

Resources