Custom Json Serializer and Deserializer for Joda datetime objects

This post demonstrates how to add custom Json serializer and deserializer classes for Joda datetime objects when used with Jackson JSON processor. I use LocalDateTime in the examples here but the same approach applies to other joda date(time) classes.

Default Serialization

By default, Jackson serializes the whole joda object as is. For example, consider the following object:

 public class ExampleDto {
      private LocalDateTime asDefault = LocalDateTime.now();
      ...

Serializing it with Jackson with

import com.fasterxml.jackson.databind.ObjectMapper;
...
ObjectMapper mapper = new ObjectMapper(); 
String json = mapper.writeValueAsString(new ExampleDto());

will return something like below in the json string:

{"asDefault":{"era":1,"dayOfMonth":24,"dayOfWeek":6,"dayOfYear":24,"year":2015,"yearOfEra":2015,...}

Not really useful

LocalDateTimeSerializer / LocalDateTimeDeserializer

Jackson provides an alternative for handling Joda objects. For example

public class ExampleDto {
       @JsonSerialize(using = LocalDateTimeSerializer.class)
       @JsonDeserialize(using = LocalDateTimeDeserializer.class)
       private LocalDateTime asArray = LocalDateTime.now();

This will return an array of integer representing the datetime in the json string, for example:

{"asArray":[2015,1,24,10,31,3,379]}

Custom Serializer and Deserializer

It is also possible to customize the output json by adding custom serialization and deserialization classes. For example, to generate json like:

{"custom":
     {"date":"2015-01-24",
      "time":"10:31:03"
}

The above format is useful when you have to persist the Json in NoSQL database such as MongoDB for datetime queries. To achieve this, first modify the @JsonSerialize and @JsonDeserialize annotations with the names of custom classes and then implements the custom classes:

public class ExampleDomain {
      @JsonSerialize(using = CustomLocalDateTimeSerializer.class)
      @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
      private LocalDateTime custom = LocalDateTime.now();

Class CustomLocalDateTimeSerializer

public class CustomLocalDateTimeSerializer extends StdScalarSerializer<LocalDateTime> {

      private final static DateTimeFormatter DATE_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd");
      private final static DateTimeFormatter TIME_FORMAT = DateTimeFormat.forPattern("HH:mm:ss");
 
      public CustomLocalDateTimeSerializer() {
            super(LocalDateTime.class);
      }

      protected CustomLocalDateTimeSerializer(Class<LocalDateTime> t) {
            super(t);
      }

      @Override
      public void serialize(LocalDateTime value, JsonGenerator jgen, SerializerProvider prov      ider) throws IOException, JsonProcessingException {
            jgen.writeStartObject();
            jgen.writeStringField("date", DATE_FORMAT.print(value));
            jgen.writeStringField("time", TIME_FORMAT.print(value));
            jgen.writeEndObject();
      }
}

Class CustomLocalDateTimeDeserializer

public class CustomLocalDateTimeDeserializer extends StdScalarDeserializer<LocalDateTime> {
      private final static DateTimeFormatter DATETIME_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");

      public CustomLocalDateTimeDeserializer() {
            super(LocalDateTime.class);
      }

      protected LocalDateTimeDeserializerMongoDb(Class<?> vc) {
            super(vc);
      }

      @Override
      public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
           String dateStr = null;
           String timeStr = null;
           String fieldName = null;
           
           while (jp.hasCurrentToken()) {
                JsonToken token = jp.nextToken();
                if (token == JsonToken.FIELD_NAME) {
                     fieldName = jp.getCurrentName();
                } else if (token == JsonToken.VALUE_STRING) {
                     if (StringUtils.equals(fieldName, "date")) {
                          dateStr = jp.getValueAsString();
                     } else if (StringUtils.equals(fieldName, "time")) {
                          timeStr = jp.getValueAsString();
                     } else {
                          throw new JsonParseException("Unexpected field name", jp.getTokenLocation());
                     }
                } else if (token == JsonToken.END_OBJECT) {
                     break;
                }
           }
           if (dateStr != null && timeStr != null) {
                  LocalDateTime dateTime = LocalDateTime.parse(dateStr + " " + timeStr, DATETIME_FORMAT);
                  return dateTime;
            }
         return null;
      }
}

Note how the JsonParser is used in the deserializer. Also, the datetime formats used in the serializer and deserializer must match.

Implementing OAuth2 with Spring Security

I would share my notes on understanding how to set up Spring Security to implement OAuth2. My ultimate goal is to implement an authority provider (Authorization Server in OAuth2 terminology) to support multiple microservices. In this post, I will describe step by step on how to setup Spring Security with OAuth2 and demonstrate how a web server client should interact with the Oauth2 servers.

OAuth2 Roles

OAuth2 consists of the following “roles”:

  1. User / Resource Owner – an entity capable of granting access to a protected resource.
  2. Resource Server – server hosting the protected resources, capable of accepting and responding to protected resource requests using access token
  3. Client – An application making requests to protected resources on behalf of the owner. It can be a web app server, a mobile app, or a client side (e.g. javascript) application.
  4. Authorization Server – Server issuing access tokens to client after successfully authentication the resource owner and obtaining authorization.

Note:

  1. Many common servers, e.g. Facebook, Google APIs, implement both the Authorization and Resource Servers.
  2. Depending on the type of clients, the interaction with the OAuth2 servers varies. This blog will focus on a web server client. Aaron Parecki’s blog post provides a concise description of OAuth2 and the interactions required by various client applications

Spring Security OAuth2 Configuration

The codes used in this blog post are largely taken from the sample here, with some minor additions/changes.

Authorization Server

The codes to configure an authorization server are shown below.

@Configuration
@ComponentScan
@EnableAutoConfiguration
@RestController
public class Application {

 private static final String RESOURCE_ID = "blog_resource";

 public static void main(String[] args) {
      SpringApplication.run(Application.class, args);
 }

 @Configuration
 @EnableAuthorizationServer // [1]
 protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

      @Autowired
      private AuthenticationManager authenticationManager;

      @Override // [2]
      public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
           endpoints.authenticationManager(authenticationManager);
      }

      @Override // [3]
      public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
           // @formatter:off
           clients.inMemory()
           .withClient("client-with-registered-redirect")
           .authorizedGrantTypes("authorization_code")
           .authorities("ROLE_CLIENT")
           .scopes("read", "trust")
           .resourceIds(RESOURCE_ID)
           .redirectUris("http://anywhere?key=value")
           .secret("secret123")
           .and()
           .withClient("my-client-with-secret")
           .authorizedGrantTypes("client_credentials", "password")
           .authorities("ROLE_CLIENT")
           .scopes("read")
           .resourceIds(RESOURCE_ID)
           .secret("secret");
           // @formatter:on
      } 

 }
}

Note:

  1. The convenient annotation @EnableAuthorizationServer is used. The server is customized by extending the class AuthorizationServerConfigurerAdapter which provides empty method implementations for the interface AuthorizationServerConfigurer. See the javadoc here for more information.
  2. By default, the authorization server does not secure the authorization end point (/oauth/authorize). The configure method here injects the Spring Security authentication manager (set up in @EnableWebSecurity as in normal Spring Security)
  3. The configure method here setup the clients that can access the server. An in memory client detail service is used here for demo purpose.

Resource Server

The codes to configure a resource server are shown below

 @RequestMapping("/") //[1]
 public String home() {
      return "Hello World";
 }

 @Configuration
 @EnableResourceServer // [2]
 protected static class ResourceServer extends ResourceServerConfigurerAdapter {

      @Override // [3]
      public void configure(HttpSecurity http) throws Exception {
           // @formatter:off
           http
           // Just for laughs, apply OAuth protection to only 2 resources
           .requestMatchers().antMatchers("/","/admin/beans").and()
           .authorizeRequests()
           .anyRequest().access("#oauth2.hasScope('read')"); //[4]
           // @formatter:on
      }

      @Override
      public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
           resources.resourceId(RESOURCE_ID);
      }

 }

