Java 带有XmlAdapter的JAXB@XmlAnyElement不调用unmarshal方法
我正在尝试解组Java 带有XmlAdapter的JAXB@XmlAnyElement不调用unmarshal方法,java,xml,jaxb,unmarshalling,moxy,Java,Xml,Jaxb,Unmarshalling,Moxy,我正在尝试解组XML,并将其映射到javapojo。我的XML可以有一些用户定义的元素,这些元素可以是随机的,所以我想存储它们。经过研究,我发现我可以使用@xmlanyement(lax=true)。我试图将XMLAdapter与@xmlanyement一起使用,但由于某种原因,我的XMLAdapter中的解组方法根本没有被调用,因此我无法映射用户定义的字段 有人能告诉我如何为编组将用户定义的字段解组到我的映射中,一切正常,我正在使用该方法。但是根本没有调用解组,这让我有点困惑 下面是我的XML
XML
,并将其映射到javapojo。我的XML可以有一些用户定义的元素,这些元素可以是随机的,所以我想存储它们。经过研究,我发现我可以使用@xmlanyement(lax=true)
。我试图将XMLAdapter
与@xmlanyement
一起使用,但由于某种原因,我的XMLAdapter
中的解组方法根本没有被调用,因此我无法映射用户定义的字段
有人能告诉我如何为编组将用户定义的
字段解组到我的映射中
,一切正常,我正在使用该方法。但是根本没有调用解组
,这让我有点困惑
下面是我的XML
,它需要解组
。(请注意,名称空间
可以是动态的和用户定义的,在每个xml中可能会发生变化):
下面是我的XMLAdapter(TestAdapter)
类,它将用于编组
和解组
用户定义的
字段。根本没有调用解组
方法。但是,编组
方法根据以下情况按预期工作
我做了很多研究,但找不到任何类似的答案。此外,我尝试了很多东西,但都没有成功。因此,在这里发布相同的内容,并寻找一些建议或解决方法
对于解组
,我没有什么疑问:
为什么在解组过程中没有调用myXMLAdapter TestAdapter.class
unmarshal
方法
如何unmarshal
可以随名称空间随机出现的XML字段
我是做错了什么,还是应该做些别的事情来读取动态显示的名称空间和元素
根据回复,我编辑了我的课程,但仍然没有按照预期工作:
@XmlRootElement(name = "Customer")
@XmlType(name = "Customer", propOrder = {"name", "others"})
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
private String name;
@JsonIgnore
@XmlJavaTypeAdapter(TestAdapter.class)
private List<Object> others;
@XmlTransient
@XmlAnyElement(lax = true)
private List<Element> another = new ArrayList<>();
}
同样,当我转换这个JSON
时,我应该得到原始的XML
以下是我的Main.class
:
class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException, JsonProcessingException {
//XML to JSON
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("Customer.xml");
final XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
final XMLStreamReader streamReader = xmlInputFactory.createXMLStreamReader(inputStream);
final Customer customer = unmarshaller.unmarshal(streamReader, Customer.class).getValue();
final ObjectMapper objectMapper = new ObjectMapper();
final String jsonEvent = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(customer);
System.out.println(jsonEvent);
//JSON to XML
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(customer, System.out);
}
}
您的others
属性的Map
类型不适用于@xmlanyement
根据its的javadoc
用于列表
或数组属性
(通常使用列表
或org.w3c.dom.Element的数组
)。
可能是你把这和
它确实与Map
属性一起使用
因此,在您的Customer
类中,不使用适配器的others
属性如下所示:
姓名
这样做时,JAXB将实际调用您的适配器。
适配器的工作是在元素
和MyObject
之间进行转换
public class TestAdapter extends XmlAdapter<Element, MyObject> {
@Override
public MyObject unmarshal(Element v) throws Exception {
...
}
@Override
public Element marshal(MyObject v) throws Exception {
...
}
}
公共类TestAdapter扩展了XmlAdapter{
@凌驾
公共MyObject解组(元素v)引发异常{
...
}
@凌驾
公共元素封送处理程序(MyObject v)引发异常{
...
}
}
在尝试了很多东西之后,我能够让它工作。发布相同的解决方案,以便将来对某人有所帮助
我使用了projectlombok
,因此您可以看到一些附加注释,如@Getter、@Setter等
方法1:
正如前面提到的@Thomas Fritsch,您必须将@xmlanyement(lax=true)
与List
一起使用,我在映射中使用了
方法2:
您可以继续使用映射
并将@XmlPath(“.”
与适配器一起使用,以使其正常工作。在这里发布相同的代码:(我添加了一个附加字段age
其他所有内容保持不变)
虽然它适用于特定情况,但我发现使用这种方法存在一个问题。
如果我收到关于该问题的任何回复,那么我将尝试更新代码,使其能够正常工作。您好,非常感谢您花时间回复。也是为了得到正确的解释。我现在了解了如何对出现在XML
中的未知元素进行解组
。但我有一个疑问:这是否意味着我拥有的原始TestAdapter
将有一个空的解组方法?因为我需要该类和编组
方法,因为我正在使用Map
进行编组
,这是否意味着我需要在Customer.class
中创建另一个变量作为others
变量,我需要它位于Map
中,因为我在编组过程中使用它,这是由Jackson@AnySetter
设置的,它需要在Map
类型和编组
我需要提供那种类型。也,在新的TestAdapter
中,marshalling
方法必须是空的,因为我需要旧的TestAdapter
的marshalling
方法和Map
的方法,所以我对如何在不创建额外的适配器
@BATMAN_2008的情况下同时处理这两个变量感到困惑在您的客户
课程中。还请记住,您可以通过@JsonIgnore
对其中一个进行注释,以便忽略它。您可以通过@xmltransive
注释另一个,这样JAXB就会忽略它。非常感谢您的回复。我将尝试这样做,如果遇到问题,我将与您联系:)我尝试了@JsonIgnore
和@xmltransive
,但它会给我错误的输出。我的要求是我必须从XML->JSON
和JSON->XML
转换文件。对于t
@jakarta.xml.bind.annotation.XmlSchema(namespace = "http://google.com", elementFormDefault = jakarta.xml.bind.annotation.XmlNsForm.QUALIFIED)
package io.model.jaxb;
*** FOLLOWING IS EDITED SECTION BASED ON RESPONSE FROM Thomas Fritsch ****
@XmlRootElement(name = "Customer")
@XmlType(name = "Customer", propOrder = {"name", "others"})
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
private String name;
@JsonIgnore
@XmlJavaTypeAdapter(TestAdapter.class)
private List<Object> others;
@XmlTransient
@XmlAnyElement(lax = true)
private List<Element> another = new ArrayList<>();
}
{
"Customer": {
"name": "BATMAN",
"google:main": {
"google:sub": "bye"
}
}
}
class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException, JsonProcessingException {
//XML to JSON
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("Customer.xml");
final XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
final XMLStreamReader streamReader = xmlInputFactory.createXMLStreamReader(inputStream);
final Customer customer = unmarshaller.unmarshal(streamReader, Customer.class).getValue();
final ObjectMapper objectMapper = new ObjectMapper();
final String jsonEvent = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(customer);
System.out.println(jsonEvent);
//JSON to XML
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(customer, System.out);
}
}
@XmlAnyElement(lax = true)
private List<Element> others = new ArrayList<>();
@XmlAnyElement(lax = true)
@XmlJavaTypeAdapter(TestAdapter.class)
private List<MyObject> others = new ArrayList<>();
public class TestAdapter extends XmlAdapter<Element, MyObject> {
@Override
public MyObject unmarshal(Element v) throws Exception {
...
}
@Override
public Element marshal(MyObject v) throws Exception {
...
}
}
@XmlRootElement(name = "Customer")
@XmlType(name = "Customer", propOrder = {"name", "age", "others"})
@XmlAccessorType(XmlAccessType.FIELD)
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
@XmlElement(name = "name")
private String name;
private String age;
@XmlJavaTypeAdapter(TestAdapter.class)
@XmlPath(".")
private Map<String, Object> others;
}
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;
}