2012-04-09 2 views
4

Die SituationNPE, wenn sie mit einer Klasse moxy Meta-Daten verwenden, die java.util.Map implementiert

I Eclipse des moxy bin mit und ich versuche, das extern OX-Mapping XML mit Klassen zu verwenden, die die Umsetzung Kartenschnittstelle jedes Mal, wenn ich versuche, eine JAXBContext jedoch erstellen, bekomme ich folgende 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) 

Einzelheiten

Dieses Problem tritt nur, wenn die Klasse zugeordnet werden, um den java.util.Map-Schnittstelle implementiert. Wenn die Klasse, die ich kartiere, diese Schnittstelle nicht implementiert, funktioniert alles einwandfrei. Hier ist ein vereinfachtes Beispiel einer Klasse I zu kartieren sind versucht:

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

Hier ist ein vereinfachtes Beispiel der Meta-Daten moxy OX Ich mag würde verwenden:

<?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> 

Hier ist, wie ich Ich erstelle meinen JAXBContext

Ich benutze EclipseLink Version 2.3.2, falls das wichtig ist. Ich habe auch mit Version 2.2.1 mit den gleichen Ergebnissen versucht.

Meine Frage

dies das erste Mal, dass ich versucht habe, JAXB auf eine Klasse zu verwenden, die die java.util.Map-Schnittstelle implementiert, und ich bin gespannt, ob ich grundlegende etwas fehlt bin. Ich erwarte nicht, dass die OX-Zuordnungen mit den Name/Wert-Paaren der Map arbeiten, sondern stattdessen mit den benutzerdefinierten Gettern und Settern, die der Klasse hinzugefügt werden.

Soll eine Konfiguration wie diese funktionieren?

Weitere Details

  1. Die DelegatedMap in dem Beispielcode verwendet erstreckt sich nicht java.util.HashMap, es wickelt nur eine Instanz ein und implementiert die Map-Schnittstelle. Außerdem ist diese Klasse mit @ XmlAccessorType (XmlAccessType.NONE) gekennzeichnet.
  2. Ich bekomme den gleichen Fehler, unabhängig davon, welche abstrakte Klasse die Map-Schnittstelle implementiert, die ich für SampleClassA verwende. Wenn SampleClassA eine Klasse erweitert, die keine Map implementiert, verhält sich alles korrekt.
  3. Die Codebasis, mit der ich arbeite, erfordert viele der Klassen, um die Map-Schnittstelle zu implementieren.

Antwort

2

Hinweis: Ich bin das EclipseLink JAXB (MOXy) Blei und Mitglied der JAXB (JSR-222) Expertengruppe.

Dies ist ein sehr interessanter Anwendungsfall. JAXB (JSR-222) hat Darstellungen für Maps und Domain-Objekte, daher ist es interessant zu überlegen, wie sich ein hybrides Objekt verhalten soll.


UPDATE

Wir haben die Umsetzung diese Erweiterung gerade beendet: Ich habe den folgenden Verbesserungsvorschlag zur Einführung Unterstützung hinzugefügt. Sie können es versuchen, am April eines Eclipse 2.4.0 nächtlichen Download-Start mit 19 2012 unter der folgenden Adresse:

Das Update beinhaltet die super-type Eigenschaft nutzen einen Supertyp angeben überschreiben Sie den echten Super-Typ. Die super-type Eigenschaft wurde bisher nur von unserer dynamic JAXB Unterstützung genutzt.

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

Im Folgenden finden Sie eine Implementierung der DelegatatedMap Klasse wie in Ihrer Frage beschrieben.

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

Um moxy als JAXB-Provider angeben müssen Sie eine Datei jaxb.properties im selben Paket wie Ihre Domain Klassen aufgerufen hinzuzufügen mit der folgende Eintrag:

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

Demo

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

} 

Ausgabe

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

Vielen Dank für in diese suchen. Ich versuche jetzt deinen Vorschlag und ich werde dich wissen lassen, wie es geht. – Terence

+0

@Terence - Der Vorschlag, den ich gab, funktioniert nicht, ich zeigte nur die Konfiguration für den geplanten Fix. –

+0

Ahh, ok. Das erklärt die NPE, in die ich gerannt bin. Ich hätte deinen Beitrag sorgfältiger lesen sollen! – Terence