本文介绍了当使用MOXy的元数据与实现java.util.Map的类时,NPE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

情况

The situation

我正在使用EclipseLink的MOXy,我正在尝试将外部OX映射XML与实现地图界面但是,每次尝试创建一个JAXBContext时,我会得到以下NPE:

I'm using EclipseLink's MOXy and I'm trying to use the external OX mapping XML with classes that implement the Map interface. However, every time I try create a JAXBContext, I get the following NPE:

Caused by: javax.xml.bind.JAXBException
 - with linked exception:
[java.lang.NullPointerException]
    at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:832)
    at org.eclipse.persistence.jaxb.JAXBContext.<init>(JAXBContext.java:143)
    at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:142)
    at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:129)
    at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:93)
    at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:83)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:210)
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:336)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
    at com.example.MOXyOXTest<clinit>(MOXyOXTest.java:59)
Caused by: java.lang.NullPointerException
    at org.eclipse.persistence.jaxb.compiler.XMLProcessor.processXML(XMLProcessor.java:202)
    at org.eclipse.persistence.jaxb.compiler.Generator.<init>(Generator.java:145)
    at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:829)

详细信息

只有当被映射的类实现java.util.Map接口时,才会出现此问题。如果我映射的类不实现该接口,一切都可以正常工作。以下是我试图映射的类的简化示例:

This problem only occurs if the class being mapped implements the java.util.Map interface. If the class I'm mapping does not implement that interface, everything works fine. Here's a simplified example of a class I'm trying to map:

package com.example;

import java.util.Map;

// This class just wraps a java.util.HashMap
import com.xetus.lib.type.DelegatedMap;

public class SampleClassA extends DelegatedMap<String, Object>{

    public SampleClassA(){
        super();
    }

    public SampleClassA(Map<String, Object> m){
        super(m);
    }

    public void setSomeProperty(String value){
        put("somevalue", value);
    }

    public String getSomeProperty(){
        return (String) get("somevalue");
    }
}

以下是MOXy OX元数据的简化示例我想使用:

Here is a simplified sample of the MOXy OX meta data I'd like to use:

<?xml version="1.0"?>
<xml-bindings
  xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
  package-name="com.example"
  xml-mapping-metadata-complete="true"> 
  <java-types>
  <java-type name="SampleClassA" xml-accessor-type="NONE">
   <xml-root-element name="SAMPLE" />
    <java-attributes>
     <xml-attribute type="java.lang.String" name="SomeProperty" required="true">
     <xml-access-methods get-method="getSomeProperty" set-method="setSomeProperty"/>
    </xml-attribute>
   </java-attributes>
  </java-type>
 </java-types>
</xml-bindings>

这是我如何创建我的JAXBContext

Here is how I'm creating my JAXBContext

Map<String, Object> props = new HashMap<String, Object>(1);
List bindings = new ArrayList(1);
bindings.add(new StreamSource(MOXyOXTest.class.getResourceAsStream("test-mappings.xml")));
props.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, bindings);

cntxt = JAXBContext.newInstance(new Class[] { SampleClassA.class }, props);

我使用EclipseLink版本2.3.2,万一这很重要。我也试过版本2.2.1,结果相同。

I'm using EclipseLink version 2.3.2, in case that's important. I've also tried with version 2.2.1 with the same results.

我的问题

这是我第一次尝试在实现java.util.Map接口的类上使用JAXB,如果我缺少一些基本的东西,我很好奇。我不希望OX映射使用地图的名称/值对,而是添加到类中的自定义getter和setter。

This the first time I've tried to use JAXB on a class that implements the java.util.Map interface and I'm curious if I'm missing something fundamental. I don't expect the OX Mappings to work with the Map's name/value pairs, but instead with the custom getters and setters added to the class.

是一个配置,如这应该工作?

Is a configuration like this supposed to work?

其他详细信息


  1. 示例代码中使用的DelegatedMap不会扩展 java.util.HashMap,它只包含一个实例,并实现Map接口。此外,该类用@XmlAccessorType(XmlAccessType.NONE)注释。

  2. 无论使用哪个抽象类,我使用了SampleClassA,都会得到相同的错误。如果SampleClassA扩展了一个不实现地图的类,那么所有的行为都是正确的。

  3. 我正在使用的代码库需要许多类来实现Map接口。
  1. The DelegatedMap used in the sample code does not extend java.util.HashMap, it just wraps an instance of one and implements the Map interface. Also, that class is annotated with @XmlAccessorType(XmlAccessType.NONE).
  2. I get the same error regardless of which abstract class that implements the Map interface I use for SampleClassA. If SampleClassA extends a class that does not implement a map, everything behaves correctly.
  3. The code base I'm working with requires many of the classes to implement the Map interface.


