gpt4 book ai didi

java - 如何在 JAXB 中将对象作为 @XmlValue 嵌入?

转载 作者:行者123 更新时间:2023-11-30 11:41:57 26 4
gpt4 key购买 nike

我想表示 List<Map<String,Object>> 的一个实例在 XML 中如下所示:

<row>
<entry key="key1" xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">value1</entry>
<entry key="key2" xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">value2</entry>
<entry key="key3" />
<entry key="keyDate" xsi:type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2012-08-19T13:00:59.412-04:00</entry>
</row>

哪里key1key2是字符串,key3为零,keyDate是一个日期。

我可以使用以下 XmlAdapter 的实现接近 :

package net.parkerson.test1;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class JAXBMapAdapter extends XmlAdapter<JAXBMapAdapter.JAXBMap, Map<String, Object>>
{

@Override
public JAXBMap marshal(Map<String, Object> map) throws Exception
{
JAXBMap jaxbMap = new JAXBMap();
for (Entry<String, Object> entry : map.entrySet())
{
jaxbMap.entry.add(new JAXBMapEntry(entry));
}
return jaxbMap;

}

@Override
public Map<String, Object> unmarshal(JAXBMapAdapter.JAXBMap mappedObject) throws Exception
{
HashMap<String, Object> map = new HashMap<String, Object>();
for (JAXBMapEntry entry : mappedObject.entry)
{
map.put(entry.key, entry.value);
}
return map;
}

public static class JAXBMapEntry
{

@XmlAttribute
public String key;

@XmlElement
public Object value;

public JAXBMapEntry()
{
}

public JAXBMapEntry(Map.Entry<String, Object> entry)
{
key = entry.getKey();
value = entry.getValue();
}
}

public static class JAXBMap
{
public List<JAXBMapAdapter.JAXBMapEntry> entry = new ArrayList<JAXBMapAdapter.JAXBMapEntry>();
}
}

和下面的测试代码:

package net.parkerson.test1;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import net.parkerson.test1.JAXBMapAdapter;

public class Test1
{
@XmlRootElement
public static class Thingy
{
@XmlElements(@XmlElement(name = "row"))
@XmlJavaTypeAdapter(type=Map.class, value=JAXBMapAdapter.class)
public List<Map<String,Object>> rows;
}

public static void main(String[] args) throws Exception
{
Test1.Thingy thingy = new Test1.Thingy();

Map<String,Object> thing1 = new HashMap<String,Object>();
thing1.put("foo", "bar");
thing1.put("date", new Date());

Map<String,Object> thing2 = new HashMap<String,Object>();
thing2.put("foo", "baz");
thing2.put("date", new Date());

List<Map<String,Object>> things = new ArrayList<Map<String,Object>>();
things.add(thing1);
things.add(thing2);

thingy.rows = things;

java.io.StringWriter sw = new java.io.StringWriter();
JAXB.marshal(thingy, sw);
System.out.print(sw.toString());
}

}

生成这个:

<thingy>
<row>
<entry key="foo">
<value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">bar</value>
</entry>
<entry key="date">
<value xsi:type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2012-08-19T13:20:57.484-04:00</value>
</entry>
</row>
<row>
<entry key="foo">
<value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">baz</value>
</entry>
<entry key="date">
<value xsi:type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">2012-08-19T13:20:57.484-04:00</value>
</entry>
</row>
</thingy>

我真正想要的是放弃嵌套的 value条目内的标记。我天真的假设是我可以替换 @XmlElement关于 value 的注释至 @XmlValue .然而,这导致 JAXB 吐了一地:

Exception in thread "main" java.lang.NullPointerException
at com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor.get(TransducedAccessor.java:154)
at com.sun.xml.internal.bind.v2.runtime.property.ValueProperty.<init>(ValueProperty.java:66)
at com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory.create(PropertyFactory.java:95)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:145)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:479)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:498)
at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementProperty.<init>(ArrayElementProperty.java:97)
at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementNodeProperty.<init>(ArrayElementNodeProperty.java:47)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory.create(PropertyFactory.java:113)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:145)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:479)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:498)
at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementProperty.<init>(ArrayElementProperty.java:97)
at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementNodeProperty.<init>(ArrayElementNodeProperty.java:47)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory.create(PropertyFactory.java:113)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:145)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:479)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:305)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1100)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:143)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:110)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:202)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:376)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:522)
at javax.xml.bind.JAXB$Cache.<init>(JAXB.java:87)
at javax.xml.bind.JAXB.getContext(JAXB.java:114)
at javax.xml.bind.JAXB._marshal(JAXB.java:538)
at javax.xml.bind.JAXB.marshal(JAXB.java:431)
at net.parkerson.test1.Test1.main(Test1.java:49)

我确信有一种方法可以使用我的 XmlAdapter 来做到这一点-based 代码,但我想我已经盯着这个看太久了,想不出来!

最佳答案

奇怪。如果您将 map 类型从 <String, Object> 更改为至 <String, String>它按预期工作。

更新:似乎如果您强制 JAXB 使用@XmlValue(或@XmlAttribute)呈现值,它就没有地方放置其类型信息:xsi:type="xs:dateTime" ...它需要是一个@XmlElement

我的建议是使用 Map<String, String>使用从 String 编码/解码的适配器至 Object取决于底层类型:

public class MySmartAdapter extends XmlAdapter<String, Object> {
@Override
public Object unmarshal(String s) throws Exception {
//check if s is date and return date
//check for other types
return s;
}

@Override
public String marshal(Object o) throws Exception {
return o != null ? o.toString() : null;
}
}


public static class JAXBMapEntry
{

@XmlAttribute
public String key;

@XmlValue
@XmlJavaTypeAdapter(MySmartAdapter.class)
public Object value;

public JAXBMapEntry()
{
}

public JAXBMapEntry(Map.Entry<String, Object> entry)
{
key = entry.getKey();
value = entry.getValue();
}
}

关于java - 如何在 JAXB 中将对象作为 @XmlValue 嵌入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12028489/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com