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)
类,它将用于
编组
解组
用户定义的
字段。根本没有调用
解组
方法。但是,
编组
方法根据以下情况按预期工作

我做了很多研究,但找不到任何类似的答案。此外,我尝试了很多东西,但都没有成功。因此,在这里发布相同的内容,并寻找一些建议或解决方法

对于
解组
,我没有什么疑问:

  • 为什么在解组过程中没有调用my
    XMLAdapter 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;
    }