2011-07-25 22 views
7

Quiero convertir un HashMap en una clase POJO a XML. Intenté usar XmlAdapter, pero resulta que solo los pares clave y de valor de HashMap son los atributos de los Elementos XML. Necesito la clave para ser el elemento en sí y el valor de HashMap para ser el valor del elemento. Por ejemplo, necesito el siguiente XML:JAXB HashMap unmappable

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<cart> 
<supervisor_id>555</supervisor_id> 
<payments> 
    <payment sequence="1"> 
     <amount>123.45</amount> 
     <billing_method>12345</billing_method> 
     <form>card</form> 
     <delivery_mode>Q</delivery_mode> 
    </payment> 
<payment sequence="2"> 
     <amount>123.45</amount> 
     <person_id>2333</person_id> 
     <form>cash</form> 
     <delivery_mode>Q</delivery_mode> 
    </payment> 
</payments> 
</cart> 

que crearon las siguientes clases: MyMapType mantiene una lista de clase MyMapEntryType que tiene dos campos a saber de clave y valor. ¿Cómo cambio el elemento clave para que sea @XmlElement y asigne el campo de valor al campo Clave?


Aquí están mis archivos fuente.

MyMapType.java

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

public class MyMapType { 

    private List<MyMapEntryType> entry = new ArrayList<MyMapEntryType>(); 

    public List<MyMapEntryType> getEntry() { 
     return entry; 
    } 

    public void setEntry(List<MyMapEntryType> entry) { 
     this.entry = entry; 
    } 

} 

MyMapEntryType.java

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 MyMapEntryType { 

@XmlAttribute 
private String key; 
@XmlValue 
private String value; 
public String getKey() { 
    return key; 
} 
public void setKey(String key) { 
    this.key = key; 
} 
public String getValue() { 
    return value; 
} 
public void setValue(String value) { 
    this.value = value; 
} 
} 

favor también encontrar la clase de adaptador:

MyMapAdapter.java

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

public class MyMapAdapter extends XmlAdapter<MyMapType, Map<String, String>> { 

    @Override 
    public MyMapType marshal(Map<String, String> map) throws Exception { 

     MyMapType myMapType = new MyMapType(); 

     for(Entry<String, String> entry : map.entrySet()) { 
     MyMapEntryType myMapEntryType = new MyMapEntryType(); 
     myMapEntryType.setKey(entry.getKey()); 
     myMapEntryType.setValue(entry.getValue()); 
     myMapType.getEntry().add(myMapEntryType); 
     } 
     return myMapType; 
    } 

    @Override 
    public Map<String, String> unmarshal(MyMapType map) throws Exception { 
     HashMap<String, String> hashMap = new HashMap<String, String>(); 
     for(MyMapEntryType myEntryType : map.getEntry()) { 
     hashMap.put(myEntryType.getKey(), myEntryType.getValue()); 
     } 
     return hashMap; 
    } 
} 

Esta es la clase que tiene el campo HashMap:

XmlElementMap.java

@XmlAccessorType(XmlAccessType.FIELD) 
public class XmlElementMap { 

@XmlAttribute(name="sequence") 
private int sequence; 

@XmlJavaTypeAdapter(MyMapAdapter.class) 
private Map<String, String> map = new HashMap<String, String>(); 

public int getSequence() { 
    return sequence; 
} 

public void setSequence(int sequence) { 
    this.sequence = sequence; 
} 

public Map<String, String> getMap() { 
    return map; 
} 

public void setMap(Map<String, String> map) { 
    this.map = map; 
} 


} 


Por favor, asesorar sobre cómo lograr esto.

Saludos,
-Anand

Actualmente se produce el siguiente resultado:

Respuesta

14

tengo el mismo requisito "Necesito la clave para ser el mismo elemento y el valor de la HashMap a ser el valor del elemento ".

No utilicé un adaptador personalizado, sino que lo implementé convirtiendo dinámicamente las entradas de HashMap en una lista de objetos JAXBElement, y luego anoté la lista con @XmlAnyElement.

@XmlRootElement(name="root") 
public class MyMapType { 

    @XmlAnyElement 
    public List<JAXBElement> entries = new ArrayList<JAXBElement>(); 

    public MyMapType() { // JAXB required  
    } 

    public MyMapType(Map<String, String> map) { 
     for (Map.Entry<String, String> entry : map.entrySet()) { 
      entries.add(new JAXBElement(new QName(entry.getKey()), 
        String.class, entry.getValue())); 
     } 
    } 

    public static void main(String[] args) throws Exception { 
     JAXBContext context = JAXBContext.newInstance(MyMapType.class); 
     Marshaller marshaller = context.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

     Map<String, String> map = new LinkedHashMap<String, String>(); 
     map.put("key1", "value1"); 
     map.put("key2", "value2"); 
     MyMapType mt = new MyMapType(map); 

     marshaller.marshal(mt, System.out); 
    } 
} 

La salida es,

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<root> 
    <key1>value1</key1> 
    <key2>value2</key2> 
</root> 
+0

+1 para una solución de trabajo muy interesante e inesperada. – informatik01

+0

La solución más fácil hasta ahora que he visto. ¡Gracias! – sinu

+0

Esta es una buena solución para XML, pero lamentablemente MOXy parece no poder manejar esto correctamente cuando se combina con JSON en un método anotado JAX-RS.De alguna manera la Lista desencadena cálculo de referencias a una matriz JSON, por lo que el resultado se ve algo como esto: { "raíz": { "key1": [ "valor1"], "clave2": [ "valor2"], "key3": ["value3"] } } Estaría agradecido si alguien tiene una idea de cómo solucionar esto. –