繁体   English   中英

JAXB:如果没有@XmlJavaTypeAdapter,是不是可以使用XmlAdapter?

[英]JAXB: Isn't it possible to use an XmlAdapter without @XmlJavaTypeAdapter?

我不能将一堆XmlAdapter注册到Marshaller | Unmarshaller所以我不需要在每个@XmlJavaTypeAdapter上指定@XmlJavaTypeAdapter ,其类型本身不支持JAXB?

我觉得有点多余

顺便说一句, someMarshaller.setAdapter(...)似乎没有做任何事情。

这是一个非常好的问题!

简短的回答是, ,在marshaller / unmarshaller上使用setAdapter并不意味着您不必使用@XmlJavaTypeAdapter

让我用一个假设的(但有效的!)场景来解释这一点。

在Web应用程序中考虑,以xml的形式获取具有以下模式的事件:

<xs:element name="event" >
    <xs:complexType>
        <xs:sequence>
           <!-- Avoiding other elements for concentrating on our adapter -->
            <xs:element name="performedBy" type="xs:string" />   
        </xs:sequence> 
    </xs:complexType>  
</xs:element>

相当于此,您的模型将如下所示:

@XmlRootElement(name="event")
@XmlType(name="")
public class Event {

     @XmlElement(required=true)
     protected String performedBy;
}

现在,应用程序已经有一个名为User的bean,它维护有关用户的详细信息。

public class User {

    private String id;
    private String firstName;
    private String lastName;

    ..
}

请注意,您的JAXB上下文不知道此User 为简单起见,我们将User作为POJO,但它可以是任何Valid Java Class。

应用程序架构师想要的是EventperformedBy应该表示为User以获取完整的详细信息。

这是@XmlJavaTypeAdapter进入图片的地方

JAXBContext而知道有关performedByxs:string ,但它必须被表示为User在Java内存。

修改后的模型如下:

@XmlRootElement(name="event")
@XmlType(name="")
public class Event {

     @XmlElement(required=true)
     @XmlJavaTypeAdapter(UserAdapter.class) 
     protected User performedBy;
}

UserAdapter.java:

public class UserAdapter extends XmlAdapter<String, User> {

     public String marshal(User boundType) throws   Exception {
             ..   
     } 

     public User unmarshal(String valueType) throws Exception {
             ..
     } 
}

适配器的定义说 -

  1. BoundType是User(在Memeory表示中)
  2. ValueType是String(JAXB Context知道的数据类型)

回到你的问题 -

我觉得有点多余。

顺便说一句,someMarshaller.setAdapter(...)似乎没有做任何事情。

考虑到我们的适配器需要一个名为UserContext的类才能成功编组/解组。

public class UserAdapter extends XmlAdapter<String, User> {

     private UserContext userContext;

     public String marshal(User boundType) throws   Exception {
          return boundType.getId();
     } 

     public User unmarshal(String valueType) throws Exception {
          return userContext.findUserById(valueType);
     } 
}

现在的问题是UserAdapter将如何获取UserContext的实例? 作为一个好的设计,应该在实例化时提供它。

public class UserAdapter extends XmlAdapter<String, User> {

     private UserContext userContext;

     public UserAdapter(UserContext userContext) {
        this.userContext = userContext;  
     } 

     public String marshal(User boundType) throws   Exception {
          return boundType.getId();
     } 

     public User unmarshal(String valueType) throws Exception {
          return userContext.findUserById(valueType);
     } 
}

但是JAXB Runtime只能接受带有No-args构造函数的Adapter ..(显然JAXBContext不知道特定于应用程序的模型)

谢天谢地,有一个选项:D

您可以告诉您的unmarshaller使用给定的UserAdapter实例,而不是通过自己的实例来实现它。

public class Test {

public static void main(String... args) { 
    JAXBContext context = JAXBContext.getInstance(Event.class);
    Unmarshaller unmarshaller = context.createUnmarshaller();

      UserContext userContext = null; // fetch it from some where
      unmarshaller.setAdapter(UserAdapter.class, new UserAdapter(userContext));

      Event event = (Event) unmarshaller.unmarshal(..);
   }
}

MarshallerUnmarshaller都提供了setAdapter方法

注意:

  1. marshaller / unmarshaller上的setAdapter并不意味着您不必使用@XmlJavaTypeAdapter

     @XmlRootElement(name="event") @XmlType(name="") public class Event { @XmlElement(required=true) // @XmlJavaTypeAdapter(UserAdapter.class) protected User performedBy; } 

    如果省略这个JAXB运行时不知道用户是你的绑定类型和值类型是别的。 它将尝试按原样封送User ,并且最终会出现错误的xml(如果启用则验证失败)

  2. 虽然我们已经采用了一个场景,其中Adapter需要带参数,因此使用setAdapter方法。

    一些高级用法也在那里,即使你有默认的no-arg构造函数,但是你提供了一个适配器的实例

    愿这个适配器配置数据,编组/解组操作正在使用!

您可以使用package-info.java

这被称为“包级别”。

示例:将package-info.java放在要编组/取消编组的类所在的包中。

假设你在mypackage.adapter中有一个类mypackage.model.A和一个适配器CalendarAdapter。 在mypackage.model中声明包含以下内容的package-info.java文件:

@XmlJavaTypeAdapters({
    @XmlJavaTypeAdapter(value = CalendarAdapter.class, type = Calendar.class)
})
package mypackage.model;

import java.util.Calendar;
import mypackage.adapter.CalendarAdapter;

A类中所有类型的字段都将使用CalendarAdapter进行编组或解组。

您可以在那里找到有用的信息: http//blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM