2012-02-29 2 views
1

Я изучаю JAXB и хотел попробовать некоторые адаптеры. Когда я добавил один в мой очень простой класс, он вызвал вызов JAXBContext.newInstance(), чтобы вызвать исключение NullPointerException. Обратите внимание, что адаптер не является строго необходимым. Если я комментирую аннотацию @XmlJavaTypeAdapter (MapTypeAdaptor.class), код работает. Но это не помогает мне узнать, как использовать адаптеры ... Добавление MapType.class и MapTypeEntry.class в JAXBContext.getInstance() также не устраняет проблему.Добавление XMLAdapter вызывает NullPointerException в JAXBContext.newInstance метод

Я был бы очень признателен за любые советы о том, что я делаю неправильно. Благодаря!

Вот объект Java Я сортировочной:

import java.util.List; 
import java.util.Map; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 
import com.s5a.api.models.jaxb.MapTypeAdaptor; 

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlRootElement 
public class TestCollections { 

@XmlJavaTypeAdapter(MapTypeAdaptor.class) // <---Adding this line causes the error 
private Map<String, Object> oneColor; 
public Map<String, Object> getColor() { 
    return oneColor; 
} 
public void setColor(Map<String, Object> oneColor) { 
    this.oneColor = oneColor; 
} 

public List<String> getListOfColors() { 
    return listOfColors; 
} 

public void setListOfColors(List<String> listOfColors) { 
    this.listOfColors = listOfColors; 
} 

private List<String> listOfColors; 


} 

Вот адаптер:

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Map.Entry; 
import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class MapTypeAdaptor extends XmlAdapter<MapType, Map<String, Object>> { 

@Override 
public MapType marshal(Map<String, Object> map) throws Exception { 
    ArrayList<MapEntryType> entries = new ArrayList<MapEntryType>(); 
    MapType mapType = new MapType(); 
    if (map != null && map.entrySet() != null){ 
     for (Entry<String, Object> entry : map.entrySet()) { 
      MapEntryType mapEntryType = new MapEntryType(); 
      if (entry != null){ 
       mapEntryType.setKey(entry.getKey()); 
       mapEntryType.setValue(entry.getValue()); 
      } 
      entries.add(mapEntryType); 
     } 
     mapType.setEntries(entries); 
    } 
    return mapType; 
} 

@Override 
public Map<String, Object> unmarshal(MapType map) throws Exception { 
    HashMap<String, Object> hashMap = new HashMap<String, Object>(); 
    if (map != null){ 
     for (MapEntryType entryType : map.getEntries()) { 
      if (entryType != null){ 
       hashMap.put(entryType.getKey(), entryType.getValue()); 
      } 
     } 
    } 
    return hashMap; 
} 
} 

Вот класс MapType:

import java.util.ArrayList; 
import java.util.List; 

public class MapType { 

private List<MapEntryType> mapEntries = new ArrayList<MapEntryType>(); 

public List<MapEntryType> getEntries() { 
    return mapEntries; 
} 

public void setEntries(List<MapEntryType> mapEntries) { 
    this.mapEntries = mapEntries; 
} 
} 

А вот класс MapEntryType:

import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlValue; 

@XmlAccessorType(XmlAccessType.FIELD) 
public class MapEntryType { 

@XmlAttribute 
private String key; 
@XmlValue 
private Object value; 

public String getKey() { 
    return key; 
} 

public void setKey(String key) { 
    this.key = key; 
} 

public Object getValue() { 
    return value; 
} 

public void setValue(Object value) { 
    this.value = value; 
} 
} 

Наконец, мой блок тест:

@Test 
    public void shouldReturnXMLRepresentation() throws Exception { 

    TestCollections test = new TestCollections(); 
    HashMap<String, Object> color1 = new HashMap<String, Object>(); 
    color1.put("blue", new Integer(50)); 
    HashMap<String, Object> color2 = new HashMap<String, Object>(); 
    color2.put("red", "red is the 2nd color"); 
    ArrayList<Map<String, Object>> colors = new ArrayList<Map<String, Object>>(); 
    colors.add(color1); 
    colors.add(color2); 
    test.setColor(color1); 

    ArrayList<String> listofstrings = new ArrayList<String>(); 
    listofstrings.add("foo"); 
    listofstrings.add("bar"); 
    test.setListOfColors(listofstrings); 

    String xmlRepresentaion = genXML(test); 
    assertTrue(xmlRepresentaion != null); 
    assertTrue(xmlRepresentaion.length() > 0); 
} 

private String genXML(Object object) throws Exception{ 
StringWriter writer = new StringWriter(); 
try { 
      /* I tried the following, but it also throw an NPE 
      JAXBContext jc = JAXBContext.newInstance(TestCollections.class, MapType.class, MapTypeEntry.class); 
      */ 
    JAXBContext jc = JAXBContext.newInstance(TestCollections.class); //<-- NPE 
    Marshaller marshaller = jc.createMarshaller(); 
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
    marshaller.marshal(object, writer); 
}catch (Exception e){ 
    System.out.println("Error marshalling: " + e.getMessage()); 
    e.printStackTrace(System.out); 
    throw e; 
} 
System.out.println(writer.toString()); 
    return writer.toString(); 
} 
+0

Я заметил, что JAXBExceptions имеют «уникальный» формат, где e.toString() предоставляет вам информацию, которую e.getMessage() не делает. NPE почти наверняка вызвана некоторой другой ошибкой; у кого-то нет конструктора no-arg или что-то в этом роде. – kylewm

+0

Спасибо, Кайл, это хорошо знать, но в этом случае не было никакой новой информации. Метод toString() возвращает тот же NPE без дополнительного сообщения. – rzrelyea

+0

У меня такая же проблема ... Тип объекта Карта, похоже, проблема. Переход на карту исправил проблему. Тем не менее, я все еще ищу решение, так как я хотел бы прозрачно сериализовать различные типы, такие как String, Number, Date. – Raman

ответ

0

Если вам нужно хранить ценности объекта и готовы принять несколько иной вывод XML, вы можете изменить MapEntryType от:

@XmlAttribute 
private String key; 
@XmlValue 
private Object value; 

к:

@XmlElement 
private String key; 
@XmlElement 
private Object value; 

Это даст выход, как:

<entry> 
    <key>someKey</key> 
    <value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">someValue</value> 
</entry> 

вместо:

<entry key="someKey">someValue</entry> 

В качестве альтернативы, если вы можете изменить вашу карту от Map<String, Object> к Map<String, String>, то существующие классы должны работать.

Смежные вопросы