JAXB/Moxy @XmlPath(".") 在解组期间与 XMLAdapter 冲突
即使在尝试了很多事情之后也无法找到解决方案,因此在此处发布希望获得一些解决方法或解决此问题.
Was unable to find the solution even after trying many things so posting here hoping to get some workaround or fix for this issue.
基本上,如果 @XmlPath(".")
已在 Map
上使用,并且其上有 XMLAdapter
然后它在 unmarshalling
期间失败.marshaling
工作完美,只有 unmarshaling
失败.
Basically, if the @XmlPath(".")
has been used on a Map
and if there is XMLAdapter
on it then it fails during the unmarshalling
. The marshaling
works perfectly only the unmarshalling
fails.
简而言之,我想执行 unmarshalling
这里提到过,但除了 Map
我还会有一个 @XmlElement
.所以一个字段用 (Map field) @XmlPath(".")
和另一个 String 字段用 @XmlElement
注释,然后我想执行 解组
.
In short, I would like to perform the unmarshalling
as mentioned here but along with Map
I will have one more @XmlElement
. So one field is annotated with (Map field) @XmlPath(".")
and another String field with @XmlElement
and then I would like to perform unmarshalling
.
以下是我尝试unmarshal
的XML
:
<Customer xmlns:google="https://google.com">
<name>Batman</name>
<age>2008</age>
<google:sub1>MyValue-1</google:sub1>
<google:sub2>MyValue-1</google:sub2>
</Customer>
下面是 Customer.class
,它将被 unmarshalled
:
@XmlRootElement(name = "Customer")
@XmlType(name = "Customer", propOrder = {"name", "age", "userExtensions"})
@XmlAccessorType(XmlAccessType.FIELD)
@NoArgsConstructor
@Getter
@Setter
@AllArgsConstructor
public class Customer extends Person {
private String name;
private String age;
@XmlPath(".")
@XmlJavaTypeAdapter(TestAdapter.class)
@XmlAnyElement
private Map<String, Object> userExtensions = new HashMap<>();
}
以下是 Main
类,它将 unmarshal
:
Following is the Main
class which will unmarshal
:
public class Unmarshalling {
public static void main(String[] args)
throws JAXBException, XMLStreamException, FactoryConfigurationError, IOException, URISyntaxException, ProcessingException {
final InputStream inputStream = Unmarshalling.class.getClassLoader().getResourceAsStream("customer.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
final Customer customer = unmarshaller.unmarshal(xmlStreamReader, Customer.class).getValue();
System.out.println("Read XML : " + customer);
}
}
当我运行这段代码时,我会得到如下输出:
When I run this code I will get the output as:
Read XML : Person(name=Rise Against, age=2000)
它不读取 custom
元素,例如 google:sub1
和 google:sub2
.
Its not reading the custom
elements such as google:sub1
and google:sub2
.
- 还有一个与此类似的问题,但其中提到的解决方法对我不起作用.
- 我在
MAP
上尝试了@XmlAnyElement(lax=true)
,即使这对我不起作用.
- There is one more issue similar to this but the workaround mentioned there did not work for me.
- I tried the
@XmlAnyElement(lax=true)
onMAP
even that did not work for me.
以下是我用于 marshalling
和 unmarhsalling
的 TestAdapter
Map
Following is the TestAdapter
that I am using for marshalling
and unmarhsalling
the Map<String,Object>
public class TestAdapter extends XmlAdapter<Wrapper, Map<String, Object>> {
@Override
public Map<String, Object> unmarshal(Wrapper value) throws Exception {
System.out.println("ADAPTER UNMARSHALLING");
System.out.println(value.getElements());
if (value == null) {
return null;
}
//Loop across all elements within ILMD tag
final Map<String, Object> extensions = new HashMap<>();
for (Object obj : value.getElements()) {
Element element = (Element) obj;
//System.out.println("Node Name : " + element.getNodeName() + " Value : " + element.getTextContent());
final NodeList children = element.getChildNodes();
if (children.getLength() == 1) {
extensions.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));
}
}
extensions.put(element.getNodeName(), child);
}
}
return extensions;
}
@SuppressWarnings("unchecked")
@Override
public Wrapper marshal(Map<String, Object> v) throws Exception {
if (v == null) {
return null;
}
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;
}
}
class Wrapper {
@XmlAnyElement
List elements;
public List getElements() {
return elements;
}
我尝试了很多东西,但直到现在都没有奏效.有人可以看看这个问题并提供您的解决方案.很高兴提供有关此问题的更多信息,因为我花了将近 10 天的时间寻找答案.
I tried many things but nothing worked till now. Can someone please have a look at this issue and provide your solution. Happy to provide any more info with regards to this issue as I have spent nearly 10 days looking for answers.
我尝试了以下方法:
- 又创建了一个变量,并尝试仅在解组期间使用它,但这也失败了.
- 尝试再创建一个字段,然后在其上使用
@XmlAnyElement
,但这也没有按我的预期工作.
- Created one more variable and tried to use it only during unmarshalling but that's also failing.
- Tried to create one more field then used the
@XmlAnyElement
on it but that's also not working as I expected.
尝试了更多的东西,但没有任何帮助.
Tried few more things but nothing helped.
一切都失败了.我试图从 MOXY
调试代码,但我无法在其中了解很多事情.对这个问题的任何帮助都会对我很有帮助.
Everything is failing. I tried to debug the code from MOXY
but I am unable to follow many things there. Any help with this issue would be really helpful for me.
推荐答案
我能够通过使用 BeforeMarshal
和 AfterMarshal
方法得到它.在这里发帖,以便将来对某人有所帮助:
I was able to get it by using the BeforeMarshal
and AfterMarshal
methods. Posting here so it can be helpful to someone in the future:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "isA")
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@XmlRootElement(name = "extension")
@XmlType(name = "extension", propOrder = {"name", "age", "otherElements"})
@XmlAccessorType(XmlAccessType.FIELD)
@Getter
@Setter
@AllArgsConstructor
@ToString
@NoArgsConstructor
public class Customer {
@XmlTransient
private String isA;
@XmlPath("customer/name/text()")
private String name;
@XmlPath("customer/age/text()")
private String age;
@XmlAnyElement(lax = true)
@JsonIgnore
@XmlPath("customer")
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);
System.out.println("Final User Extensions : " + userExtensions);
otherElements = new ArrayList();
}
}
完整的答案可以在这里找到:https://stackoverflow.com/a/67923216/7584240
The complete answer can be found here: https://stackoverflow.com/a/67923216/7584240
相关文章