推荐答案

注意:我是,并且是专家组

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

这是一个非常有趣的用例。 JAXB(JSR-222)具有映射和域对象的表示形式,因此它可以考虑混合对象的行为方式。我添加了以下增强请求来介绍它的支持:

This is a very interesting use case. JAXB (JSR-222) has representations for maps and domain objects, so it is intersting to consider how a hybrid object should behave. I have added the following enhancement request to introduce support for it:



  • http://bugs.eclipse.org/37640

更新

我们刚刚完成了此增强功能。您可以从2012年4月19日起使用EclipseLink 2.4.0每晚下载开始尝试使用:

We have just finished implementing this enhancement. You can try it out using an EclipseLink 2.4.0 nightly download start on April 19, 2012 from the following location:



  • http://www.eclipse.org/eclipselink/downloads/nightly.php

修复涉及利用超类型属性来指定超类型以覆盖真实超级型。 超级类型属性之前仅被我们的

The fix involves leveraging the super-type property to specify a super type to override the real super type. The super-type property was previously only leveraged by our dynamic JAXB support.

bindings.xml

<?xml version="1.0"?>
<xml-bindings 
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum10075634">
    <java-types>
        <java-type name="SampleClassA" super-type="java.lang.Object" xml-accessor-type="NONE">
            <xml-root-element name="SAMPLE" />
            <java-attributes>
                <xml-attribute java-attribute="someProperty" name="SomeProperty" required="true"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

DelegatedMap

以下是您的问题中描述的 DelegatatedMap 类的实现。

Below is an implementation of the DelegatatedMap class as described in your question.

package forum10075634;

import java.util.*;

public class DelegatedMap<K,V> implements Map<K,V> {

    private Map<K,V> map;

    public DelegatedMap() {
        map = new HashMap<K,V>();
    }

    public DelegatedMap(Map<K,V> map) {
        this.map = map;
    }

    public void clear() {
        map.clear();
    }

    public boolean containsKey(Object key) {
        return map.containsKey(key);
    }

    public boolean containsValue(Object value) {
        return map.containsValue(value);
    }

    public Set<java.util.Map.Entry<K, V>> entrySet() {
        return map.entrySet();
    }

    public V get(Object key) {
        return map.get(key);
    }

    public boolean isEmpty() {
        return map.isEmpty();
    }

    public Set<K> keySet() {
        return map.keySet();
    }

    public V put(K key, V value) {
        return map.put(key, value);
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        map.putAll(m);
    }

    public V remove(Object key) {
        return map.remove(key);
    }

    public int size() {
        return map.size();
    }

    public Collection<V> values() {
        return map.values();
    }

}

SampleClassA

package forum10075634;

import java.util.Map;

public class SampleClassA extends DelegatedMap<String, Object> {

    public SampleClassA() {
        super();
    }

    public SampleClassA(Map<String, Object> m) {
        super(m);
    }

    public void setSomeProperty(String value) {
        put("somevalue", value);
    }

    public String getSomeProperty() {
        return (String) get("somevalue");
    }

}

jaxb.properties

要指定MOXy作为您的JAXB提供程序,您需要在...中添加一个名为 jaxb.properties 的文件与您的域类相同的包含以下条目:

To specify MOXy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain classes with the following entry:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

演示

package forum10075634;

import java.io.StringReader;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>(1);
        properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum10075634/bindings.xml");
        JAXBContext jc = JAXBContext.newInstance(new Class[] {SampleClassA.class}, properties);

        StringReader xml = new StringReader("<SAMPLE SomeProperty='Foo'/>");
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        SampleClassA sampleClassA = (SampleClassA) unmarshaller.unmarshal(xml);

        System.out.println(sampleClassA.getSomeProperty());
        System.out.println(sampleClassA.get("somevalue"));

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(sampleClassA, System.out);
    }

}

输出

Foo
Foo
<?xml version="1.0" encoding="UTF-8"?>
<SAMPLE SomeProperty="Foo"/>

这篇关于当使用MOXy的元数据与实现java.util.Map的类时,NPE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!