我无法向XmlAdapter
| Marshaller
注册一堆Unmarshaller
,因此我不需要在每个字段上指定@XmlJavaTypeAdapter
,其类型为原生JAXB支持吗?
我发现它有些redundant。
BTW,someMarshaller.setAdapter(...)
似乎没有做任何事情。
答案 0 :(得分:22)
这是一个非常好的问题!
简短的回答是没有,在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 Context不知道此User
。
为简单起见,我们将User作为POJO,但它可以是任何Valid Java Class。
应用程序架构师想要的是Event
的{{1}}应该表示为performedBy
获得全部细节。
这是@XmlJavaTypeAdapter进入图片的地方
JAXBContext将User
视为performedBy
,但必须将其表示为
Java中的xs:string
在内存中。
修改后的模型如下:
User
UserAdapter.java:
@XmlRootElement(name="event")
@XmlType(name="")
public class Event {
@XmlElement(required=true)
@XmlJavaTypeAdapter(UserAdapter.class)
protected User performedBy;
}
适配器的定义是 -
回到你的问题 -
我发现它有些多余。
顺便说一句,someMarshaller.setAdapter(...)似乎没有做任何事情。
考虑到我们的适配器需要一个名为UserContext的类才能成功编组/解组。
public class UserAdapter extends XmlAdapter<String, User> {
public String marshal(User boundType) throws Exception {
..
}
public User unmarshal(String valueType) throws Exception {
..
}
}
现在的问题是UserAdapter将如何获取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);
}
}
但是JAXB Runtime只能接受带有No-args构造函数的Adapter。 (显然JAXBContext不了解应用程序特定的模型)
谢天谢地,有一个选项:D
您可以告诉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);
}
}
使用unmarshaller
的给定实例,而不是通过自己的实例来设置它。
UserAdapter
{p} 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
&amp; Marshaller
注意:
Unmarshaller
并不意味着您不必使用setAdapter
。
@XmlJavaTypeAdapter
如果省略这个JAXB运行时不知道用户是你的绑定类型&amp;价值类型是另一回事。它将尝试按原样排列@XmlRootElement(name="event")
@XmlType(name="")
public class Event {
@XmlElement(required=true)
// @XmlJavaTypeAdapter(UserAdapter.class)
protected User performedBy;
}
。你最终会得到错误的xml
(或启用验证失败)
虽然我们已经采用了一个场景,其中必须使用Adapter作为参数
使用User
方法。
一些高级用法也在那里,即使你有默认的no-arg构造函数,但是你提供了一个适配器的实例
这个适配器可以配置数据,编组/解组操作正在使用!
答案 1 :(得分:6)
您可以使用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