Category Archives: Java

Custom Validation Annotations

Let’s say we want to task the back-end REST API application with validating the syntax of an email address provided by a new user while doing the registration. Aside from the fact that the “first level” validation should always happen on the front-end side (using for example a JavaScript solution) it is still a good idea to do a “second level” validation on the back-end (a user can have JavaScript support disabled in his/her browser or try some dirty hacks on our webpage and be sending invalid data to the server causing inconsistencies at best).

What would be a nice approach to handle server-side validation? A custom annotation – something like @ValidEmailSyntax

Here’s an idea on how to implement it:

 

1) Create an interface for the Validation Annotation:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EmailSyntaxValidator.class)
@Documented
public @interface ValidEmailSyntax {

    String message() default "Invalid email syntax";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };

}
  • As you can see from the code above, our @ValidEmailSyntax annotation can be used to annotate a field, method or another annotation
  • “Invalid email syntax” is the message returned by the server in case of failed validation

 

2) Create a EmailSyntaxValidator class that will be responsible for making decision whether the subject of validation (field, method, etc…) is valid or not:

@Component
public class EmailSyntaxValidator implements ConstraintValidator<ValidEmailSyntax, EmailAddressType> {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void initialize(ValidEmailSyntax constraintAnnotation) {
        logger.debug("EmailSyntaxValidator initialization successful");
    }

    @Override
    public boolean isValid(EmailAddressType value, ConstraintValidatorContext context) {

        return value == null || Pattern.compile(EmailStructure.PATTERN, Pattern.CASE_INSENSITIVE).matcher(value.getEmail()).matches();

    }

}

 

3) The validator class above will validate the the email represented by following EmailAddressType object:

@JsonSerialize(using = ToStringSerializer.class)
public class EmailAddressType implements Serializable {

    private static final long serialVersionUID = 1L;

    private String email;

    public EmailAddressType(String email) {
        this.email = email;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return email;
    }

}

 

4) …against the following email structure pattern (represented by an EmailStructure interface):

public interface EmailStructure {

    static final String ATOM = "[a-z0-9!#$%&'*+/=?^_`{|}~-]";
    static final String DOMAIN = "(" + ATOM + "+(\\." + ATOM + "+)+";
    static final String IP_DOMAIN = "\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\]";

    static final String PATTERN = "^" + ATOM + "+(\\." + ATOM + "+)*@" + DOMAIN + "|" + IP_DOMAIN + ")$";

}

 

5) finally this is how we will use the validation annotation in our code:

public class User {

    @ValidEmailSyntax
    private EmailAddressType email;
    ...
    //getters and setters ommited

}

 

 

Happy coding! 🙂

Tomcat, JNDI and Spring bean application configuration

While setting up a Continuous Integration environment recently i faced an issue related to application (REST API in this case) configuration not being deployment-environment independent. Namely as the code pushed to Git repository and picked up by Jenkins build server was later on automatically deployed across several server environments (DEV, INT, STAGING, PROD) it turned out that in each of those environments the API application (war archive deployed in Tomcat container) requires to be fed with a specific/different configuration (environment-specific settings).

 

This is how i managed to solve this issue:

 

1. I created the following Tomcat context entry in “conf/context.xml” file:

<Context>
    <Resource name="config/Api"
        auth="Container"
        type="com.mycompany.model.ApiConfigBean"
        factory="com.mycompany.api.jndi.CustomApiJNDIFactory"
        scheme="https"
        server="api.mycompany.com"
        port="8443"
        version="1.0"
        sso="sso.mycompany.com" />
</Context>

 

2. Created the “CustomApiJNDIFactory” class:

public class CustomApiJNDIFactory implements ObjectFactory {

    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?,?> environment) throws Exception {

        validateProperty(obj, "Invalid JNDI object reference");

        String scheme = null;
        String host = null;
        String port = null;
        String version = null;
        String sso = null;

        Reference ref = (Reference) obj;

        Enumeration props = ref.getAll();

        while (props.hasMoreElements()) {

            RefAddr addr = props.nextElement();
            String propName = addr.getType();
            String propValue = (String) addr.getContent();

            switch (propName) {
                case "scheme":
                    scheme = propValue;
                    break;
                case "host":
                    host = propValue;
                    break;
                case "port":
                    port = propValue;
                    break;
                case "version":
                    version = propValue;
                    break;
                case "sso":
                    sso = propValue;
                    break;
            }

        }

        // validate properties
        validateProperty(scheme, "Invalid or empty scheme type");
        validateProperty(host, "Invalid or empty server host name");
        validateProperty(port, "Invalid or empty port number");
        validateProperty(version, "Invalid or empty API version number");
        validateProperty(sso, "Invalid or empty SSO server name");

        //create API Configuration Bean
        return new ApiConfigBean(scheme, host, port, version, sso);

    }

    /**
     * Validate internal String properties
     *
     * @param property the property
     * @param errorMessage the error message
     * @throws javax.naming.NamingException
     */
    private void validateProperty(String property, String errorMessage) throws NamingException {

        if (property == null || property.trim().equals("")) {
            throw new NamingException(errorMessage);
        }

    }

}

 

3. Defined an jndi-lookup entry in my “spring-api-context.xml” file that will read Tomcat JNDI configuration entry and expose it as a Spring bean of name jndiApi:

<jee:jndi-lookup id="jndiApi" jndi-name="java:/comp/env/config/Api" expected-type="com.mycompany.model.ApiConfigBean" />

 

4. Created the “jndiApi” Spring bean backing pojo

public class ApiConfigBean {

    private String scheme;
    private String host;
    private String port;
    private String version;
    private String sso;