Note:

  1. For testing purpose, a resource end point is included here
  2. Like the Authorization Server, the convenient annotation @EnableResourceServer is used with a bean that extends ResourceServerConfigurerAdapter. See javadoc here for more details
  3. The configure method shows how to setup resources for OAuth2 protection.
  4. Spring Security’s expression based support is used here, i.e. #autho2.hasScope(). An expression handler is registered by default by @EnableResourceServer.

Web Server Client

Now with the OAuth2 servers setup, we can demonstrate how a web server client can access protected resource on behalf of the end user via OAuth2. It consists of the following sequence of interactions:

  1. Client redirects user to the authorization server. User login and approve client access to the resource
  2. Authorization server redirects back to client with the access code
  3. Client exchange the access code with an access token from the authorization server
  4. Client uses the access token to get resource from  the resource server

I won’t have a client web server implemented here but will use a chrome rest client plugin to issue the requests to the oauth2 servers. You may use curl to send the equivalent requests.

Also, for the following to work, you will need to setup normal Spring Security and have a login page so that the end user can login with his credential at the oauth2 server so that he can approve the client for accessing the resource on his behalf. For example, as shown in the codes here.

1: Client redirects user to the authorization server. User login and approve client access to the resource

The client redirects the user to the following URL:

http://localhost:8080/oauth/authorize?
     response_type=code
     &client_id=client-with-registered-redirect
     &redirect_url=http://client_host?key=value
     &scope=read

