当前位置: 首页 > 知识库问答 >
问题:

JAXB/MOXY解组将所有字段值分配给map而不是为其提供的特定字段

潘弘博
2023-03-14

简而言之,我希望执行这里提到的解组,但是除了映射之外,我还会有一个@XmlElement。因此,一个字段用(映射字段)@XMLPath(“.”)注释,另一个字段用(字符串字段)@XMLElement注释,然后我要执行解组

以下是我想要转换为JSONXML:(注意:nameage是专用字段,othersuser-defined字段。)

<Customer xmlns:google="https://google.com">
  <name>BATMAN</name>
  <age>2008</age>
  <google:main>
    <google:sub>bye</google:sub>
  </google:main>
</Customer>

下面是我的customer类,用于moxyjackson进行封送处理agecustomer类:(注意:nameage是专用字段,而others用户定义的字段。我希望others只存储不能直接映射到POJO的值,如google:main及其从上面XML的子项)

@XmlRootElement(name = "Customer")
@XmlType(name = "Customer", propOrder = {"name", "age", "others"})
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
  private String name;
  private String age;

  @XmlPath(".")
  @XmlJavaTypeAdapter(TestAdapter.class)
  private Map<String, Object> others;
  //Getter, Setter and other constructors
}

下面是我的TestAdapter类,它将用于userdefined字段:

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

最后,我的main类将用于marshalingunmarshaling。还要转换为JSON和XML。

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);
  }
}

当我转换xml->json时,我会得到以下输出:(如果您注意到字段nameage不作为customer类中的专用字段,而是作为随机场写入others中)

{
  "name" : "",
  "age" : "",
  "others" : {
    "google:main" : [ {
      "google:sub" : "bye"
    } ],
    "name" : "BATMAN",
    "age" : "2008"
  }
}
{
  "name": "BATMAN",
  "age": 2008,
  "google:main": {
    "google:sub": "bye"
  }
}

下面是我希望在封送处理过程中获得的XML。另外,请注意,我使用的是@XMLPath(“.”),这样在封送期间,我就不会在我的XML中获得others节点。

<Customer>
    <name>BATMAN</name>
    <age>2008</age>
    <google:main>>
        <google:sub>bye</google:sub>
    </google:main>
</Customer>

封送工作正常。问题发生在.解封期间,根据我的理解,它的发生是由于XmlAdapter的注释@XmlPath(“.”)造成的,但如果我删除此注释,它将无法正常工作。有人能帮我解决这个问题吗?

**编辑**

共有1个答案

仲孙文乐
2023-03-14

我相信这与@xmlpath(“.”)这个问题有一定的关系与@XmlAdapter冲突

根据bug ticket:

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
       }
 类似资料:
  • 在不使用getter和setter的情况下,JAXB可以正确地解组所提供的JSON。 null和“null”是完全不同的东西,但是我不想在POJO中包含这个字段,并且我必须忽略这些null值。 编辑

  • 问题内容: 由于空字符串是Go的零/默认值,因此我决定将所有此类字段定义为。例如 如果该值不适用于该特定字段,则我正在发送数据的应用程序期望使用null而不是空字符串。 这是正确的方法吗?或者有人可以向我指出比这更好的方法。 问题答案: 在json包文档中: 指针值编码为指向的值。nil指针编码为空JSON对象。 因此,您可以存储指向字符串的指针,如果不为nil,则将其编码为字符串;如果为nil,

  • 问题内容: 我正在阅读的源代码,并发现了一些我不理解的代码: 注意这一行: 为什么不直接使用它,而是将其分配给局部变量? 问题答案: 可能是出于 优化 目的吗? 可能可以通过JIT编译器更轻松地将局部变量直接分配给寄存器。 至少在Android中,对于API的第一个版本,访问局部变量比访问实例变量便宜(不能代表较新的版本)。普通的Java可能是相同的,在某些情况下使用本地是有意义的。 实际上,在这

  • 问题内容: 是否可以在每个表的每个字段中搜索Oracle中的特定值? 有几百个表,有些表中有成千上万的行,因此我知道这可能需要很长时间才能查询。但是我唯一知道的是我要查询的字段的值是1/22/2008P09RR8。< 我已经尝试过使用以下语句根据我认为应命名的内容找到合适的列,但未返回任何结果。 这个数据库上绝对没有文档,我也不知道该字段是从哪里提取的。 有什么想法吗? 问题答案: 引用: 我已尝

  • 所以这是我以前在jooq 3.11中工作的查询。 我正在更新一个JSON字段,但是它使用Json绑定映射到我模型中的字符串,我将在下面发布 这在升级到jooq 3.13.2后不再有效。我还不得不将我的sql方言更改为mysql,即使我正在使用mysql 5_7数据库,这可能是问题所在? 我也试过这个,它还是一样的 JsonBinding.class JsonConverter.class 以下是j