更新时间:2023-11-05 13:22:10
啊,终于松了口气.这个问题让我很头疼,但我终于找到了解决方法.尝试了很多事情并联系了很多人,但似乎没有任何效果,我认为这是 JAXB/Moxy
库的问题.我找到了解决方法.希望它对未来的人有所帮助,不要像我一样感到沮丧:)
ah, finally some relief. This issue ate my head a lot but I was finally able to find a workaround. Tried a lot of things and reached out to many people but nothing seems to work and I thought it's an issue from the JAXB/Moxy
library. I was able to find a workaround. Hope it helps someone in the future and do not get frustrated like me :)
我使用了 2 个字段,一个带有 @XmlAnyElement(lax=true) List
用于在 marshaling
和另一个 Map
.除此之外,我知道我们可以使用JSON
自定义序列化的对象>beforeMarshal
、afterMarshal
、beforeUnmarshal
、afterMarshal
方法.这个名字本身就暗示了它的作用.
I used 2 fields one with @XmlAnyElement(lax=true) List<Object>
for storing the elements during the marshaling
and another Map<String, Object>
with custom serialization for JSON
. In addition to this, I got to know that we can use beforeMarshal
, afterMarshal
, beforeUnmarshal
, afterMarshal
methods. The name itself suggests what it does.
就我而言,我使用 beforeMarshal
方法将未知数据从我的 Map
添加到 List
因此,在 marshaling
期间,将使用 List
中的值.我删除了 XMLAdapter
.
In my case, I used the beforeMarshal
method to add the unknown data from my Map<String, Object>
to List<Object>
so during the marshaling
values from List<Object>
will be used. I removed the XMLAdapter
.
此外,afterUnmarshal
方法将读取的未知元素从 List
添加到 Map
所以 Jackson
可以利用它并使用 CustomSearlizer
写入 JSON
.
Also, the afterUnmarshal
method to add the read unknown elements from List<Object>
to Map<String, Object>
so Jackson
can utilize it and write to JSON
using CustomSearlizer
.
基本上,这是一种捉迷藏的方法.List
将在 JAXB/Moxy
的 unmarshalling
和 marshaling
期间使用.Map
将在 Jackson
的序列化和反序列化
过程中使用.
Basically, it's a kind of hide-and-show approach. List<Object>
will be used during the unmarshalling
and marshaling
by JAXB/Moxy
. Map<String, Object>
will be used during the serialization and deserialization
by Jackson
.
Custome.class
与我的 beforeMarshal
和 afterUnmarshalling
:(它看起来有点复杂,基本上它如上所述交换数据.我将有复杂的数据所以我需要递归循环和排列.您可以根据需要进行更改)
Custome.class
with my beforeMarshal
and afterUnmarshalling
: (It seems bit complex basically it exchanges the data as mentioned above. I will have complex data so I need to recursively loop and arrange. You can make changes according to your need)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@XmlRootElement(name = "Customer")
@XmlType(name = "Customer", propOrder = {"name", "age", "otherElements"})
@XmlAccessorType(XmlAccessType.FIELD)
@Getter
@Setter
@AllArgsConstructor
@ToString
public class Customer {
@XmlTransient
private String isA;
private String name;
private String age;
@XmlAnyElement(lax = true)
@JsonIgnore
private List<Object> otherElements = new ArrayList<>();
@JsonIgnore
@XmlTransient
private Map<String, Object> userExtensions = new HashMap<>();
@JsonAnyGetter
@JsonSerialize(using = CustomExtensionsSerializer.class)
public Map<String, Object> getUserExtensions() {
return userExtensions;
}
@JsonAnySetter
public void setUserExtensions(String key, Object value) {
userExtensions.put(key, value);
}
private void beforeMarshal(Marshaller m) throws ParserConfigurationException {
System.out.println("Before Marshalling User Extension: " + userExtensions);
ExtensionsModifier extensionsModifier = new ExtensionsModifier();
otherElements = extensionsModifier.Marshalling(userExtensions);
System.out.println("Before Marshalling Final Other Elements " + otherElements);
userExtensions = new HashMap<>();
}
private void afterUnmarshal(Unmarshaller m, Object parent) throws ParserConfigurationException {
System.out.println("After Unmarshalling : " + otherElements);
ExtensionsModifier extensionsModifier = new ExtensionsModifier();
userExtensions = extensionsModifier.Unmarshalling(otherElements);
otherElements = new ArrayList();
}
}
然后是 ExtensionsModifier.class
将被 beforeMarshal
和 afterUnmarshalling
方法调用:
Then the ExtensionsModifier.class
which will be called by beforeMarshal
and afterUnmarshalling
method:
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;
}
}
以下是我的 CustomSearlizer
,Jackson
将使用它来创建 JSON:
Following is my CustomSearlizer
which will be used by Jackson
to create 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);
}
}
}
}
}
}
}
如果我提供如下输入XML
:
<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>
然后我得到以下 JSON
作为输出:
Then I get the following JSON
as output:
{
"isA" : "Customer",
"name" : "Rise Against",
"age" : "2000",
"google:main" : {
"google:sub" : "MyValue",
"google:sub" : "MyValue"
}
}
反之亦然.希望很清楚,如果不发表评论将尝试回复.
Viceversa would also work fine. Hope it's clear if not leave a comment will try to respond.