How to handle internationalization in a Spring application (inside a class) - java

I already know how to handle internationalization in a Spring application using <spring:message code="xxx"/> in a JSP page. Now my users are allowed to change languages using simple links like
IT and EN
Now, I have to handle internationalization inside a class. This is what I did:
1) I created a text.xml file to identify where my texts are
.....
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="struttura"></property>
</bean>
......
2) I created a different properties files according to different languages
3) I use this method to get the message according to the locale
......
ApplicationContext context = new ClassPathXmlApplicationContext("text.xml");
String stringa = context.getMessage("textCode",null, locale);
.......
Everything works. But I'm sure this is not the fastest and cleanest way to do it. It looks too intricate!
Does anybody know a better way to reach my goal?

MessageResource is a Spring managed bean so you can just inject it into your controllers (or other Spring managed classes):
#Autowired
private MessageSource messageResource;

Related

Spring injecting or autowiring datasource bean to class

this may be a very novice question, but I have searched and either I have a large gap in my understanding or am doing something incorrectly that I cannot figure out.
In my context file here is an excerpt
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${datasource.driverClassName}" />
<property name="url" value="${datasource.url}" />
<property name="username" value="${datasource.username}" />
<property name="password" value="${datasource.password}" />
</bean>
<bean id="myBeanOne" class="a.b.c.myBeanOne">
<property name="dataSource" ref="dataSource" />
</bean>
Now in myBeanOne I have:
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource (DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public void myMethod() {
String sql = "'My generic SQL update query'";
try {
this.jdbcTemplate.update(sql);
} catch (org.springframework.dao.EmptyResultDataAccessException ex) {
}
System.exit(0);
}
when I try to execute this on the line where setDataSource is invoked I get this error:
ERROR org.springframework.integration.handler.LoggingHandler
org.springframework.integration.MessageHandlingException:
java.lang.NullPointerException
on the line: this.jdbcTemplate.update(sql);
I have tried maybe ten different configurations to get this to work, but I cannot seem to do it. Any assistance is appreciated, thank you.
Edit: as per Luiggi's comment:
//in yet another classes run method
myBeanOne bOne = SomeOtherClass.create(); //just returns new myBeanOne
bOne.myMethod();
Neither SomeOtherClass or this class are classified as beans in the context or have any presence in the context.
I know that this is a very basic question but I am struggling with it.
Thank you for your patience.
As noted in comments, the problem is that you're manually creating the bean instead of letting Spring container create it. Basically, you're doing this:
new MyBeanOne()
So Spring container can't inject any of the fields you have configured thus being null e.g. jdbcTemplate field. There are some solutions to this:
Convert your SomeOtherClass into a bean managed by Spring container and let it inject the MyBeanOne instance (probably using #Autowired annotation).
If latter approach can't be done since you need to manually create the bean, you can create the bean manually as shown here: How to create spring beans dynamically?
But this implementation makes you hardcode somewhere the spring config file name and use it in your code. So, a better approach would be option 3.
Look at this solution: Creating New Spring Beans on Demand, where you create a client abstract class with a method that Spring will implement to retrieve a new instance of your Spring managed bean.
I found another way to handle this by using #Configurable annotation. By decorating your bean with this annotation, you can create a new instance of the bean on demand and Spring will manage the injection of Spring managed beans for you. But to achieve this, Spring needs to use aspects behind the scenes and you should activate usage of aspects for your project. The explanation is quite long, so I provide links that explain in depth this solution:
Spring Framework: 7.8 Using AspectJ with Spring applications
Using Spring's #Configurable in three easy steps
Note that in order to enable this feature, you have to add a java agent when starting the JVM that will weave the class at runtime using aspects.
NullPointerException on the line: this.jdbcTemplate.update(sql);
If the NPE is actually on that line, then this.jdbcTemplate is obviously null. If this is true then either:
The setDataSource(...) method is not being called in Spring, possibly because the #Autowired is not right somehow. It would be easy to add a System.out.println(...) or put a debugging breakpoint in setDataSource to see if it is being called.
If it is being called then maybe there are more than one instance of a.b.c.myBeanOne? Are you for sure getting the instance being called from another class from the Spring context? Put a breakpoint in setDataSource and notice the this object reference id. Then put a breakpoint on the this.jdbcTemplate.update(...) line and make sure that the this reference-id is the same.

Spring Java Config using Autowired caused NPE

I am having difficulty understanding why something in Spring Java Config using #Autowired does not work.
First, I am trying to move all my #Autowired annotations in the Java Config classes. This has the effect of making my "POJOs" back into real POJOs. I can then not only test them easily outside of a Spring context, but can also use mock objects easily and readily.
So I first tried this:
#Configuration
public class Module3ConfigClass {
#Autowired
private Module1Bean1 module1Bean1;
#Autowired
private Module2Bean1 module2Bean1;
#Bean
public Module3Bean1 module3Bean1() {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
However, when the Module3Bean1 constructor is invoked, both passed in Beans are null. If you didn't follow my made up naming convention above, both of those beans would be created by a separate Java Config configuration file. Also note that everything is wired up correctly - I know this because everything works perfectly when the #Autowired tags are on the corresponding private member fields inside of Module3Bean1.
FWIW, I tried adding an #DependsOn annotation to module3Bean1() method, but had the same results. I guess I just would really like to understand this behavior, is it correct (I suspect it is, but why)?
Finally, I found an acceptable workaround shown here:
#Configuration
public class Module3ConfigClass {
#Bean
#Autowired
public Module3Bean1 module3Bean1(Module1Bean1 module1Bean1, Module2Bean1 module2Bean1) {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
This seems fine to me, but if anyone would care to comment on it, that would be welcome as well.
I think you came across same problem I just had. In my case problem was invalid xml configuration. In my module B I had config like :
<beans>
<context:component-scan base-package="com.moduleB"/>
<import resource="classpath:applicationContext-moduleA.xml"/>
</beans>
In moduleA context I placed "context:annotation-config" annotation.
When I change import/context order to :
<beans>
<import resource="classpath:applicationContext-moduleA.xml"/>
<context:component-scan base-package="com.moduleB"/>
</beans>
Autowiring for configuration class properties started to work.
We had the same issue and came to the conclusion that the error arose because we had a circular dependency where a BeanPostProcessor was involved.
A PropertyPlaceholderConfigurer (a BeanPostProcessor) has been configured to set its propertiesArray property with the help of another bean:
<bean id="globalPropertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
lazy-init="false" depends-on="javaLoggingConfigurer">
<property name="locations">
<list>
<value>classpath:config/host/${env.instance}.properties</value>
<value>WEB-INF/config/host/${env.instance}.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true" />
<property name="propertiesArray" value="#{springPropertyFinder.findProperties()}" />
</bean>
The used springPropertyFinder bean to set the propertiesArray is not a BeanPostProcessor but a "normal" bean that gathers all Properties instances with:
public Properties[] findProperties() {
Map<String, Properties> propertiesMap = applicationContext.getBeansOfType(Properties.class);
for (String title : propertiesMap.keySet()) {
PropertiesLoggerUtil.logPropertiesContent(logger, "Springcontext Properties ("+title+")", propertiesMap.get(title));
}
return propertiesMap.values().toArray(new Properties[propertiesMap.size()]);
}
The #Configuration class contained a bean of type Properties
So our assumption is that the #Configuration class has been created without being processed by the ConfigurationClassPostProcessor (also a BeanPostProcessor), because the PropertyPlaceholderConfigurer depends on the springPropertyFinder, which depends on the properties bean in the #Configuration class. The order of the BeanPostProcessors is probably not setup right under these circumstances.
This described setup worked in XML, but not with Java config.

Properties Handling With Seam In A Spring-like fashion

One of the Spring features I like the most is how you can handle properties loaded from a file. You only to need to set up a bean like the one below
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/app.properties" />
</bean>
Now you are able to inject the properties values loaded from the app.properties into your beans by using either xml (see below) or annotations.
<bean class="com.example.PersonDaoImpl">
<property name="maxResults" value="${results.max}"/>
</bean>
results.max is one of the properties.
I'm great fan of this feature because it enables me to create quite flexible applications that I can turn on/off some functionality by only changing one property - without redeploying the app.
Now I'm working with JBoss Seam and I've been struggling to find a way to do something similar using this framework.
Does anyone know how to do it? If not, does anyone have any idea of how I could handle properties in a nice way using Seam (I have seen some ways - but none of them were good enough).
Thanks.
If there's no appropriate way using you software stack (is there really no dependency injection!?). I'd say: Use Google Guice (https://code.google.com/p/google-guice/ , https://code.google.com/p/google-guice/wiki/Motivation?tm=6)!
Bad thing with Guice: You may have to read a lot to understand how it works, and what you can do with it. But after it's running you will simply inject your Properties object where you need it:
class YourClass {
#Inject Properties myProperties;
#Inject
public YourClass() { ... }
public void someMethod() {
use the property
}
}
or if you need the properties inside the constructor, you could also do:
class YourClass {
final Properties myProperties;
#Inject
public YourClass(Properties myProperties) {
this.myProperties = myProperties;
}
public void someMethod() {
use the property
}
}
Using Guice maybe enforces you to refactor your whole app.
But if you already have some DI framework, you should simply use that :)

Spring #Value annotations don't work, returning null

I have the following class:
#Component
public class MyClass {
#Value("${main.url}") private String mainUrl;
the following XML context:
<context:annotation-config/>
<context:component-scan base-package="mypackage"/>
<context:property-placeholder file-encoding="UTF-8" location="classpath:/app.properties" ignore-unresolvable="true"/>
and prop file:
main.url=veryniceurl.com
Injection doesn't work, it is always null.
I read a lot of similar examples and I thought that everything is ok but it isn't. Can anyone tell me if I forgot about something? I'm working with Mule ESB.
#Value doesn't seem to work with Mule. Instead you need to wire it up through the Mule XML, where I assume you are loading your component as a Spring Bean:
<spring:bean id="MyClass" class="com.example.MyClass">
<spring:property name="mainUrl" value="${main.url}"/>
</spring:bean>
Give an id to your properties and use this syntax :
#Value("#{jetProperties['jetBean.name']}")
<!-- define the properties file to use -->
<util:properties id="jetProperties" location="classpath:/jet.properties" />
From http://chrislovecnm.com/2010/03/08/spring-3-java-based-configuration-with-value/
Did you add the context placeholder in the dispatcher-servlet.xml ? As per here, Spring #Value annotation in #Controller class not evaluating to value inside properties file they seem to have solved it by adding it there instead of the application context

What is the cleanest way to autowire Spring Beans in a JSP?

We're currently adding some new features to an old webapp which was using only JSP without any framework for the front. We have added Spring recently, and we would like to autowire our beans in our modified JSP, while not rewriting everything to use SpringMVC, Struts2 or Tapestry5.
We're using autowiring by type, so it leads to get some code like this in the JSP, while previously getting the web application context ( as "wap") :
MyDao myDao = (MyDao) wap.getBeansOfType(MyDao.class).values().toArray()[0];
We would like not to use such a code but rather automagically inject our beans directly in our JSPs as we would in a business bean using #Autowired annotation.
In fact we're looking to the cleanest ways to inject our beans in our JSPs. What do you use ?
You can use Spring's ContextExposingHttpServletRequest:
HttpServletRequest decorator that
makes all Spring beans in a given
WebApplicationContext accessible as
request attributes, through lazy
checking once an attribute gets
accessed.
This would require your controller code to wrap the original HttpServletRequest in a ContextExposingHttpServletRequest, and then forward that to the JSP. It can either expose specific named beans, or every bean in the context.
Of course, this just shifts the problem from your JSPs to your controller code, but that's perhaps a more manageable problem.
You can't use #Autowired directly because both your jsps and servlets are instantiated by the servlet conainer. So they are not part of the spring context and hence their dependencies aren't injected.
You can:
move all code that to pure servlets, rather than in jsps - leave only presentation in the jsps.
use #Configurable on your servlets (and add a javaagent, as described in the linked docs)
Another way, is to make the servlet part of the current context manually. This is possible in both jsps and servlets:
public void init() {
WebApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(getServletContext());
AutowireCapableBeanFactory bf = ctx.getAutowireCapableBeanFactory();
bf.autowireBean(this);
}
This will resolve the #Autowired annotated dependencies.
Now, I'm not sure whether servlet containers are required to use only one instance of a servlet class. If not, you'd better place the above code in a getter-method for the dependency (getDao()) and if the #Autowired property is null (i.e. another instance of the servlet-class is used by the container) - perform the above operation.
That all said, really consider using a web framework (any of the ones you listed). Having logic in jsps is completely wrong, hard to support, hard to read, etc.
What about overriding jspInit() method and adding Autowiring support:
<%# page import="com.example.ExampleService"%>
<%# page import="org.springframework.beans.factory.annotation.Value"%>
<%# page import="org.springframework.beans.factory.annotation.Autowired"%>
<%# page import="org.springframework.web.context.support.SpringBeanAutowiringSupport"%>
<%!
public void jspInit()
{
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
getServletContext());
}
#Value("${example.property}")
private String someField;
#Autowired
private ExampleService exampleService;
%>
<% final Object data = exampleService.getSomething(someField); %>
I doubt that there is a clean way to inject dependencies into a JSP.
I think that the clean solution would be to start refactoring your code to get the business logic out of the JSPs, using either SpringMVC or one of the alternatives you cited.
Start with one or more minimalist controllers that simply pass the request to the JSPs with the injected beans as attributes; #skaffman's answer gives one way to do that, or you could do it more selectively. Then progressively migrate code out of the JSPs and into the controllers.
This isn't autowired, but Spring can expose your bean names into the request context, you just need to configure it in the viewResolver.
From: https://raibledesigns.com/rd/entry/spring_mvc_jstlview_and_exposecontextbeansasattributes
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="exposeContextBeansAsAttributes" value="true"/>
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>

Categories