Running the above on your browser should redirect it to the oauth2 server’s login page. Once the user enters and submits his username and password, The OAuth approval page should display as below. I will need to work out how to customize this page later…

blogOauth2Approve

2: Authorization server redirects back to client with the access code

When the user clicks “Approve”, the authorization server will redirect back to the client url as defined in the redirect_url parameter of the original request, together with an authorization code, i.e.

http://client_host/?key=value&code=3X42jv

Since we don’t have a client server implemented,  the above will cause browser error. But we do now has the authorization code from the authorization server.

3: Client exchange the access code with an access token from the authorization server

Now the client has to exchange the access code with the authorization server for an access token by the following:

POST http://localhost:8080/oauth/token
Header: Authorization: Basic Y2xpZW50LXdpdGgtcmVnaXN0ZXJlZC1yZWRpcmVjdDpzZWNyZXQxMjM=
Payload: grant_type=authorization_code&code=3X42jv

Note that base authorization is set up by default with the @EnableAuthroizationServer annotation for the token endpoint. The string “Y2xp…M=” is the Base64 encoded text of the client’s id and password of the form <client_id>:<client_secret>, i.e.  client-with-registered-redirect:secret123. Ignoring this header will result in the oauth2 server returning an “Full authentication is required to access this resource” error. 

The authorization server should return something like below:

{
     access_token: "cd515d9d-56b1-4ef6-ae99-317d8975f292     token_type: "bearer     expires_in: 43199 
     scope: "read"
}

4: Client uses the access token to get resource from  the resource server

With the access token, the client can now get the resource on behalf of the user. Remember we set up 2 toy resources to be protected under oauth2 when setting up the resource server? Let’s try go get hold of it

GET http://localhost:8080/ 
Header : Authorization: Bearer cd515d9d-56b1-4ef6-ae99-317d8975f292

It should return “Hello World” in the response body.

That’s it. We finally got the resource after all these interactions!

A few words on grant type

The client here uses authorization code grant type. As demonstrated above, this means the authorization code is obtained using the authorization server as an intermediate between the client and the resource owner. Note the resource onwer’s credential is never shared with the client. Also, the access token is passed directly from the authorization server to the ciient without going through resource owner’s user-agent, adding a level of security.

