2011-10-21 15 views
8

Esta es mi situación. Tengo una clase genérica:Campo duplicado en XML generado utilizando JAXB

public class Tuple<T> extends ArrayList<T> { 
    //... 
    public Tuple(T ...members) { 
    this(Arrays.asList(members)); 
    } 

    @XmlElementWrapper(name = "tuple") 
    @XmlElement(name = "value") 
    public List<T> getList() { 
    return this; 
    } 
} 

Y una clase hija:

public class StringTuple extends Tuple<String> { 
    public StringTuple(String ...members) { 
    super(members); 
    } 

    //explanation of why overriding this method soon ... 
    @XmlElementWrapper(name = "tuple") 
    @XmlElement(name = "value") 
    @Override 
    public List<String> getList() { 
    return this; 
    } 
} 

se hace referencia a estas clases aquí:

@XmlRootElement(namespace = "iv4e.xml.jaxb.model") 
public class Relation { 
    private Tuple<StringTuple> relationVars; 
    //... 
    @XmlElementWrapper(name = "allRelationVars") 
    @XmlElement(name = "relationVarsList") 
    public Tuple<StringTuple> getRelationVars() { 
    return relationVars; 
    } 
} 

A continuación, un objeto Relation se crea con algo como:

Relation rel = new Relation(); 
rel.setRelationVars(new Tuple<StringTuple>(
    new StringTuple("RelationshipVar1"), new StringTuple("RelationshipVar2"))); 

Después de ordenar este objeto, la salida XML es el siguiente:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ns2:relation xmlns:ns2="iv4e.xml.jaxb.model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=""> 

    <allRelationVars> 
    <relationVarsList> 
     <tuple> 
      <value xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">RelationshipVar1</value> 
     </tuple> 
     <tuple> 
      <value>RelationshipVar1</value> 
     </tuple> 
    </relationVarsList> 
    <relationVarsList> 
     <tuple> 
      <value xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">RelationshipVar2</value> 
     </tuple> 
     <tuple> 
      <value>RelationshipVar2</value> 
     </tuple> 
    </relationVarsList> 
    </allRelationVars> 

</ns2:relation> 

Así que los elementos están duplicados value !.

Ahora, la razón por la StringTuple clase anula List<T> getList() con List<String> getList() es evitar los molestos generados xmlns:xs atributos de todos los miembros de la lista (los value elementos del documento XML). Pero luego cada miembro de la lista se muestra dos veces en la salida. Aparentemente, es porque tanto el método padre anulado como el método secundario están anotados con @XmlElement. Así que mi pregunta principal es: ¿hay una forma de ignorar los métodos anotados anotados con @XmlElement en Jaxb? (teniendo en cuenta que el método de anulación también está anotado con @XmlElement)

Encontré una publicación anterior que informaba sobre un problema bastante similar: http://old.nabble.com/@XmlElement-on-overridden-methods-td19101616.html, pero no encontré ninguna solución todavía. También tenga en cuenta que agregar una anotación @XmlTransient al método getList en la clase principal (Tuple<T>) podría resolver este problema pero generará otros, ya que la clase padre no es abstracta y se usa sola en otros contextos.

Pregunta secundaria de un lado: ¿es posible declarar el atributo xmlns:xs en el nodo raíz en lugar de mostrarlo -annoyingly- en cada nodo donde se necesita? Sé que esto se puede hacer con la clase NamespacePrefixMapper, pero como es una clase interna SUN no estándar, prefiero usar un enfoque más independiente de la implementación.

¡Gracias de antemano por cualquier comentario!

+1

Antes de llegar demasiado lejos en este problema, sus objetos de dominio necesitan extender 'ArrayList'? ¿Por qué 'Tuple' extiende' ArrayList' en lugar de tener una propiedad de tipo 'ArrayList'? –

+0

¡Hola, Blaise !, elegí heredar de ArrayList ya que mi objeto Tuple es, de hecho, una ArrayList. Sin embargo, podría vivir con un ArrayList en su lugar, aunque tendría que implementar algunos métodos de delegación. De todos modos, eso no resolvería mi problema, ya que todavía tendría una clase genérica Tuple y un StringTuple extendiendo Tuple . – Sergio

+0

He agregado una respuesta con un enfoque que podría usarse para deshacerse de la declaración 'xsi: type'. –

Respuesta

3

podría utilizar el siguiente enfoque de marcar la propiedad @XmlTransient en la matriz y @XmlElement en el niño:

Padres

package forum7851052; 

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

import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.XmlTransient; 

@XmlRootElement 
public class Parent<T> { 

    private List<T> item = new ArrayList<T>(); 

    @XmlTransient 
    public List<T> getItem() { 
     return item; 
    } 

    public void setItem(List<T> item) { 
     this.item = item; 
    } 

} 

IntegerChild

package forum7851052; 

import java.util.List; 

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class IntegerChild extends Parent<Integer> { 

    @Override 
    @XmlElement 
    public List<Integer> getItem() { 
     return super.getItem(); 
    } 

    @Override 
    public void setItem(List<Integer> item) { 
     super.setItem(item); 
    } 

} 

StringC Hild

package forum7851052; 

import java.util.List; 

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class StringChild extends Parent<String> { 

    @Override 
    @XmlElement 
    public List<String> getItem() { 
     return super.getItem(); 
    } 

    @Override 
    public void setItem(List<String> item) { 
     super.setItem(item); 
    } 

} 

demostración

package forum7851052; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(Parent.class, IntegerChild.class, StringChild.class); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

     IntegerChild integerChild = new IntegerChild(); 
     integerChild.getItem().add(1); 
     integerChild.getItem().add(2); 
     marshaller.marshal(integerChild, System.out); 

     StringChild stringChild = new StringChild(); 
     stringChild.getItem().add("A"); 
     stringChild.getItem().add("B"); 
     marshaller.marshal(stringChild, System.out); 
    } 

} 

salida

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<integerChild> 
    <item>1</item> 
    <item>2</item> 
</integerChild> 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<stringChild> 
    <item>A</item> 
    <item>B</item> 
</stringChild> 
+0

¿Qué pasa si el elemento primario también se utiliza en la serialización (haciendo que el campo transitorio del padre no sea una opción)? Ese debería ser un caso absolutamente válido, pero JAXB parece ingore @Override anotaciones. – stuchl4n3k

2

Esto podría ser bastante viejo, pero es el primer resultado, mientras que la búsqueda de "JAXB duplicar campos"

topamos con el mismo problema, esto hizo el truco para mí:

@XmlRootElement 
@XmlAccessorType(XmlAccessType.NONE) // <-- made the difference 
public abstract class ParentClass 
{ 
... 
} 


@XmlRootElement 
public class ChildClass extends ParentClass 
{ 
... 
} 
Cuestiones relacionadas