Java JAXB/Moxy解组将所有字段值分配给映射<;字符串,对象>;而不是为其提供的特定字段
简言之,我想执行Java JAXB/Moxy解组将所有字段值分配给映射<;字符串,对象>;而不是为其提供的特定字段,java,xml,jaxb,unmarshalling,moxy,Java,Xml,Jaxb,Unmarshalling,Moxy,简言之,我想执行解组,但除了映射之外,我还有一个@xmlement。因此,一个字段用(Map field)@XmlPath(“.”注释,另一个字段用(String field)@xmlement注释,然后我想执行解组 <Customer> <name>BATMAN</name> <age>2008</age> <google:main>> <google:sub>by
解组
,但除了映射
之外,我还有一个@xmlement
。因此,一个字段用(Map field)@XmlPath(“.”
注释,另一个字段用(String field)@xmlement
注释,然后我想执行解组
<Customer>
<name>BATMAN</name>
<age>2008</age>
<google:main>>
<google:sub>bye</google:sub>
</google:main>
</Customer>
我的应用程序的主要目标是使用JAXB/Moxy和Jackson
库转换XML->JSON
和JSON->XML
。我正在尝试unmarshal
XML并将其映射到javapojo。我的XML可以有一些专用元素和一些用户定义的元素,这些元素可能是随机的,因此我希望将它们存储在Map
中。因此,我正在使用XMLAdapter
。我正在跟踪调查。我做的不完全一样,但有点不同
我面临的问题是在解组期间
根本不考虑专用字段。所有值都将解组
到映射
。据我所知,这是因为注释@XmlPath(“.”
和XMLAdapter
的使用而发生的,但如果我删除此注释,它将无法按预期工作。有人能帮我解决这个问题吗?封送处理
可以与@XmlPath(“.”
和XMLAdapter
一起正常工作。该问题仅在解组
期间出现
<Customer>
<name>BATMAN</name>
<age>2008</age>
<google:main>>
<google:sub>bye</google:sub>
</google:main>
</Customer>
以下是我想转换为JSON
的XML
:(注意:Name
和Age
是专用字段,others
是用户定义的字段。)
以下是我的TestAdapter
类,它将用于用户定义的
字段:
class TestAdapter extends XmlAdapter<Wrapper, Map<String, Object>> {
@Override
public Map<String, Object> unmarshal(Wrapper value) throws Exception {
System.out.println("INSIDE UNMARSHALLING METHOD TEST");
final Map<String, Object> others = new HashMap<>();
for (Object obj : value.getElements()) {
final Element element = (Element) obj;
final NodeList children = element.getChildNodes();
//Check if its direct String value field or complex
if (children.getLength() == 1) {
others.put(element.getNodeName(), element.getTextContent());
} else {
List<Object> child = new ArrayList<>();
for (int i = 0; i < children.getLength(); i++) {
final Node n = children.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
Wrapper wrapper = new Wrapper();
List childElements = new ArrayList();
childElements.add(n);
wrapper.elements = childElements;
child.add(unmarshal(wrapper));
}
}
others.put(element.getNodeName(), child);
}
}
return others;
}
@Override
public Wrapper marshal(Map<String, Object> v) throws Exception {
Wrapper wrapper = new Wrapper();
List elements = new ArrayList();
for (Map.Entry<String, Object> property : v.entrySet()) {
if (property.getValue() instanceof Map) {
elements.add(new JAXBElement<Wrapper>(new QName(property.getKey()), Wrapper.class, marshal((Map) property.getValue())));
} else {
elements.add(new JAXBElement<String>(new QName(property.getKey()), String.class, property.getValue().toString()));
}
}
wrapper.elements = elements;
return wrapper;
}
}
@Getter
class Wrapper {
@XmlAnyElement
List elements;
}
当我转换XML->JSON
时,我得到以下输出:(如果您观察到name
和age
字段不是作为Customer
类的专用字段,而是作为随机字段,并写入其他中)
我希望我的输出是这样的:(我希望先映射我的专用字段,然后如果有任何未知字段,则稍后在其他映射中映射它们
)。请注意,我不想在我的JSON
中获得others
标记。我只想获取专用字段的字段名
{
"name": "BATMAN",
"age": 2008,
"google:main": {
"google:sub": "bye"
}
}
以下是我希望在封送过程中获得的XML
。另外,请注意,我使用的是@XmlPath(“.”
,这样在封送过程中,我就不会在XML
中获得其他
节点
<Customer>
<name>BATMAN</name>
<age>2008</age>
<google:main>>
<google:sub>bye</google:sub>
</google:main>
</Customer>
蝙蝠侠
2008
>
再见
封送处理
工作正常。根据我的理解,解组
过程中出现问题是因为使用XMLAdapter
的注释@XmlPath(“.”
),但如果我删除此注释,它将无法按预期工作。有人能帮我解决这个问题吗
**编辑**
我想到了一些变通办法,但似乎没有什么办法适合我。由于@XmlPath(“.”
,它们变得一团糟。仍在寻找一些想法或解决办法。任何帮助都将不胜感激。我相信这与问题有关:
根据错误通知单:
org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl
public XPathNode getNonAttributeXPathNode(String namespaceURI, String localName, String qName, Attributes attributes) {
...
Line 1279
if(null == resultNode && null == nonPredicateNode) {
// ANY MAPPING
resultNode = xPathNode.getAnyNode();// by default it return the EventAdapter returing a null at this place fix the problem, but i dont know if its the best solution
}
我认为这与这个问题有些关联:
根据错误通知单:
org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl
public XPathNode getNonAttributeXPathNode(String namespaceURI, String localName, String qName, Attributes attributes) {
...
Line 1279
if(null == resultNode && null == nonPredicateNode) {
// ANY MAPPING
resultNode = xPathNode.getAnyNode();// by default it return the EventAdapter returing a null at this place fix the problem, but i dont know if its the best solution
}
作为(只是)一种解决方法,专用字段可以转到单独的类中,因此它可以自行解组。“客户”将从此类扩展
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Person", propOrder = { "name", "age"})
public class Person {
protected String name;
protected String age;
//getters and stuff
}
顾客
@XmlRootElement(name = "Customer")
@XmlType(name = "Customer") //, propOrder = { "name", "age", "others" }
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer extends Person{
@XmlPath(".")
@XmlJavaTypeAdapter(TestAdapter.class)
private Map<String, Object> others;
}
作为(只是)一种解决方法,专用字段可以转到单独的类中,因此它可以自行解组。“客户”将从此类扩展
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Person", propOrder = { "name", "age"})
public class Person {
protected String name;
protected String age;
//getters and stuff
}
顾客
@XmlRootElement(name = "Customer")
@XmlType(name = "Customer") //, propOrder = { "name", "age", "others" }
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer extends Person{
@XmlPath(".")
@XmlJavaTypeAdapter(TestAdapter.class)
private Map<String, Object> others;
}
啊,终于松了一口气。这个问题让我头痛不已,但我终于找到了解决办法。尝试了很多东西并联系了很多人,但似乎没有任何效果,我认为这是来自JAXB/Moxy
库的问题。我找到了一个解决办法。希望它能帮助将来的人,不要像我一样沮丧:)
我使用了两个字段,一个是@xmlanyement(lax=true)List
,用于在封送过程中存储元素,另一个是Map
,用于JSON
的自定义序列化。除此之外,我还知道我们可以使用beforemashal
,afterMarshal
,beforemashal
,afterMarshal
方法。这个名字本身就暗示了它的功能
在我的例子中,我使用beforemashall
方法将我的Map
中的未知数据添加到List
中,因此在封送期间,将使用List
中的值。我删除了XMLAdapter
另外,afterUnmarshal
方法将读取的未知元素从List
添加到Map
,以便Jackson
可以利用它,并使用CustomSearlizer
写入JSON
基本上,这是一种隐藏和显示的方法<代码>列表
将在解组
和封送
期间由JAXB/Moxy
使用<代码>映射
将由Jackson
在序列化和反序列化期间使用
Custome.class
与我的beforemashall
和afterunmarshall
:(看起来有点复杂,基本上它会像上面提到的那样交换数据。我会有复杂的数据,所以我需要递归地循环和排列。你可以根据需要进行更改)
以下是我的CustomSearlizer
,它将被Jackson
用来创建JSON:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
public class CustomExtensionsSerializer extends JsonSerializer<Map<String, Object>> {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public void serialize(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
System.out.println("Custom Json Searlizer: " + value);
recusiveSerializer(value, gen, serializers);
}
public void recusiveSerializer(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
for (Map.Entry<String, Object> extension : value.entrySet()) {
if (extension.getValue() instanceof Map) {
//If instance is MAP then call the recursive method
recusiveSerializer((Map) extension.getValue(), gen, serializers);
} else if (extension.getValue() instanceof String) {
//If instance is String directly add it to the JSON
gen.writeStringField(extension.getKey(), (String) extension.getValue());
} else if (extension.getValue() instanceof ArrayList) {
//If instance if ArrayList then loop over it and add it to the JSON after calling recursive method
//If size more than 1 add outer elements
if (((ArrayList<Object>) extension.getValue()).size() > 1) {
gen.writeFieldName(extension.getKey());
gen.writeStartObject();
for (Object dupItems : (ArrayList<Object>) extension.getValue()) {
if (dupItems instanceof Map) {
recusiveSerializer((Map) dupItems, gen, serializers);
} else {
gen.writeStringField(extension.getKey(), (String) dupItems);
}
}
gen.writeEndObject();
} else {
for (Object dupItems : (ArrayList<Object>) extension.getValue()) {
if (dupItems instanceof Map) {
gen.writeFieldName(extension.getKey());
gen.writeStartObject();
recusiveSerializer((Map) dupItems, gen, serializers);
gen.writeEndObject();
} else {
gen.writeStringField(extension.getKey(), (String) dupItems);
}
}
}
}
}
}
}
然后我得到以下JSON
作为输出:
{
"isA" : "Customer",
"name" : "Rise Against",
"age" : "2000",
"google:main" : {
"google:sub" : "MyValue",
"google:sub" : "MyValue"
}
}
维切维萨会的
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ExtensionsModifier {
private javax.xml.parsers.DocumentBuilderFactory documentFactory;
private javax.xml.parsers.DocumentBuilder documentBuilder;
private org.w3c.dom.Document document;
public ExtensionsModifier() throws ParserConfigurationException {
documentFactory = DocumentBuilderFactory.newInstance();
documentBuilder = documentFactory.newDocumentBuilder();
document = documentBuilder.newDocument();
}
public List<Object> Marshalling(Map<String, Object> userExtensions) throws ParserConfigurationException {
if (userExtensions == null) {
return null;
}
List<Object> tempElement = new ArrayList<>();
for (Map.Entry<String, Object> property : userExtensions.entrySet()) {
Element root = document.createElement(property.getKey());
if (property.getValue() instanceof Map) {
List<Object> mapElements = Marshalling((Map<String, Object>) property.getValue());
mapElements.forEach(innerChildren -> {
if (innerChildren instanceof Element) {
if (((Element) innerChildren).getTextContent() != null) {
root.appendChild(document.appendChild((Element) innerChildren));
}
}
});
tempElement.add(root);
} else if (property.getValue() instanceof String) {
root.setTextContent(((String) property.getValue()));
tempElement.add(root);
} else if (property.getValue() instanceof ArrayList) {
for (Object dupItems : (ArrayList<Object>) property.getValue()) {
if (dupItems instanceof Map) {
Element arrayMap = document.createElement(property.getKey());
List<Object> arrayMapElements = Marshalling((Map<String, Object>) dupItems);
arrayMapElements.forEach(mapChildren -> {
if (mapChildren instanceof Element) {
if (((Element) mapChildren).getTextContent() != null) {
arrayMap.appendChild(document.appendChild((Element) mapChildren));
}
}
});
tempElement.add(arrayMap);
} else if (dupItems instanceof String) {
Element arrayString = document.createElement(property.getKey());
arrayString.setTextContent((String) dupItems);
tempElement.add(arrayString);
}
}
}
}
return tempElement;
}
public Map<String, Object> Unmarshalling(List<Object> value) {
if (value == null) {
return null;
}
final Map<String, Object> extensions = new HashMap<>();
for (Object obj : value) {
org.w3c.dom.Element element = (org.w3c.dom.Element) obj;
final NodeList children = element.getChildNodes();
//System.out.println("Node Name : " + element.getNodeName() + " Value : " + element.getTextContent());
List<Object> values = (List<Object>) extensions.get(element.getNodeName());
if (values == null) {
values = new ArrayList<Object>();
}
if (children.getLength() == 1) {
values.add(element.getTextContent());
extensions.put(element.getNodeName(), values);
} else {
List<Object> child = new ArrayList<>();
for (int i = 0; i < children.getLength(); i++) {
final Node n = children.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
List<Object> childElements = new ArrayList();
childElements.add(n);
values.add(Unmarshalling(childElements));
child.add(Unmarshalling(childElements));
}
}
extensions.put(element.getNodeName(), values);
}
}
return extensions;
}
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
public class CustomExtensionsSerializer extends JsonSerializer<Map<String, Object>> {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public void serialize(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
System.out.println("Custom Json Searlizer: " + value);
recusiveSerializer(value, gen, serializers);
}
public void recusiveSerializer(Map<String, Object> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
for (Map.Entry<String, Object> extension : value.entrySet()) {
if (extension.getValue() instanceof Map) {
//If instance is MAP then call the recursive method
recusiveSerializer((Map) extension.getValue(), gen, serializers);
} else if (extension.getValue() instanceof String) {
//If instance is String directly add it to the JSON
gen.writeStringField(extension.getKey(), (String) extension.getValue());
} else if (extension.getValue() instanceof ArrayList) {
//If instance if ArrayList then loop over it and add it to the JSON after calling recursive method
//If size more than 1 add outer elements
if (((ArrayList<Object>) extension.getValue()).size() > 1) {
gen.writeFieldName(extension.getKey());
gen.writeStartObject();
for (Object dupItems : (ArrayList<Object>) extension.getValue()) {
if (dupItems instanceof Map) {
recusiveSerializer((Map) dupItems, gen, serializers);
} else {
gen.writeStringField(extension.getKey(), (String) dupItems);
}
}
gen.writeEndObject();
} else {
for (Object dupItems : (ArrayList<Object>) extension.getValue()) {
if (dupItems instanceof Map) {
gen.writeFieldName(extension.getKey());
gen.writeStartObject();
recusiveSerializer((Map) dupItems, gen, serializers);
gen.writeEndObject();
} else {
gen.writeStringField(extension.getKey(), (String) dupItems);
}
}
}
}
}
}
}
<Customer xmlns:google="https://google.com">
<name>Rise Against</name>
<age>2000</age>
<google:main>
<google:sub>MyValue</google:sub>
<google:sub>MyValue</google:sub>
</google:main>
</Customer>
{
"isA" : "Customer",
"name" : "Rise Against",
"age" : "2000",
"google:main" : {
"google:sub" : "MyValue",
"google:sub" : "MyValue"
}
}