You may notice the authorization server config also includes a client my-client-with-secret with grant type client_credentials. This is intended for the client to get access token for accessing its own account. For example:

POST http://localhost:8080/oauth/token
Header: Authorization: Basic bXktY2xpZW50LXdpdGgtc2VjcmV0OnNlY3JldA==
Payload: grant_type=client_credentials

Another interesting grant type is implicit, which is intended for client-side (e.g. browse) client.

Wrap Up…for now

That’s it for now. OAuth2 is a flexible protocol and this article only describe a rather simple but hopefully typical use of it in securing web resources. Also, most of Spring Security support for OAuth2 is not explored here. I wish to cover both in future posts.

Using Maven build number plugin to load code revision details

In this blog post, I will demonstrate how to use Maven build number plugin to get build number and version details from your source code repository for use in Spring web applications. I use this technique for a number of web apps I develop to register which version of the codes (i.e. tag) the systems are running on to help operation support and debugging.

Project configuration

I have the following project setup:

  1. Maven 3
  2. Subversion as source code repository
  3. Eclipse IDE with m2e plugin

Getting build number from subversion

1. Add Maven plugin buildnumber-maven-plugin to pom.xml file

First add the following to your pom file:

<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>buildnumber-maven-plugin</artifactId>
 <version>1.0</version>
 <executions>
      <execution>
           <phase>validate</phase>
           <goals>
                <goal>create</goal>
           </goals>
      </execution>
 </executions>
 <configuration>
      <doCheck>false</doCheck>
      <doUpdate>false</doUpdate>
      <providerImplementations>
          <svn>javasvn</svn>
      </providerImplementations>
 </configuration>
 <dependencies>
      <dependency>
           <groupId>com.google.code.maven-scm-provider-svnjava</groupId>
           <artifactId>maven-scm-provider-svnjava</artifactId>
           <version>2.0.2</version>
      </dependency>
      <dependency>
           <groupId>org.tmatesoft.svnkit</groupId>
           <artifactId>svnkit</artifactId>
           <version>1.8.6</version>
      </dependency>
 </dependencies>
</plugin>

The above plugin config adds the build number plugin to the build lifecycle. Note the use of the javasvn provider to connect to SVN.

2. Add build property placeholders

The build number plugin is now run every time you build the project and will make build number (e.g. SVN revision number) available to Maven. The next step is to include a properties file so the values can be passed into the web app via Spring. For example, create a build.properties file (e.g. in  src/main/resources) as below and add it to the files to be loaded by Spring property placeholder configurer:

build.properties:
build.version=${version}  # Maven version
build.revision=${buildNumber} # Source code revision number 
build.timestamp=${timestamp} # long value of check in time

Running build should then produce the following files with the values replaced with real ones from subversion, e.g.

build.properties:
build.version=1.2.3
build.revision=9876
build.timestamp=12345459

3. Using build number in web app

Now you can use the build number in your web app. For example, in a Spring MVC controller interceptor to inject the values to the incoming http request for display in the web page footer.

