2011-07-28 16 views

Respuesta

18

¡Esta es una muy buena pregunta!

La respuesta corta es que no , utilizando setAdapter en marshaller/unmarshaller no quiere decir que usted no tiene que utilizar @XmlJavaTypeAdapter.

Déjenme explicar esto con un escenario hipotético (¡pero válido!).

tener en cuenta en una aplicación web, uno va a buscar un evento en forma de XML que tiene la siguiente esquema:

<xs:element name="event" > 
    <xs:complexType> 
     <xs:sequence> 
      <!-- Avoiding other elements for concentrating on our adapter --> 
      <xs:element name="performedBy" type="xs:string" /> 
     </xs:sequence> 
    </xs:complexType> 
</xs:element> 

Equivalente a esto, el modelo se verá así:

@XmlRootElement(name="event") 
@XmlType(name="") 
public class Event { 

    @XmlElement(required=true) 
    protected String performedBy; 
} 

Ahora la aplicación ya tiene un bean llamado User que mantiene la información detallada sobre el usuario.

public class User { 

    private String id; 
    private String firstName; 
    private String lastName; 

    .. 
} 

Tenga en cuenta que este User no se conoce a su contexto JAXB. Para simplificar, tenemos el usuario como POJO, pero puede ser cualquier clase válida de Java.

Lo que quiere es arquitecto de aplicaciones Event 's performedBy deben estar representados como User para ganar más detalles.

Aquí es donde entra en el cuadro @XmlJavaTypeAdapter

JAXBContext es consciente de performedBy como xs:string, pero tiene que ser representado como User en la memoria en Java.

modelo modificado se ve así:

@XmlRootElement(name="event") 
@XmlType(name="") 
public class Event { 

    @XmlElement(required=true) 
    @XmlJavaTypeAdapter(UserAdapter.class) 
    protected User performedBy; 
} 

UserAdapter.java:

public class UserAdapter extends XmlAdapter<String, User> { 

    public String marshal(User boundType) throws Exception { 
      .. 
    } 

    public User unmarshal(String valueType) throws Exception { 
      .. 
    } 
} 
definición

El adaptador de dice que -

  1. BoundType es usuario (En representación Memeory)
  2. ValueType es String (El Contexto tipo de datos JAXB es consciente de)

Regresar a su pregunta -

Me resulta algo redundante.

Por cierto, algunosMarshaller.setAdapter (...) parecen no hacer nada.

Considere que nuestro Adaptador requiere una clase llamada UserContext para organizar/desenmascarar con éxito.

public class UserAdapter extends XmlAdapter<String, User> { 

    private UserContext userContext; 

    public String marshal(User boundType) throws Exception { 
      return boundType.getId(); 
    } 

    public User unmarshal(String valueType) throws Exception { 
      return userContext.findUserById(valueType); 
    } 
} 

Ahora la pregunta es cómo va a ir a buscar un UserAdapter se instace de UserContext ?? Como un buen diseño siempre se debe suministrarla al tiempo que ha consiguió una instancia ..

public class UserAdapter extends XmlAdapter<String, User> { 

    private UserContext userContext; 

    public UserAdapter(UserContext userContext) { 
     this.userContext = userContext; 
    } 

    public String marshal(User boundType) throws Exception { 
      return boundType.getId(); 
    } 

    public User unmarshal(String valueType) throws Exception { 
      return userContext.findUserById(valueType); 
    } 
} 

Pero JAXB tiempo de ejecución sólo puede aceptar adaptadores sin-args constructor .. (Obviamente JAXBContext no sabe nada de modelo específico de la aplicación)

Así que por suerte no es una opción: D

Usted puede decirle a su unmarshaller utilizar instancia dada de UserAdapter en lugar de la creación de instancias que por su propia cuenta.

public class Test { 

public static void main(String... args) { 
    JAXBContext context = JAXBContext.getInstance(Event.class); 
    Unmarshaller unmarshaller = context.createUnmarshaller(); 

     UserContext userContext = null; // fetch it from some where 
     unmarshaller.setAdapter(UserAdapter.class, new UserAdapter(userContext)); 

     Event event = (Event) unmarshaller.unmarshal(..); 
    } 
} 

setAdapter método está disponible tanto en Marshaller & Unmarshaller

Nota:

  1. setAdapter en marshaller/unmarshaller no quiere decir que usted no tiene que utilizar @XmlJavaTypeAdapter.

    @XmlRootElement(name="event") 
    @XmlType(name="") 
    public class Event { 
    
        @XmlElement(required=true) 
        // @XmlJavaTypeAdapter(UserAdapter.class) 
        protected User performedBy; 
    } 
    

    Si se omite este tiempo de ejecución JAXB no tiene ni idea de que su usuario está Tipo Bound & Tipo Valor es otra cosa. Se tratará de reunir User como es & u será llegar a tener mal xml (o la validación falla si está habilitado)

  2. Si bien hemos tomado un escenario en el que se requiere adaptador para estar con argumentos, por lo tanto, uso setAdapter método.

    Algunos usos adavanced también están allí, donde en incluso si usted tiene defecto sin argumentos del constructor, sin embargo, que proporcionan una instancia del adaptador

    mayo de este adaptador está configurado con los datos, que Mariscal/operación unmarshal está utilizando !

+11

** Así respuesta corta es no ** No se puede utilizar sin necesidad de utilizar XmlAdapter anotación @xmlJavaTypeAdapter. – user1128134

5

Puede utilizar el package-info.java

Eso se llama "nivel de paquete".

Ejemplo: ponga un paquete-info.java en el mismo paquete que la clase que desea ordenar/deshacer.

Supongamos que tiene una clase mypackage.model.A y un adaptador CalendarAdapter en mypackage.adapter. declarar un archivo que contiene package-info.java en mypackage.model:

@XmlJavaTypeAdapters({ 
    @XmlJavaTypeAdapter(value = CalendarAdapter.class, type = Calendar.class) 
}) 
package mypackage.model; 

import java.util.Calendar; 
import mypackage.adapter.CalendarAdapter; 

Todo campo de tipo de calendario en la clase A se marshalled o unmarshalled con el CalendarAdapter.

Puede encontrar informaciones útiles que hay: http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html

Cuestiones relacionadas