    public ApiConfigBean(String scheme, String host, String port, String version, String sso) {
        this.scheme = scheme;
        this.host = host;
        this.port = port;
        this.version = version;
        this.sso = sso;
    }

    // getters and setters ommited.

}

 

5. and finally wired-in the bean to my classes where i needed to make use of the “externalized” configuration:

@Autowired
@Qualifier("jndiApi")
private ApiConfigBean apiConfigBean;

    public void foo() {

        String host = apiConfigBean.getHost();
        ...

    }

 

 

That’s it! Have a wonderful day! 🙂

Spring localized exception handling in REST API

In today’s post i’ll share with you the way we’re handling Internationalization (i18n) and Localization (L10n) in our REST API which is based on Spring MVC (3.2.3.RELEASE).

Our front-end web client is an SPA (Single Page Application) built using AngularJS framework and occasionally it needs to handle Java exceptions messages thrown by the back-end. The way it has been implemented is that it intercepts JSON error responses, wraps them in a pre-defined web page template and displays to the user in a unified and nice way.

“Localization” of back-end related error messages happens …at the back-end level.

 

After this quick intro let’s get familiar with following two definitions:

  • Internationalization – process of designing software applications so that they can be adapted to various languages and regions without engineering changes.
  • Localization – process of adapting internationalized applications for a specific region or language by adding locale-specific components and translating text.

OK, this is how message bundles look like:

// messages.properties
exception.npe=Unrecognized error: We're sorry.
(...)

and the project view so you get a feel on how maven-managed multi-module project is structured (i use IntelliJ IDEA)

Spring REST API

 

The ‘resourceBundle’ spring bean is located in ‘spring-locale-context.xml’

<bean id="resourceBundle"
      class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
      p:basename="classpath:locale/messages"
      p:cacheSeconds="5"
      p:defaultEncoding="UTF-8" />

 

As you can see i’m using ‘ReloadableResourceBundleMessageSource‘ which i prefer over ‘ResourceBundleMessageSource‘ – here’s why (according to Spring framework spec.)

  • ResourceBundleMessageSource – MessageSource implementation that accesses resource bundles using specified basenames. This class relies on the underlying JDK’s ResourceBundle implementation, in combination with the JDK’s standard message parsing provided by MessageFormat. This MessageSource caches both the accessed ResourceBundle instances and the generated MessageFormats for each message. It also implements rendering of no-arg messages without MessageFormat, as supported by the AbstractMessageSource base class. The caching provided by this MessageSource is significantly faster than the built-in caching of the java.util.ResourceBundle class. Unfortunately, java.util.ResourceBundle caches loaded bundles forever: Reloading a bundle during VM execution is not possible. As this MessageSource relies on ResourceBundle, it faces the same limitation. Consider ReloadableResourceBundleMessageSource for an alternative that is capable of refreshing the underlying bundle files.
  • ReloadableResourceBundleMessageSource – Spring-specific MessageSource implementation that accesses resource bundles using specified basenames, participating in the Spring ApplicationContext‘s resource loading. In contrast to the JDK-based ResourceBundleMessageSource, this class uses Properties instances as its custom data structure for messages, loading them via a PropertiesPersister strategy from Spring Resource handles. This strategy is not only capable of reloading files based on timestamp changes, but also of loading properties files with a specific character encoding. It will detect XML property files as well. In contrast to ResourceBundleMessageSource, this class supports reloading of properties files through the "cacheSeconds" setting, and also through programmatically clearing the properties cache. Since application servers typically cache all files loaded from the classpath, it is necessary to store resources somewhere else (for example, in the “WEB-INF” directory of a web app). Otherwise changes of files in the classpath will not be reflected in the application. This MessageSource implementation is usually slightly faster than ResourceBundleMessageSource, which builds on ResourceBundle – in the default mode, i.e. when caching forever. With “cacheSeconds” set to 1, message lookup takes about twice as long – with the benefit that changes in individual properties files are detected with a maximum delay of 1 second. Higher “cacheSeconds” values usually do not make a significant difference.

 

Now, let’s make our resourceBundle accessible to exception handlers:

public class AbstractExceptionHandler {

    @Autowired
    private ReloadableResourceBundleMessageSource resourceBundle;

    public ReloadableResourceBundleMessageSource getResourceBundle() {
        return resourceBundle;
    }

    public void setResourceBundle(ReloadableResourceBundleMessageSource resourceBundle) {
        this.resourceBundle = resourceBundle;
    }

}

 

Create an MVC REST Controller:

@Controller
@RequestMapping(value = "/users")
public class UserController {

    @Autowired
    private UserService service;

    /**
     * Handling GET request to retrieve all {@link User}'s
     * @return Collection<User> a collection of users
     */
    @RequestMapping(method = RequestMethod.GET)
    public @ResponseBody
    Collection<User> getUsers() {
        return service.findAllUsers();
    };

}

 

…and an exception handler that will intercept (NPE in this case) exceptions thrown by the controller:

@ControllerAdvice
public class BusinessExceptionHandler extends AbstractExceptionHandler {

    @ExceptionHandler(NullPointerException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody DefaultErrorMessage handleNullPointerException() {

        String error = getResourceBundle().getMessage("exception.npe", null, Locale.getDefault());

        return new DefaultErrorMessage("RS00230", "SYSTEM_ERROR", error);

    }

}

 

As you can see above, I did two things:

  • fed the error string with exception.npe message that comes from the message bundle and used Locale.getDefault()
  • and defined a custom DefaultErrorMessage which basically is a POJO send over to the client as a JSON response which looks like this:
{
  "code" : "RS00230",
  "status" : "SYSTEM_ERROR",
  "errors" : [ "Unrecognized error: We're sorry." ]
}

 

Hope you find this brief example helpful. Cheers!

 

 

Resources: