Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Practical validation of JAXB data with JAX-RS?

We are using JAX-RS with some fairly basic POJO entities and have a number of @GET and @POST annotated methods that @Produce and @Consume MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML. Nothing spectacular.

Question I have is how best should I validate the data coming in?

We do not have an XML Schema although I could generate one. I would need to hook this in somehow which doesn't look terribly appealing and I have not found a concise example yet.

We could use "bean validation" but I am again unsure how I might hook this up and invoke it.

Finally (I think) we could for example add some isValidForXXX() methods to the entity POJOs and call them whenever we have an instance handed in to us.

Recommendations anyone?

like image 644
jmkgreen Avatar asked May 01 '12 13:05

jmkgreen


People also ask

Which of the following is type of bean validation method provided in Jersey?

Validation is the process of verifying that some data obeys one or more pre-defined constraints. It is, of course, a very common use case in most applications. The Java Bean Validation framework (JSR-380) has become the de-facto standard for handling this kind of operations in Java.

Which API is used for generating XML as a response in Jax RS?

Your JAX-RS application can use the JAXB objects to manipulate XML data. JAXB objects can be used as request entity parameters and response entities. The JAX-RS runtime environment includes standard MessageBodyReader and MessageBodyWriter provider interfaces for reading and writing JAXB objects as entities.

What is JAXB marshalling and Unmarshalling?

JAXB definitionsMarshalling is the process of transforming Java objects into XML documents. Unmarshalling is the process of reading XML documents into Java objects. The JAXBContext class provides the client's entry point to the JAXB API. It provides API for marshalling, unmarshalling and validating.

What is the use of JAXB in Web service?

Java Architecture for XML Binding (JAXB) is an XML-to-Java binding technology that simplifies the development of web services by enabling transformations between schema and Java objects and between XML instance documents and Java object instances.


2 Answers

If you have an XML schema then you could use JAXB validation inside a MessageBodyReader. For a concrete example see my answer to a similar question.

  • Validate JAXBElement in JPA/JAX-RS Web Service

ValidatingReader

Below is a bare bones implementation of MessageBodyReader that does four things: 1) Create a JAXBContext, 2) Create an instance of Schema, 3) Sets the schema on the Unmarshaller 4) Unmarshals the InputStream.

package org.example;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.URL;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.ext.*;
import javax.xml.XMLConstants;
import javax.xml.bind.*;
import javax.xml.validation.*;

@Provider
@Consumes("application/xml")
public class ValidatingReader implements MessageBodyReader<Customer> {

    @Context
    protected Providers providers;

    private Schema schema;
    private JAXBContext jaxbContext;

    public ValidatingReader() {
        try {
            JAXBContext jc = JAXBContext.newInstance(Customer.class);
            SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            URL schemaURL = null; // URL for your XML schema
            schema = sf.newSchema(schemaURL);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    public boolean isReadable(Class<?> arg0, Type arg1, Annotation[] arg2, MediaType arg3) {
        return arg0 == Customer.class;
    }

    public Customer readFrom(Class<Customer> arg0, Type arg1, Annotation[] arg2, MediaType arg3, MultivaluedMap<String, String> arg4, InputStream arg5)
            throws IOException, WebApplicationException {
        try {
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            unmarshaller.setSchema(schema);
            return (Customer) unmarshaller.unmarshal(arg5);
        } catch(JAXBException e) {
            throw new RuntimeException(e);
        }
    }

}
like image 71
bdoughan Avatar answered Oct 12 '22 20:10

bdoughan


Was looking to accomplish the same thing as the original poster. Since there seemed to be a desire to avoid a MessageBodyReader I thought I would share this solution, which just uses the HttpServletRequest as a parameter and then uses the getInputStream method to directly work with the data.

@POST
@Path("/myPath")
@Consumes(MediaType.APPLICATION_XML)
public Response saveCustomerInteraction(@Context HttpServletRequest httpRequest) {

    Response response = null;
    try {
        CustomerInteraction ci = this.handleCustomerInteractionRequest(httpRequest);
        if (ci!=null){
            // save your data or whatever your app does
        }
        else {
            response = Response.status(Status.BAD_REQUEST).entity("invalid XML").build();               
        }
    }
    catch(Exception e){
        log.error(e.getMessage(),e);
        response = Response.serverError().entity(e.getMessage()).build();
    }
    return response;
}

The handleCustomerInteractionRequest method would then handle the servlet stream and validate the XML

protected CustomerInteraction handleCustomerInteractionRequest(HttpServletRequest request){

    CustomerInteraction ci = null;
    try {
        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = sf.newSchema(schemaUrl);
        JAXBContext jaxbContext = JAXBContext.newInstance(CustomerInteraction.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setSchema(schema);
        ci = (CustomerInteraction) unmarshaller.unmarshal(request.getInputStream());    
    }
    catch (Exception e){
        // log error and return a null (or whatever you want to do with the error)
    }

    return ci;
} 
like image 26
Mike Barlotta Avatar answered Oct 12 '22 20:10

Mike Barlotta