JAXB:难道不能在没有@XmlJavaTypeAdapter的情况下使用XmlAdapter吗?
我不能注册一堆s来|这样我就不需要在每个文件上指定,其类型本身不受 JAXB 支持?XmlAdapter
Marshaller
Unmarshaller
@XmlJavaTypeAdapter
我发现它有些多余。
顺便说一句,似乎没有做任何事情。someMarshaller.setAdapter(...)
我不能注册一堆s来|这样我就不需要在每个文件上指定,其类型本身不受 JAXB 支持?XmlAdapter
Marshaller
Unmarshaller
@XmlJavaTypeAdapter
我发现它有些多余。
顺便说一句,似乎没有做任何事情。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;
}
现在,应用程序已经有一个名为Bean的bean,它维护有关用户的详细信息。User
public class User {
private String id;
private String firstName;
private String lastName;
..
}
请注意,JAXB 上下文不知道这一点。为简单起见,我们将 User 作为 POJO,但它可以是任何有效的 Java 类。User
应用程序架构师想要的是,应该表示为获得完整的细节。Event
performedBy
User
这是@XmlJavaTypeAdapter进入画面的地方
JAXBContext 知道 as,但它必须在 Java 中的内存中表示。performedBy
xs:string
User
修改后的模型如下所示:
@XmlRootElement(name="event")
@XmlType(name="")
public class Event {
@XmlElement(required=true)
@XmlJavaTypeAdapter(UserAdapter.class)
protected User performedBy;
}
用户适配器.java:
public class UserAdapter extends XmlAdapter<String, User> {
public String marshal(User boundType) throws Exception {
..
}
public User unmarshal(String valueType) throws Exception {
..
}
}
适配器的定义是 -
回到你的问题 -
我发现它有些多余。
顺便说一句,一些Marshaller.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的instace?作为一个好的设计,人们应该总是在实例化时提供它。
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 运行时只能接受带有 No-args 构造函数的适配器。(显然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(..);
}
}
setAdapter
方法在两者上都可用Marshaller
& Unmarshaller
注意:
setAdapter
在 marshaller / unmarshaller 上并不意味着您不必使用 .@XmlJavaTypeAdapter
@XmlRootElement(name="event")
@XmlType(name="")
public class Event {
@XmlElement(required=true)
// @XmlJavaTypeAdapter(UserAdapter.class)
protected User performedBy;
}
如果你省略了这个 JAXB 运行时,就不知道用户是你的绑定类型,值类型是别的什么。它将尝试按原样进行封送处理,您最终将拥有错误的xml(如果启用,则验证失败)User
虽然我们采用了一个场景,其中适配器需要与参数一起使用,因此使用方法。setAdapter
一些可用的用法也在那里,即使您有默认的no-arg构造函数,但您提供了适配器的实例
可能此适配器配置了数据,哪个封送/取消元帅操作正在使用!
您可以使用包信息.java
这称为“包级别”。
示例:将一个包信息.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 中所有“日历”类型的字段都将使用“日历适配器”进行编组或取消编组。
你可以在那里找到有用的信息:http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html