Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

Will they blend? How to use Spring with JSF for resource bundling

Screen Shot 2014-01-06 at 12.33.06 PM

Did you know that when it comes to Java EE development, you sometimes get to have your cake and eat it too? That’s right: by combining the strengths of multiple Java web frameworks, you can often benefit more than by using just one framework to rule them all.

In a recent RebelLabs report called The 2014 Decision Maker’s Guide to Java Web Frameworks, we scored 8 different web frameworks based on different use cases and features. One of the most interesting findings was that although the well-known Spring Framework received average scores in all but a couple areas, it’s a great foundation for combining with another framework, such as JSF, GWT or Wicket.

So what if you are developing multiple web modules in a Java EE application? At some point, you probably will need to put common Java code and assets in one place and distribute it along your applications. In this article, we discuss how to do this using Spring and JSF together. Score!

Why would you need to bundle resources?

Let’s say you’re developing a range of Business Support Systems (BSS) for telecommunications companies like AT&T, Vodafone or MTS. You’ll probably want to offer your clients different web modules for providing CRM, order management, product catalog, etc. to meet modern requirements.

This also means that your product and customer data will need to accessible by various modules and applications, and it’s therefore sensible to centralize the common stuff (using the DRY–Don’t Repeat Yourself–principle. This suggests that you should use existing tools and methodologies (i.e. Java, Spring) to solve this if you can, to avoid bugs and reduce maintenance costs.

Java EE now provides elegant solutions for this scenario, and with release of JSF 2, the UI world can now enjoy this goodness by putting images, stylesheets, JavaScript or even facelet pages within one JAR file. These resources can easily be distributed from the bundled JAR file and be used within JSF 2 powered web applications.

Enter Spring and Resource Bundle-fu

But before we get too excited, there are some limitations. One thing JSF can’t handle yet is centralized resource bundling. What does this mean?

Well, imagine that you have a button with a text ‘Yes’. You are probably going to define the label ‘Yes’ in a bundle package for the various languages that your applications are supporting. Things are still ok until this point. Since ‘Yes’ is a common term for a button, most probably it will be all over the pages of each application. So this definition needs to be distributed across all your web applications.

At some point things become unmanageable, since it’s inevitable that you’ll have the exact same definitions for buttons, labels and etc. throughout the applications. So question here is: Wouldn’t it be nice to just put all these recurring parts of the bundle package in a common JAR file and get it distributed?

This way, your modules and applications could seamlessly be integrated with the infrastructure, and developers can easily decide on which key-value pair should be moved to the common place and which should stay application-specific.

This is where Spring, the most-used commonly framework in Java, comes to the rescue of JSF 2. With the help of Spring, you will find a neat solution to this problem–we’ll define the common values for our bundles in a core JAR file for use within our web application. The trick here is in bypassing the JSF resource bundle mechanism and delegating this work to the Spring’s ReloadableResourceBundleMessageSource mechanism. We will also tweak Spring a little bit (we’ll come to that point soon) to let us store the common keys in one place and manage them from there.

Setting up the project structure

We wanted to provide a full working example for demonstration purposes, so here we have two projects defined with Maven; one is the my-core, which is the JAR project that contains common resource bundle and my-web is the web application that demonstrates the resource bundle resolving mechanism.

mert1

Your my-core project has the bundles messagesBase_en_US.properties for English and messagesBase_tr_TR.properties file for localization in Turkish. Similarly, your my-web application contains messages_en_US.properties for English and messages_tr_TR.properties for Turkish.

These files should be loaded within the application context of Spring. At this point we’re employing the ReloadableResourceBundleMessageSource and altering it a little bit to support the loading of messageBase properties files that reside under my-core.jar.

The definition messageSource also contains the properties for handling the encoding of the bundle files. You can change the fileEncodings and defaultEncoding properties as you like it in your project. Having them set to UTF-8 made it easy for us to manage the Turkish files.

<bean id="messageSource" class="org.rebellabs.ReloadableResourceBundleMessageSource">
    <property name="fileEncodings" value="UTF-8" />
    <property name="defaultEncoding" value="UTF-8"/>
    <property name="basenames">
        <list>
            <value>classpath*:messagesBase</value>
            <value>classpath*:messages</value>
        </list>
    </property>
</bean>

For curious readers, we can say that we modified the refreshProperties method of the ReloadableResourceBundleMessageSource class in order to load the bundles files that reside in JAR files within the classpath. The full implementation of the class is stated in this Gist: https://gist.github.com/mulderbaba/7972040

Since we haven’t defined any resource bundle in the faces-config.xml file we need to find a way to bridge the messageResource with the UI part. Here, we implemented a nice and clean solution that embodies SpringBeanFacesELResolver el-resolver mechanism. We defined a Spring bean that extends the java.util.HashMap with the name msg:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.stereotype.Component;

import javax.faces.context.FacesContext;
import javax.servlet.ServletRequest;
import java.util.HashMap;

@Component(value = "msg")
public class ResourceBundleBean extends HashMap {

    @Autowired
    private MessageSource messageSource;

    @Override
    public String get(Object key) {
        ServletRequest request = (ServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
        String message;
        try {
            message = messageSource.getMessage((String) key, null, request.getLocale());
        }
        catch (NoSuchMessageException e) {
            message = "???" + key + "???";
        }
        return message;
    }
}

The msg bean is a @Component that auto-wires the messageResource bean inside. And we did a hack-tic solution here by extending the HashMap class and we’ve overridden the get method to lookup the values for the given key within the bundles defined with the basenames property of messageSource bean.

As we mentioned above, the JSF el-resolver definition, SpringBeanFacesELResolver, should be registered in faces-config.xml in order to delegate the bean resolving mechanism to Spring.

<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>

Now it’s time to request the key values! Here is a simple page that gets the username and prints out a greeting:

mert2

The implementation of the page is here:

&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;
                xmlns:h=&quot;http://java.sun.com/jsf/html&quot;&gt;
    &lt;h:body&gt;
        &lt;h:form&gt;
            &lt;h:panelGrid columns=&quot;2&quot;&gt;
                &lt;h:outputText value=&quot;#{msg.typeYourName}&quot;/&gt;
                &lt;h:inputText value=&quot;#{mainView.parameter}&quot; /&gt;
                &lt;h:panelGroup&gt;
                    &lt;h:commandButton value=&quot;#{msg.btnYes}&quot; action=&quot;index&quot;  /&gt;
                    &lt;h:commandButton value=&quot;#{msg.btnCancel}&quot; action=&quot;#{mainView.cancel}&quot; /&gt;
                &lt;/h:panelGroup&gt;
            &lt;/h:panelGrid&gt;
            &lt;h:outputText value=&quot;#{msg.greeting} #{mainView.parameter}&quot; rendered=&quot;#{mainView.parameter != null}&quot; /&gt;
        &lt;/h:form&gt;
    &lt;/h:body&gt;
&lt;/html&gt;

The msg bean is being used as the resource bundle variable of JSF, which is used in an EL expression. Each parameter after the ‘msg.’ will be treated as key values and the get() method of the msg bean will be invoked.

Final words and resources

In this article, we tried to show you how to combine the strengths of two frameworks, Spring and JSF, for achieving your goals with complex multi-module enterprise apps; namely, how to effectively share resource bundles using existing methods instead of writing a bunch of your own code. The idea is that this approach will ease your development & maintenance processes while keeping your code clean since it’s a reflection of the DRY principle.

All code provided above is available on GitHub at https://github.com/mulderbaba/bundlizer. Also, jetty-maven-plugin is defined within the pom.xml of my-web, so after pulling the code just run mvn jetty:run under my-web and request for http://localhost:8080/my-web/index.jsf in your browser. You’ll then see that simple page for demonstrating the bundle resolving mechanism.

I hope you found this helpful! Let me know what you think below in the comments section, or by tweeting @mertcal or @ZeroTurnaround.


Want to know more about Java web frameworks? Check out some of our detailed reports!

Learn more about Java's top 8 web frameworks
 

  • leoaxi97

    How can i use it from ManageBean

  • Mert ÇALIŞKAN

    @leoaxi97:disqus if you are managing your JSF backing beans via Spring, you can inject the ResourceBundleBean into your managedBean easily and use it since it’s also a Spring managed bean.

  • Rafael Ruiz Tabares

    Nice article! I got a doubt, how do you use parametized messages and replace placeholders?

    Thanks!

  • p_bodnar

    Nice article, but with one important shortcoming: you shouldn’t take the actual locale from ServletRequest (where locale can be virtually any), but rather by calling FacesContext.getCurrentInstance().getViewRoot().getLocale() (which is limited by faces-config.xml) :)