有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

CXF中的java格式XML输出?

我知道在使用Marshaller时如何打开格式。但是我正在使用ApacheCXF(JAX-RS)并返回类似return Response.ok(entity).build();的响应

我还没有找到任何设置输出格式的选项。我怎么做


共 (2) 个答案

  1. # 1 楼答案

    您可以实现一个MessageBodyWriter。这是一种JAX-RS机制,允许您重写对象如何编组为XML

    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_FORMATTED_OUTPUT, true);
                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;
        }
    
    }
    

    了解更多信息

    下面是一个完整示例的链接,其中MessageBodyWriter被用作JAX-RS服务的一部分

  2. # 2 楼答案

    首先,获取XML格式化输出的方法是在封送器上设置正确的属性(在使用CXF时通常是JAXB,这是可以的,因为JAXB做了一项可信的工作)。也就是说,在某个地方你会有这样的东西:

    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    

    问题是,您不一定要格式化all输出;它增加了相当多的开销。幸运的是,您已经在生成一个显式的Response,因此我们可以使用它的更多功能:

    Marshaller marshaller = JAXBContext.newInstance(entity.getClass()).createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    StringWriter sw = new StringWriter();
    marshaller.marshal(entity, sw);
    
    return Response.ok(sw.toString(), MediaType.APPLICATION_XML_TYPE).build();
    

    另一种方法在this JIRA issue中提到(它本身是封闭的,但这对您来说不是什么问题):

    The workaround is to register a custom output handler which can check whatever custom query is used to request the optional indentation:

    http://svn.apache.org/repos/asf/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/FormatResponseHandler.java

    JAXBElementProvider and JSONProvider are driven by the JAXB Marshaller so by default they check a Marshaller.JAXB_FORMATTED_OUTPUT property on the current message.

    这导致了如下代码:

    public class FormattedJAXBInterceptor extends AbstractPhaseInterceptor<Message> {
        public FormattedJAXBInterceptor() {
            super(Phase.PRE_STREAM);
        }
    
        public void handleMessage(Message message) {
            message.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        }
    
        public void handleFault(Message message) {
            message.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        }
    }
    

    CXF站点discusses registration of interceptors