【问题标题】:How can I instruct a JAXB Marshaller to scrub base64Binary data only for auditing?我如何指示 JAXB Marshaller 只为审计清理 base64Binary 数据?
【发布时间】:2012-01-18 16:50:33
【问题描述】:

我在 JAXWS/JAXB Web 服务环境中工作。开箱即用的 JAXWS 使用 JAXB 来编组/解组 Web 服务负载。

我还需要审核所有请求和响应负载。

我想要一个用于审计的有效负载的紧凑和简洁的编组表示(作为不相关的旁注 - 我正在使用 java.util.concurrent.BlockingQueue 和一些消费者线程进行审计,以将成批的审计数据放入审计数据源中)。

我在一些 Web 服务响应负载中包含二进制内容 (mtom),但我不想编组审核这些内容,因为序列化的 base64 会太大。

所以我需要创建一个编组器(专门用于审计),它在所有情况下都会清理二进制内容,但不会为了编组 Web 服务响应有效负载的主要目的而清理。我做 XSD 到 Java xjc。我需要为两个上下文/编组器使用相同的 XSD/JAXB 命名空间。

Java 类型转换器:

<jxb:javaType name=""
        parseMethod="com.xxx.xxx.ws.converter.XXXLongConverter.parseXXXLong" 
            printMethod="com.xxx.xxx.ws.converter.XXXLongConverter.printXXXLong" />

is 不起作用,因为 1. 我需要注销适配器 http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/Marshaller.html#setAdapter%28java.lang.Class,%20A%29 对于编组器,我不认为我对 JAXWS 有兴趣。 2. 我无法保证 JAXB 将决定创建的类名以便注销它。

我创建了自己的 XMLAdapter 并使用了 annox jaxb 插件 但这并没有真正起作用,原因与上述不起作用的原因相同。

更新:我现在尝试在编组清理二进制数据之前手动和反思地遍历有效负载(待审核),但这对于它的价值来说太痛苦了。

我还应该提到,为了简化审核,我使用的是球衣 JSON serialization supporting JAXB 但我认为这不会消除或增加我的基本问题:

如何清理一个编组器/解组器中的数据,而不是另一个,但两者的来源都是相同的 JAXB 上下文?

更新:从来没有想出一个优雅的方法来做到这一点。在这一点上,使用框架实际上是不可能的。 更新:不正确。扩展 AttachmentMarshaller(我非常喜欢并将使用它)或创建“需要感知”的 XmlAdapter 将适用于审计特定的编组器,如下面的@Blaise 回答。

更新:如果我可以更进一步完善我的用例...我在上面提到,为了简化审核,我想使用 jersey api 对 JSONJAXBContext 进行 Json 序列化,特别是使用JSONMarshaller 但接口没有定义 setAdapter 和 setAttachmentMarshaller。从JSONJAXBContext.createJSONMarshaller() 出来的是一个JSONMarshallerImpl 实现,它确实定义了这些方法。我将不情愿地转换为 impl,以便我可以设置我的自定义附件编组器。

