JAXB/Jersey - How To Specify “schemaLocation”

2020-04-15 20:57发布

I am using Jersey to create a restful web-service marshals XML.

How would I set the xsi:schemaLocation?

This answer show how to set the Marshaller.JAXB_SCHEMA_LOCATION directly on the Marshaller.

The trouble I am having is that Jersey is marshaling the Java objects into XML. How do I tell Jersey what the schema location is?

标签: jaxb jersey
1条回答
可以哭但决不认输i
2楼-- · 2020-04-15 21:25

You could create a MessageBodyWriter for this use case. Through the ContextResolver mechanism you can get the JAXBContext associated with your domain model. Then you can get a Marshaller from the JAXBContext and set the JAXB_SCHEMA_LOCATION on it and do the marshal.

package org.example;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;

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

@Provider
@Produces(MediaType.APPLICATION_XML)
public class FormattingWriter implements MessageBodyWriter<Object>{

    @Context
    protected Providers providers;

    public boolean isWriteable(Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    public void writeTo(Object object, Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType,
        MultivaluedMap<String, Object> httpHeaders,
        OutputStream entityStream) throws IOException,
        WebApplicationException {
        try {
            ContextResolver<JAXBContext> resolver 
                = providers.getContextResolver(JAXBContext.class, mediaType);
            JAXBContext jaxbContext;
            if(null == resolver || null == (jaxbContext = resolver.getContext(type))) {
                jaxbContext = JAXBContext.newInstance(type);
            }
            Marshaller m = jaxbContext.createMarshaller();
            m.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "foo bar");
            m.marshal(object, entityStream);
        } catch(JAXBException jaxbException) {
            throw new WebApplicationException(jaxbException);
        }
    }

    public long getSize(Object t, Class<?> type, Type genericType,
        Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

}

UPDATE

One other question. What is the connection between the my rest resource and the provider?

You still implement your resource the same way. The MessageBodyWriter mechanism is just a way to override how the writing to XML will be done. The @Provider annotation is a signal to the JAX-RS application to have this class automatically registered.

My resource class would return a Foo object. I take it I should be implementing a MessageBodyWriter<Foo>?

You could implement it as MessageBodyWriter<Foo> if you only want it applied to the Foo class. If you want it to apply to more than just Foo you can implement to the isWriteable method to return true for the appropriate classes.

查看更多
登录 后发表回答