0

I'm creating a Spring 4 REST application, using MappingJackson2XmlHttpMessageConverter to convert incoming XML requests to domain objects. Is there any way to apply XSD validation in that process? If not, I think my fallback is to just make the @RequestBody a String, parse and validate it, and then convert it to the domain object. Is there a better approach?

Xstian
  • 8,184
  • 10
  • 42
  • 72
sockmonk
  • 4,195
  • 24
  • 40

1 Answers1

0

One approach to this may be to write a custom HttpMessageConverter<T> that checks XSD validation (look here for a way to validate XML with XSD) before returning the object.

Suppose that you have the following method in your Controller class:

@RequestMapping(value = "/")
public CustomObject getCustomObject(@RequestParam(value = "id") String id){
    return new CustomObject();
}

Then your converter may look like this:

public class CustomObjectConverter implements HttpMessageConverter<CustomObject> {
    // a real message converter that will respond to ancillary methods and do the actual work
    protected HttpMessageConverter<Object> delegateConverter;

    public CustomObjectConverter (HttpMessageConverter<Object> delegate) {
        super(delegate, personService);
        super.delegateConverter = delegate;
        this.employeePhotoBaseUrl = employeePhotoBaseUrl;
    }

    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return delegateConverter.canRead(clazz, mediaType) && CustomObject.class.equals(clazz);
    }

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return delegateConverter.canWrite(clazz, mediaType) && CustomObject.class.equals(clazz);
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return delegateConverter.getSupportedMediaTypes();
    }

    @Override
    public CustomObject read(Class<? extends CustomObject> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return (CustomObject) delegateConverter.read(clazz, inputMessage);
    }

    @Override
    public void write(CustomObject t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        if(validationOK)
            delegateConverter.write(t, contentType, outputMessage);
        else
            // You may implement a custom exception handler to return a proper HTTP error code
            throw new YourCustomException();
    }
}

Remember to configure your new converter. I do this in my configuration class:

@Configuration
@EnableWebMvc
public class RestConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // initialize your MappingJackson2XmlHttpMessageConverter
        MappingJackson2XmlHttpMessageConverter xmlMessageConverter = xmlMessageConverter();

        //Here we add our custom-configured HttpMessageConverters
        converters.add(new CustomObjectConverter(xmlMessageConverter));
        super.configureMessageConverters(converters);
    }
}
Community
  • 1
  • 1
Marco Ferrari
  • 4,914
  • 5
  • 33
  • 53