【问题讨论】:

    标签: web-services jaxb jax-ws jersey marshalling


    【解决方案1】:

    如何清理一个编组器/解组器中的数据,而不是另一个 但是两者的起源是相同的 JAXB 上下文?


    您可以设置自己的 AttachemntMarshaller 实现并将其设置在您用于审计的 Marshaller 上。

    下面是具有byte[] 属性的示例域对象,默认情况下将表示为base64Binary 类型的元素。

    package forum8914008;
    
    import javax.xml.bind.annotation.*;
    
    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Root {
    
        byte[] bytes;
    
    }
    

    演示

    下面的演示代码首先将对象编组为 XML,然后使用自定义实现 AttachmentMarshaller 集对其进行第二次编组。

    package forum8914008;
    
    import javax.activation.DataHandler;
    import javax.xml.bind.*;
    import javax.xml.bind.attachment.AttachmentMarshaller;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Root.class);
    
            Root root = new Root();
            root.bytes = "Hello World".getBytes();
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(root, System.out);
    
            marshaller.setAttachmentMarshaller(new AttachmentMarshaller() {
    
                @Override
                public boolean isXOPPackage() {
                   return true;
                }
    
                @Override
                public String addMtomAttachment(DataHandler arg0, String arg1,
                        String arg2) {
                    return "fake";
                }
    
                @Override
                public String addMtomAttachment(byte[] arg0, int arg1, int arg2,
                        String arg3, String arg4, String arg5) {
                    return "fake";
                }
    
                @Override
                public String addSwaRefAttachment(DataHandler arg0) {
                    return "fake";
                }
    
            });
            marshaller.marshal(root, System.out);
        }
    
    }
    

    输出

    下面是运行演示代码的输出。如果 byte[] 很大,那么第一个 XML 文档可能会变得很大。第二个 XML 文档的大小将保持不变。

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <root>
        <bytes>SGVsbG8gV29ybGQ=</bytes>
    </root>
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <root>
        <bytes>
            <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="fake"/>
        </bytes>
    </root>
    

    【讨论】:

      【解决方案2】:

      如何清理一个编组器/解组器中的数据,而不是另一个 但是两者的起源是相同的 JAXB 上下文?


      您可以通过 XmlAdapter 支持此用例。

      XmlAdapter (ByteArrayAdapter)

      以下XmlAdapter 用于将byte[] 转换为byte[]。在其默认状态下,它将返回原始byte[],它还有一个审核状态,它将返回一个空字节[]。

      package forum8914008;
      
      import javax.xml.bind.annotation.adapters.XmlAdapter;
      
      public class ByteArrayAdapter extends XmlAdapter<byte[], byte[]> {
      
          private boolean audit;
      
          public ByteArrayAdapter() {
              this(false);
          }
      
          public ByteArrayAdapter(boolean audit) {
              this.audit = audit;
          }
      
          @Override
          public byte[] marshal(byte[] bytes) throws Exception {
              if(audit) {
                  return new byte[0];
              }
              return bytes;
          }
      
          @Override
          public byte[] unmarshal(byte[] bytes) throws Exception {
              return bytes;
          }
      
      }
      

      包裹信息

      @XmlJavaTypeAdapter 注释用于注册XmlAdapter。在包级别使用时,它将应用于该包中指定类型的所有属性(请参阅:http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html)。

      @XmlJavaTypeAdapter(value=ByteArrayAdapter.class, type=byte[].class)
      package forum8914008;
      
      import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
      

      下面是一个带有 byte[] 属性的示例域对象,默认情况下将表示为 base64Binary 类型的元素。

      package forum8914008;
      
      import javax.xml.bind.annotation.*;
      
      @XmlRootElement
      @XmlAccessorType(XmlAccessType.FIELD)
      public class Root {
      
          byte[] bytes;
      
      }
      

      演示

      下面的演示代码首先使用ByteArrayAdapter 的默认状态封送对象,这将返回真实的byte[],然后使用有状态的ByteArrayAdapter 设置第二次封送对象,这将转换所有byte[]值为空的byte[]

      package forum8914008;
      
      import javax.xml.bind.*;
      
      public class Demo {
      
          public static void main(String[] args) throws Exception {
              JAXBContext jc = JAXBContext.newInstance(Root.class);
      
              Root root = new Root();
              root.bytes = "Hello World".getBytes();
      
              Marshaller marshaller = jc.createMarshaller();
              marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
              marshaller.marshal(root, System.out);
      
              marshaller.setAdapter(new ByteArrayAdapter(true));
              marshaller.marshal(root, System.out);
          }
      
      }
      

      输出

      下面是运行演示代码的输出。 XmlAdapter 将应用于 byte[] 类型的所有映射字段/属性。

      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <root>
          <bytes>SGVsbG8gV29ybGQ=</bytes>
      </root>
      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <root>
          <bytes></bytes>
      </root>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-14
        • 1970-01-01
        • 2018-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-25
        相关资源
        最近更新 更多