4

我们的模型类使用@XmlJavaTypeAdapter(在类级别)进行注释。解组对于根元素和包含/嵌套(根据我们在自定义 XmlAdapter 中实现的内容)工作得很好。

到目前为止,我们对 XML 和 JSON 序列化/反序列化都很满意。但是,出现了新的需求,我不知道如何实现它?

在某些情况下,我希望能够“恢复”为默认的 JAXB 行为以进行包含:我希望忽略/覆盖类级别的 @XmlJavaTypeAdapter 注释。

我花了几个小时阅读 Blaise Doughan 的博客 ( http://blog.bdoughan.com/ ) 并搜索 StackOverflow 和 Google,但找不到优雅/实用的解决方案。

这是一个快速设置来说明我们目前拥有的内容(请注意,为简单起见,我们所有的 JPA/Hibernate/其他注释都没有列出,但它们确实存在于我们的模型类 (POJO) 中):

班主任

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
@XmlJavaTypeAdapter(XmlMasterAdapter.class)
public class Master {
    @XmlElement
    private Long masterPrimaryKey;

    @XmlElement
    private String name;
}

课程详情

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
@XmlJavaTypeAdapter(XmlDetailAdapter.class)
public class Detail {
    @XmlElement
    private Long detailPrimaryKey;

    @XmlElement
    private Master master; // reference/foreign key. No need for @XmlJavaTypeAdapter since it's defined at the class-level in Master.

    @XmlElement
    private String value;
}

当 Master 用作根元素时,XML 是这样的:

<master>
    <masterPrimaryKey>1234</masterPrimaryKey>
    <name>master name</name>
</master>

当 Master 用作包含/嵌套元素时,XML 是这样的:(感谢我们自定义的 XmlAdapter,<master> 元素通过其主键“汇总”)

<detail>
    <detailPrimaryKey>5678</detailPrimaryKey>
    <master>1234</master>
    <value>detail value</value>
</detail>

到目前为止,一切正常,我们对此感到满意。

现在,我们的新需求:

我希望收容在特定情况下以不同的方式工作。我希望 Master 上的类级 @XmlJavaTypeAdapter 在特定上下文中“暂时”被忽略/恢复/覆盖。我希望默认的 JAXB 解组器能够启动(好像包含的类上从来没有类级别的 @XmlJavaTypeAdapter)。

考虑一种数据导入情况,我们在一个有效负载中接收主数据和所有详细信息。就好像它们都是包装在一个大 DTO/transport 容器中的独立根元素一样。

这是呈现我们想要的内容的 XML:

<masterDetailImport>
    <master>
        <!-- Primary keys omitted because of the import mode -->
        <name>master name</name>
    </master>

    <details>
        <detail>
            <value>detail 1 value</value>
        </detail>

        <detail>
            <value>detail 2 value</value>
        </detail>

        <detail>
            <value>detail 3 value</value>
        </detail>
    </details>
</masterDetailImport>

类 MasterDetailImport

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class MasterDetailImport implements Serializable 
{
    @XmlElement
    @PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT
    private Master master;

    @XmlElementWrapper(name="details")
    @XmlElement
    @PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT
    private List<Detail> detail = new ArrayList<Detail>();
}

我正在寻找的是神奇的 [但不存在的] @PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT 注释,它允许我指示 JAXB 去做,就好像从未在嵌套类的类级别定义过 @XmlJavaTypeAdapter 一样。

到目前为止,我们设想 [但不喜欢] 的解决方案是:

  1. 仅当我们必须支持导入时,才为反序列化创建“镜像”DTO 对象。这种方法有很多缺点(重复代码仅用于反序列化,适配器将 DTO 内容复制到模型类中,编写/维护更多单元测试等)。

  2. 在我们希望能够导入/嵌套的所有实体上摆脱类级别的@XmlJavaTypeAdapter,并在使用嵌套/包含的所有属性上显式使用@XmlJavaTypeAdapter。我测试了这种方法并且知道它会起作用。但是,我认为它容易出错并且不如在类级别定义它那么优雅,并且能够有一个异常/特殊情况/覆盖处理告诉 JAXB 暂时表现得好像它从来不知道 @XmlJavaTypeAdapter 已在类上定义.

我的想法已经用完了...我尝试寻找 JAXB 的默认 XML 适配器但没有成功: javax.xml.bind.annotation.adapters.XmlAdapter<ValueType,BoundType> 是抽象的,继承自 Java.lang.Object .

现在,一个简单的问题:如何实现 @PLEASE_IGNORE_CLASS_LEVEL_XmlJavaTypeAdapter_AND_UNMARSHAL_AS_IF_IT_WERE_A_ROOT_ELEMENT ?

提前致谢 !

4

1 回答 1

3

XmlAdapter将始终应用 JAXB 中的一个,但您可以将逻辑放在其本身XmlAdapter中以处理您的用例。默认情况下,XmlAdapter每次使用时都会创建一个新实例,如果您是有状态的,您可以在orXmlAdapter上设置一个实例,以便使用它。您可以利用它来帮助确定是否应该应用它。MarshallerUnmarshaller

下面是我对相关问题给出的答案的链接,其中有状态XmlAdapter用于在第一次引用对象时内联对象,然后在每次引用时将其编组为链接。

于 2013-11-12T21:18:26.423 回答