[英]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。
应用程序架构师想要的是Event
的performedBy
应该表示为User
以获取完整的详细信息。
这是@XmlJavaTypeAdapter进入图片的地方
JAXBContext而知道有关performedBy
为xs: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 {
..
}
}
适配器的定义说 -
回到你的问题 -
我觉得有点多余。
顺便说一句,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(..);
}
}
Marshaller
和Unmarshaller
都提供了setAdapter
方法
注意:
marshaller / unmarshaller上的setAdapter
并不意味着您不必使用@XmlJavaTypeAdapter
。
@XmlRootElement(name="event") @XmlType(name="") public class Event { @XmlElement(required=true) // @XmlJavaTypeAdapter(UserAdapter.class) protected User performedBy; }
如果省略这个JAXB运行时不知道用户是你的绑定类型和值类型是别的。 它将尝试按原样封送User
,并且最终会出现错误的xml(如果启用则验证失败)
虽然我们已经采用了一个场景,其中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.