public class PageRequestInterceptor extends HandlerInterceptorAdapter {

@Value(“${build.version}”)
private String buildVersion;

@Value(“${build.revision}”)
private String buildRevision;

private DateTime buildTimestamp;

@Value(“${build.timestamp}”)
public void setBuildTimestamp(String timestamp) {
buildTimestamp = new DateTime(Long.parseLong(timestamp));
}

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

request.setAttribute(“buildVersion”, buildVersion);
request.setAttribute(“buildRevision”, buildRevision);
request.setAttribute(“buildDateTime”, buildTimestamp);

4. Fix up Eclipse m2e plugin lifecycle mapping

If you are using Eclipse, you also need to update the Maven plugin lifecycle mapping to enable the build number plugin. Otherwise, Eclipse auto build will overwrite the resolved build properties file created by the build number plugin, e.g. in /target/classes, with the one in your source path. Add the below in the pom file as child to the <build> tag:

<pluginManagement>
 <plugins>
 <!-- This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. -->
      <plugin>
           <groupId>org.eclipse.m2e</groupId>
           <artifactId>lifecycle-mapping</artifactId>
           <version>1.0.0</version>
           <configuration>
                <lifecycleMappingMetadata>
                     <pluginExecutions>
                        <pluginExecution>
                            <pluginExecutionFilter>
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>buildnumber-maven-plugin</artifactId>
                            <versionRange>[1.0,)</versionRange>
                            <goals>
                                <goal>create</goal>
                            </goals>
                            </pluginExecutionFilter>
                            <action>
                                <execute>
                                  <runOnIncremental>true</runOnIncremental>
                                </execute>
                            </action>
                       </pluginExecution>
                </pluginExecutions>
             </lifecycleMappingMetadata>
          </configuration>
      </plugin>
   </plugins>
 </pluginManagement>

You can verify the above is working by looking at the Project Maven lifecycle properties in Eclipse. RIght click on the project, the select Properties->Maven->Lifecycle Mapping

That’s it.

Setup Spring Security with Active Directory LDAP in Spring Boot Web Application

This post illustrates how to set up Spring Security in Spring Boot configuration with Active Directory LDAP for a Spring MVC web application. I will also show what needs to be configured for the embedded tomcat to accept HTTPS.

Spring Security with LDAP

To configure Spring Security in Spring Boot, add the following Configuration class to your project. Note the use of annotation @EnableWebMvcSecurity. The configuration class extends the WebSecurityConfigurerAdapter class in Spring Security. More information can be found in the Spring Security Reference here.

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

     @Value("${ldap.domain}")
     private String DOMAIN;

     @Value("${ldap.url}")
     private String URL;

     @Value("${http.port}")
     private int httpPort;

     @Value("${https.port}")
     private int httpsPort;

     @Override
     protected void configure(HttpSecurity http) throws Exception {
          /*
           * Set up your spring security config here. For example...
          */
          http.authorizeRequests().anyRequest().authenticated().and().formLogin().loginUrl("/login").permitAll();
          /*
           * Use HTTPs for ALL requests
          */
          http.requiresChannel().anyRequest().requiresSecure();
          http.portMapper().http(httpPort).mapsTo(httpsPort);
     }

     @Override
     protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
          authManagerBuilder.authenticationProvider(activeDirectoryLdapAuthenticationProvider()).userDetailsService(userDetailsService());
     }

     @Bean
     public AuthenticationManager authenticationManager() {
          return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
     }
     @Bean
     public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
          ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(DOMAIN, URL);
          provider.setConvertSubErrorCodesToExceptions(true);
          provider.setUseAuthenticationRequestCredentials(true);
          return provider;
     }
}

Add HTTPS connector for embedded Tomcat in Spring Boot

Now that Spring Security is set up, you need to update the web server to accept requests from HTTPS. To do that using the embedded Tomcat server in Spring Boot, add the following EmbeddedServletContainerCustomizer bean to the application configuration as shown below. Note I am using anonymous inner classes here instead of lambda expression as I see in other examples for Java 7 compatibility. You will need a keystore file for this to work.

@Bean
EmbeddedServletContainerCustomizer containerCustomizer (

     @Value("${https.port}") final int port, 
     @Value("${keystore.file}") Resource keystoreFile,
     @Value("${keystore.alias}") final String alias, 
     @Value("${keystore.password}") final String keystorePass,
     @Value("${keystore.type}") final String keystoreType) throws Exception {
          final String absoluteKeystoreFile = keystoreFile.getFile().getAbsolutePath();
          return new EmbeddedServletContainerCustomizer() {
               public void customize(ConfigurableEmbeddedServletContainer container) {
                    TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container;
                    tomcat.addConnectorCustomizers(new TomcatConnectorCustomizer() {
                         public void customize(Connector connector) {
                              connector.setPort(port);
                              connector.setSecure(true);
                              connector.setScheme("https");
                              Http11NioProtocol proto = (Http11NioProtocol) connector.getProtocolHandler();
                              proto.setSSLEnabled(true);
                              proto.setKeystoreFile(absoluteKeystoreFile);
                              proto.setKeyAlias(alias);
                              proto.setKeystorePass(keystorePass);
                              proto.setKeystoreType(keystoreType);
                        }
               });
           }
     };
 }

 

Getting Start with Spring Boot Configurations

Spring Boot allows development of Spring applications with minimum configuration. This is particular useful for developing microservices. This blog post will demonstrate a few things that may help in understanding how Spring Boot does its job of auto configuring a Spring application.

Auto-Configuration

So what has been configured?

The main feature of Spring Boot is its ability to automatically configuration the Spring application based on its included jar files. So the first thing you may want to look at is what have been configured for you. This can be done by running the application with the debug flag either by adding “–debug” to the command line or JVM argument “-Ddebug“. You will then see the “Auto Configuration Report” displayed in your console like below:

=========================
AUTO-CONFIGURATION REPORT
=========================

Positive matches:
—————–

AopAutoConfiguration
– @ConditionalOnClass classes found: org.springframework.context.annotation.EnableAspectJAutoProxy,org.aspectj.lang.annotation.Aspect,org.aspectj.lang.reflect.Advice (OnClassCondition)
– SpEL expression on org.springframework.boot.autoconfigure.aop.AopAutoConfiguration: ${spring.aop.auto:true} (OnExpressionCondition)

AopAutoConfiguration.JdkDynamicAutoProxyConfiguration
– SpEL expression on org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$JdkDynamicAutoProxyConfiguration: !${spring.aop.proxyTargetClass:false} (OnExpressionCondition)

// rest omitted…

Negative matches:
—————–

ActiveMQAutoConfiguration
– required @ConditionalOnClass classes not found: javax.jms.ConnectionFactory,org.apache.activemq.ActiveMQConnectionFactory (OnClassCondition)

// rest omitted…

The report should give you an indication of what have been configured for you. It depends mainly on what jar files you have included in your project dependencies.

Excluding an auto configuration

Spring Boot is designed so that you can gradually replaced the auto-configuration as needed. To exclude an auto configuration, use the exclude attribute of the @EnableAutoConfiguration annotation as below:

@Configuration
@ComponentScan
@EnableAutoConfiguration(exclude = ProcessEngineAutoConfiguration.class)
@ImportResource("classpath:/activiti.xml")
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

I am using the Activiti Spring Boot module here. Note instead of relying on its auto configuration setup, I have included the activiti.xml configuration file using the @ImportResource annotation to manually configure the process engine used by Activiti.

Configuration properties

Application properties, e.g. JDBC connection string, are to be set in the application.properties file in the classpath. Profile specific properties should be included in a separate application-<profile>.properties file located at the same directory of the application.properties file.

A list of commonly used property keys can be found in the Reference Guide (here). For example, to change the embedded web server port to 8181, add the following line the the application.properties file

### application.properties

server.port=8181

Logging

You may configure Spring Boot to use logging framework of your choice. But first, it may be useful to configure the logger properties and understand what has been configured for you. To do this, add the property of the format logging.level.<package name>=<level> to your application.properties file. For example, to display debug messages for Hibernate, add the following lilne:

logging.level.org.hibernate=DEBUG

That’s it. The above has helped me to get started with Spring Boot, to understand how auto configuration works. The Reference Guide provides a comprehensive documentation of the framework and various how-tos. There are also many tutorials and blog articles around for reference.

 

Including Field Value In Validation Message Using Spring Validation framework for JSR-303

This blog post demonstrates how to include the value of the field in the error message when using Spring Validation framework support for JSR-303. This has been made possible in Bean Validation API 1.1 with the new support of error message interpolation using EL expression. In particular, the use of the parameter “validatedValue” in the message. This post is inspired by the blog “Better Error Messages With Bean Validation 1.1 In Spring MVC Application” and will focus on the Spring Validation framework alone and demonstrate alternative ways to setup message keys using validateValue

Application Setup

I am using Spring 4 and Hibernate Validator 5.1.1 in the example here.

Spring Configuration

Nothing special with the spring configuration file (app-config.xml) here. The messageAccessor bean is used by the test class to get the validation error messages.

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns:mvc=”http://www.springframework.org/schema/mvc&#8221;
xmlns:context=”http://www.springframework.org/schema/context&#8221;
xsi:schemaLocation=”
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd”&gt;

<!– Creates the JSR-303 Validator –>
<bean id=”validator” class=”org.springframework.validation.beanvalidation.LocalValidatorFactoryBean” >
<property name=”validationMessageSource” ref=”messageSource”/>
</bean>

<bean id=”messageSource” class=”org.springframework.context.support.ResourceBundleMessageSource”>
<property name=”basenames”>
<list>
<value>messages</value>
</list>
</property>
</bean>

<bean id=”messageAccessor” class=”org.springframework.context.support.MessageSourceAccessor”>
<constructor-arg index=”0″ ref=”messageSource”/>
</bean>

</beans>

Order Class

Let say we have the following class we need to validate against. For simplicity, all the 3 fields have to be of at least 10 characters. The javax validation annotation @Size(min = 10) is hence used.


public class Order {

@Size(min = 10, message = “{Size.order.customerName.custom} ${validatedValue}”)
private String customerName;

@Size(min = 10, message =”phone number entered [${validatedValue}] is invalid. It must have at least {min} digits”)
private String phoneNumber;

@Size(min = 10)
private String address;

// getter and setter omitted here …

messages.properties file

The error messages are defined in the messages.properties file (shown below) and are used by the validator to resolve the message keys against.

javax.validation.constraints.Size.message=Invalid size for input: ${validatedValue}
Size.order.customerName.custom=Invalid customer name:

Test Class

Now we are ready to write some tests

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“/spring/app-config.xml”)
public class OrderValidationTest {

@Autowired
private Validator validator;

@Autowired
private MessageSourceAccessor messageSourceAccessor;

@Test
public void testValidateOrder() {

Order order = new Order();
order.setCustomerName(“a”);
order.setPhoneNumber(“1234″);
order.setAddress(“b”);
BindingResult errors = new BeanPropertyBindingResult(order, “order”);
validator.validate(order, errors);
assertEquals(“Invalid customer name: a”, getValidationErrorMessage(errors, “customerName”));
assertEquals(“phone number entered [1234] is invalid. It must have at least 10 digits”, getValidationErrorMessage(errors, “phoneNumber”));
assertEquals(“Invalid size for input: b”, getValidationErrorMessage(errors, “address”));

}

private String getValidationErrorMessage(BindingResult result, String field) {

if (result.hasErrors()) {
FieldError fieldError = result.getFieldError(field);
return messageSourceAccessor.getMessage(fieldError);
}
return “”;

}

}

The example classes above demonstrate 3 different ways to include the value of the invalid field in the error message, all using the validatedValue parameter supported by Bean Validation 1.1 API.

1. Update default message for the validator

First option is to modify the default message key used by the validation annotation as shown in the field address in the messages.properties file as shown below:

@Size(min = 10)
private String address;

// messages.properties

javax.validation.constraints.Size.message=Invalid size for input: ${validatedValue}

2.  Add message attribute to the validation annotation

To include validatedValue only for certain field in a class, add message attribute to the validator annotation:

@Size(min = 10, message =”phone number entered [${validatedValue}] is invalid. It must have at least {min} digits”)
private String phoneNumber;

3. Add custom message key in the message attribute

It is possible to use message key by enclosing with {} if you do not want to hard coded message text in the class:

@Size(min = 10, message = “{Size.order.customerName.custom} ${validatedValue}”)
private String customerName;

// messages.properties

Size.order.customerName.custom=Invalid customer name:

You cannot use the same key as expected by Spring, i.e. Size.order.customerName. Note also you cannot just add “${validatedValue}” in the text in messages.properties file.

That’s it. Hope this post helps.

Resources

  1. Hibernate Validator 5.1. documentation – See this chapter for more details on message interpolation.

Set up a full broker for Spring 4 STOMP over WebSocket messaging using ActiveMQ

Spring 4 websocket comes with a built-in “simple” broker for handling messaging in memory. In this blog, I will demonstrate how to configure Spring 4 to use a “full” broker, i.e. ActiveMQ, to support STOMP over WebSocket messaging.

1. Enable ActiveMQ for STOMP

First, we need to enable STOMP protocol support in ActiveMQ. This can be done by adding the connector in the activemq.xml file as shown below.

 <transportConnectors>
       <transportConnector name="openwire" uri="tcp://0.0.0.0:61616"/> 
       <transportConnector uri="stomp://localhost:61613"/>
 </transportConnectors>

You may also setup security as mentioned in the ActiveMQ documentation here.

2. Add reactor-tcp jar files

Add to following dependencies to the pom.xml file:

 <!-- Reactor for websocket relay to MQ-->
 <dependency>
      <groupId>org.projectreactor</groupId>
      <artifactId>reactor-core</artifactId>
      <version>1.0.0.RELEASE</version>
 </dependency>
 <dependency>
      <groupId>org.projectreactor</groupId>
      <artifactId>reactor-tcp</artifactId>
      <version>1.0.0.RELEASE</version>
 </dependency>

Or download the jar files reactor-core-1.0.0.RELEASE.jar and reactor-tcp-1.0.0.RELEASE.jar into your classpath

3. Update Spring WebSocket config

Replace the simple broker config below

 <websocket:message-broker application-destination-prefix="/app">
       <websocket:stomp-endpoint path="/hello">
             <websocket:sockjs/>
       </websocket:stomp-endpoint>
       <websocket:simple-broker prefix="/topic,/queue"/>
 </websocket:message-broker>

with a full broker:

 <websocket:message-broker application-destination-prefix="/app">
       <websocket:stomp-endpoint path="/hello">
            <websocket:sockjs/>
       </websocket:stomp-endpoint>
       <websocket:stomp-broker-relay prefix="/topic,/queue"
           relay-host="localhost" relay-port="61613"
           heartbeat-send-interval="20000" heartbeat-receive-interval="20000"/>
 </websocket:message-broker>

If you setup security in ActiveMQ, you will also need to include the attributes client-login, client-passcode, system-login and system-passcode for connecting to  the broker on behalf of the client and the application respectively. By default, they are set as “guest”

Putting in altogether

That’s it. Now to test it out. first fire off ActiveMQ, you should see in the logger messages something like this:

INFO | Listening for connections at: stomp://messageserver:61613
INFO | Connector stomp://localhost:61613 Started

Now start the web server, I am using jetty 9. You should see the following logger message from reactor-tcp:

INFO : 12 Apr 2014 10:47:13,023 (reactor-tcp-io-3) reactor.tcp.netty.NettyTcpClient - CONNECT: [id: 0x71a8bfb1, /127.0.0.1:49617 =>       localhost/127.0.0.1:61613]
 ...
[INFO] Started Jetty Server

Now we are ready to send some messages to the full broker. I use the hello world application in my previous blog to send a message to the topic “greetings”. You should then see the topic created in the ActiveMQ admin console, e.g. http://localhost:8161/admin/topics.jsp.