19 Nov

Spring Boot extension for Stripes framework

Stripes and Spring Boot

We’ve recently had the opportunity of bringing Spring Boot into our technology stack and we’ve witnessed first-hand why it has been awarded the most innovative contribution to the Java ecosystem at the 2.016 JAX Innovation Awards.

Additionally, a lot less known, but far from not being top notch quality software, we also use Stripes, an MVC web framework, which heavily relies on configuration by convention and is, above all, extremely easy and fun to work with. It doesn’t have the miryad of posibilities that other frameworks (like, for example, Spring MVC) offer, but for sure it covers the 99.9% of functionalities that a typical web application is going to have, and it covers them pretty well. For us, that is more than enough. Another of its great strengths is how “natural” it feels, how everything works as expected, without nasty surprises along the way, and how easy is to extend it.

Precisely because it is a framework which isn’t widely known, it doesn’t have an Spring Boot starter module, which was an excellent excuse for us to develop it and, while we were at it, learn about Spring’s Boot internals. The end result is available on github.

Developing an Spring Boot custom starter module

Spring’s Boot reference guide is an excellent starting point when developing a new starter module. In our case, we are going to develop twothree maven modules:

  • starter: an (almost) empty jar, basically used to provide the default module dependencies. Other than that, it contains a ./META-INF/spring.provides file, which references the next module,
  • autoconfigure: which contains the Spring Boot magic; this module is responsible of instantiating and setting up whatever Spring beans are needed and, optionally, register a namespace which to provide configuration values. Dependencies on this module should be marked as optional, so they aren’t pushed with this module when importing it.
  • sample: not really necessary, but having a working example which showcases the new starter module is always worth looking at. In this case, we will transform the calculator from Stripes’ quick start guide into an Spring Boot application.

Contents of autoconfigure module

The entry point is located on the ./META-INF/spring.factories file, which references an Spring Configuration class through the org.springframework.boot.autoconfigure.EnableAutoConfiguration entry:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=net.sourceforge.stripes.springboot.autoconfigure.StripesAutoConfiguration

The StripesAutoConfiguration class is a normal Spring’s configuration class (and because of this, annotated with @Configuration), which is responsible of setting up a couple of FilterRegistrationBeans which contain both StripesFilter and DynamicMappingFilter. In this concrete case, some other Spring beans are also defined, so that Spring MVC can be deactivated.

@Configuration
@ConditionalOnClass( name="net.sourceforge.stripes.springboot.autoconfigure.SpringBootVFS" ) // @see http://stackoverflow.com/a/25790672
@ConditionalOnProperty( name = "stripes.enabled", matchIfMissing = true )
@EnableConfigurationProperties( StripesProperties.class )
public class StripesAutoConfiguration {

private static final Log LOG = Log.getInstance( StripesAutoConfiguration.class );
[...]

    @Bean( name = "stripesDynamicFilter" )
    @ConditionalOnMissingBean( name = "stripesDynamicFilter" )
    public FilterRegistrationBean stripesDynamicFilter() {
        final DynamicMappingFilter filter = new DynamicMappingFilter();

        final List< String > urlPatterns = new ArrayList< String >();
        urlPatterns.add( "/*" );

        final FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter( filter );
        registration.setUrlPatterns( urlPatterns );
        registration.setDispatcherTypes( DispatcherType.REQUEST, DispatcherType.INCLUDE, DispatcherType.FORWARD, DispatcherType.ERROR );
        registration.setOrder( Ordered.LOWEST_PRECEDENCE );
        return registration;
}

[...]

It can be observed that this class is annotated at both type and method level with several @ConditionalOnXXX annotations. These annotations allow the configuration beans to be optionally registered based on environment properties, the existence of other beans, etc. They sit at the very center of Spring’s Boot “magic”. It’s an extremely simple, clever and powerful mechanism which, next to the election of very well thought default values (which can be easily replaced), are the main reason of this framework’s success. Kudos to the bright minds behind these ideas.

In addition to all of this, this class is also annotated with @EnableConfigurationProperties( StripesProperties.class ), which signals the class used to reserve the stripes namespace at the application.properties file. This class is a normal POJO, whose class members map to their equivalents at the application.properties file. The only particularity of this class is that it is annotated with @ConfigurationProperties, which is used to state the reserved namespace:

@ConfigurationProperties(prefix = StripesProperties.STRIPES_PREFIX )
public class StripesProperties {

    public static final String STRIPES_PREFIX = "stripes";

    /** value for: {@code ActionBeanPropertyBinder.Class} */
    private String actionBeanPropertyBinder;

    /** value for: {@code ActionBeanContextFactory.Class} */
    private String actionBeanContextFactory;

    /** value for: {@code ActionBeanContext.Class} */
    private String actionBeanContext;

[...]
    /** placeholder for custom configuration */
    private Map< String, String > customConf = new HashMap< String, String >();

[...]

// getter & setters

[...]
}

As a curiosity, this class also includes a Map instance, which will be used to gather all kind of custom values, which will get added to the Stripes’ filter configuration. This way, an entry like stripes.custom-conf.MY_CUSTOM_KEY=MY_CUSTOM_VALUE on the application.properties file will get added to the Stripes’ filter as a parameter with key MY_CUSTOM_KEY and value MY_CUSTOM_VALUE.

Contents of sample module

As said before, not strictly necessary, to the extent that is not mentioned on the Spring Boot reference guide, but having a working example is the best way to have your extension used. This time, the example is taken from the Stripes’ reference guide calculator sample. This module is a normal Maven module, whose pom.xml includes the org.springframework.boot:spring-boot-maven-plugin plugin execution, and which includes both the Java class and the JSP from de reference guide exactly as they are in there. Finally, an application.properties file is added with the required Stripes’ configuration (note: this starter module is smart enough to configure the framework with some reasonable default values as to be able to start up the application without having to set any specific value).

Once all the modules have been compiled, the application can be started from this module either by executing mvn spring-boot:run or java -jar target/stripes-spring-boot-sample-1.0.0.jar, and it will be ready to go at http://localhost:8080/index.jsp.

After doing all this, an announce was sent to the Stripes distribution list, so there is a chance it could get into the main distribution and be available for the 1.7.0 release.

Leave a Reply

Your email address will not be published. Required fields are marked *