[英]JAXB @XmlAdapter: Map -> List adapter? (marshall only)
[英]How can JAXB XmlAdapter be used to marshall lists?
此类的实例是大型对象图的一部分,而不是对象图的根:
public class Day
{
public Day(LocalDate date, List<LocalTime> times)
{
this.date = date;
this.times = times;
}
public Day()
{
this(null, null);
}
public LocalDate getDate()
{
return date;
}
public List<LocalTime> getTimes()
{
return times;
}
private final LocalDate date;
private final List<LocalTime> times;
}
使用Jersey和JAXB将对象图转换为JSON。 我XmlAdapter
的注册为LocalDate
和LocalTime
。
问题在于它仅适用于date
属性,而不适用于times
属性。 我怀疑这与times
是一个列表而不是一个单一值有关。 然后,如何告诉Jersey / JAXB使用注册的XmlAdapter
将times
列表中的每个元素编组?
更新:
我通过添加标量LocalTime
属性并观察JSON中的预期输出,确认LocalTime
编组确实适用于标量LocalTime
属性。
为了完整起见,这里是package-info.java:
@XmlJavaTypeAdapters({
@XmlJavaTypeAdapter(value = LocalDateAdapter.class, type = LocalDate.class),
@XmlJavaTypeAdapter(value = LocalTimeAdapter.class, type = LocalTime.class)
})
package same.package.as.everything.else;
LocalDateAdapter
:
public class LocalDateAdapter extends XmlAdapter<String, LocalDate>
{
@Override
public LocalDate unmarshal(String v) throws Exception
{
return formatter.parseLocalDate(v);
}
@Override
public String marshal(LocalDate v) throws Exception
{
return formatter.print(v);
}
private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyyMMdd");
}
LocalTimeAdapter
:
public class LocalTimeAdapter extends XmlAdapter<String, LocalTime>
{
@Override
public LocalTime unmarshal(String v) throws Exception
{
return formatter.parseLocalTime(v);
}
@Override
public String marshal(LocalTime v) throws Exception
{
return formatter.print(v);
}
private final DateTimeFormatter formatter = DateTimeFormat.forPattern("HHmm");
类的XmlAdapter
应用于该类型的映射字段/属性,对于集合,则应用于集合中的每个项目。 下面的示例证明了这可行。 您是否尝试过将示例独立运行到XML以验证这种方式的映射。 怀疑问题是XmlAdapter
以外的其他问题。
StringAdapter
以下XmlAdapter
将在解组操作时将String
转换为小写,并在编组时将其转换为大写。
package forum14569293;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringAdapter extends XmlAdapter<String, String> {
@Override
public String unmarshal(String v) throws Exception {
return v.toLowerCase();
}
@Override
public String marshal(String v) throws Exception {
return v.toUpperCase();
}
}
包信息
就像您的问题一样,将使用包级别@XmlJavaTypeAdapters
批注来注册XmlAdapter
。 这将为此包内所有映射的String
属性注册此XmlAdapter
(请参阅: http : XmlAdapter
)。
@XmlJavaTypeAdapters({
@XmlJavaTypeAdapter(value=StringAdapter.class, type=String.class)
})
package forum14569293;
import javax.xml.bind.annotation.adapters.*;
根
下面是一个与您的Day
类相似的示例域模型,具有两个映射的属性。 第一个是String
类型,第二个是List<String>
。 关于Day
类,我注意到的一件事是您只有get
方法。 这意味着您将需要为JAXB impl添加一个@XmlElement
批注,以考虑该映射属性。
package forum14569293;
import java.util.*;
import javax.xml.bind.annotation.*;
@XmlRootElement
public class Root {
public Root(String foo, List<String> bar) {
this.foo = foo;
this.bar = bar;
}
public Root() {
this(null, null);
}
@XmlElement
public String getFoo() {
return foo;
}
@XmlElement
public List<String> getBar() {
return bar;
}
private final String foo;
private final List<String> bar;
}
演示
package forum14569293;
import java.util.*;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
List<String> bar = new ArrayList<String>(3);
bar.add("a");
bar.add("b");
bar.add("c");
Root root = new Root("Hello World", bar);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
产量
下面是运行演示代码的输出,我们看到XmlAdapter
将所有字符串都转换为大写。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<bar>A</bar>
<bar>B</bar>
<bar>C</bar>
<foo>HELLO WORLD</foo>
</root>
UPDATE
谢谢。 我尝试了一下,XML只包含一个空标记,这意味着JAXB不喜欢POJO模型。 (也许它应该可序列化?)
JAXB不需要POJO实现Serializable
。
这很有趣,因为它似乎表明JAXB唯一起作用的部分是将其批注和其他一些接口(例如XmlAdapter)借给JSON(反)序列化器,并且关系就在那里结束了。
这取决于用作JSON绑定层的内容。 JAXB(JSR-222)规范不涵盖JSON绑定,因此这种类型的支持超出了规范。 EclipseLink JAXB(MOXy)提供了本机JSON绑定(我是MOXy主管),您可以执行以下操作:
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
marshaller.marshal(root, System.out);
并获得将XmlAdapter
考虑在内的以下输出:
{
"bar" : [ "A", "B", "C" ],
"foo" : "HELLO WORLD"
}
但是,当我有机会的时候,我将尽我所能来使JAXB生成XML,这可能会揭示出其他东西。
这将很有用,因为我不认为您看到的是JAXB问题,而是您正在使用的JSON绑定层中的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.