如何指示 JAXB Marshaller 仅出于审核目的清理 base64Binary 数据?

发布于 2024-12-27 19:24:30 字数 2201 浏览 1 评论 0原文

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

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

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

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

所以我的需要是创建一个编组器(专门用于auditng),在所有情况下都会擦除二进制内容,但不会出于编组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" />

将不起作用,因为 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 插件 但这并没有真正起作用,原因与上述不起作用相同。

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

我还应该提到,为了简洁起见,我正在使用 jersey 支持 JAXB 的 JSON 序列化 但我不认为这会消除或增加我的基本问题:

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

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

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

I am working in a JAXWS/JAXB web service environment. JAXWS out of the box uses uses the JAXB to marshal/unmarshaler the web service payloads.

I also have a requirement to audit all request and response payloads.

I want a compact and concise marshaled representation of the payload for the audit (as a irrelevant side note - I am auditing using a java.util.concurrent.BlockingQueue and some consumer threads to put batches of audit data in the audit datasource).

I have binary content(mtom) included on some web service response payloads but I DO NOT want to marshal audit these because the serialized base64 would be too large.

So my need is to create a marshaller (exclusively for auditng) that in all cases will scrub binary content but then NOT scrub for the prime purpose of marshalling web service response payloads. I do XSD to Java xjc. I need to use the same XSD/JAXB namespace for both contexts/marshallers.

Java type converter:

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

is will not work because 1. I would need to unregister the adapter http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/Marshaller.html#setAdapter%28java.lang.Class,%20A%29
for the marshaller and I don't THINK I have a hook into that for JAXWS. 2. I can't be guaranteed the class name that JAXB will decide to create in order to unregister it.

I created my own XMLAdapter and used the annox jaxb plugin
but that didn't really work for the same reasons the above didn't work.

Update: I now tried manually and reflectively walking through payload(to be audited) prior to marshalling to scrub the binary data but that got to be too much pain for what it was worth.

I should also mention that for brevity of the audit I am using jersey JSON serialization supporting JAXB
but I don't think that takes away or adds to my base problem:

How can I scrub data in one marshaller/unmarshaller but not another but both whose origin is the same JAXB context?

UPDATE: Never figured out an elegate way to do this. Not really possible at this point with the frameworks as they are. UPDATE: Not true. Extending AttachmentMarshaller (I like this a lot and will use it) or creating a "need-aware" XmlAdapter would work for the audit specific marshaller as @Blaise answers below.

UPDATE: If I may take this a step further to round out my use case...I mentioned above that for brevity of the audit I'd like to do Json Serialization of the JSONJAXBContext using jersey apis, specifically using the JSONMarshaller but the interface does not define setAdapter and setAttachmentMarshaller. Coming out of JSONJAXBContext.createJSONMarshaller() is a JSONMarshallerImpl implementation which do define these this methods. I will grudgingly cast to impl so I can set my custom attachment marshaller.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

飘然心甜 2025-01-03 19:24:30

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


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

Root

下面是一个具有 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>

How can I scrub data in one marshaller/unmarshaller but not another
but both whose origin is the same JAXB context?


You could set your own implementation of AttachemntMarshaller and set it on the Marshaller that you are using for auditing.

Root

Below is a sample domain object with a byte[] property that by default will be represented as an element of type base64Binary.

package forum8914008;

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    byte[] bytes;

}

Demo

The demo code below first marshals the object to XML, and then marshals it a second time with a custom impplementation of AttachmentMarshaller set.

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);
    }

}

Output

Below is the output from running the demo code. The first XML document could grow to be quite large if the byte[] was big. The second XML document would stay the same size.

<?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>
暮年 2025-01-03 19:24:30

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


您可以使用 XmlAdapter 支持此用例。

XmlAdapter (ByteArrayAdapter)

下面的XmlAdapter用于将byte[]转换为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;
    }

}

package-info

@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;

Root

下面是一个具有 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>

How can I scrub data in one marshaller/unmarshaller but not another
but both whose origin is the same JAXB context?


You could support this use case with an XmlAdapter.

XmlAdapter (ByteArrayAdapter)

The following XmlAdapter is used to convert a byte[] to a byte[]. In its default state it will return the original byte[], it also has a audit state where it will return an empty 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;
    }

}

package-info

The @XmlJavaTypeAdapter annotation is used tp register the XmlAdapter. When used at the package level it will apply to all properties of the specified type in that package (see: 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;

Root

Below is a sample domain object with a byte[] property that by default will be represented as an element of type base64Binary.

package forum8914008;

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    byte[] bytes;

}

Demo

The demo code below first marshals the object with the default state of the ByteArrayAdapter which will return the real byte[] and the marshals the object a second time with a stateful ByteArrayAdapter set which will convert all byte[] values to an empty 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);
    }

}

Output

Below is the output from running the demo code. The XmlAdapter would apply to all mapped fields/properties of type 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文