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"
  }
}