2011-02-24 11 views
12

¿Cómo escribo un servicio JAX-WS para que @WebParam de mi @WebMethod sea una clase Joda-Time como DateTime? ¿Funcionará @XmlTypeAdapter en un parámetro? Me estoy desplegando en GlassFish 2.1.JAX-WS y Joda-Time?

Déjenme aclarar la pregunta porque ambas respuestas hasta ahora se han centrado en vincular tipos personalizados a las clases existentes de JAXB, lo cual está relacionado pero no con la pregunta que estoy formulando. ¿Cómo hago que @WebService acepte los objetos Joda DateTime como parámetros?

import javax.jws.WebMethod; 
import javax.jws.WebParam; 
import javax.jws.WebService; 
import javax.jws.soap.SOAPBinding; 
import org.joda.time.DateTime; 

@WebService 
@SOAPBinding(style = SOAPBinding.Style.RPC) 
public interface Resender { 
    @WebMethod 
    void resend(
      @WebParam(name = "start") DateTime start, 
      @WebParam(name = "end") DateTime end 
    ); 

} 

Respuesta

2

Hay que anotar el parámetro directamente como a continuación (estoy haciendo uso de XSDDateTimeMarshaller escrito por @DennisTemper como una de las responde a su pregunta, pero siéntase libre de sustituirlo por otro ...):

@WebService 
@SOAPBinding(style = SOAPBinding.Style.RPC) 
public interface Resender { 
    @WebMethod 
    void resend(
     @WebParam(name = "start") @XmlJavaTypeAdapter(type = DateTime.class, value = XSDDateTimeMarshaller.class) DateTime start, 
     @WebParam(name = "end") @XmlJavaTypeAdapter(type = DateTime.class, value = XSDDateTimeMarshaller.class) DateTime end 
    ); 
} 
9

Escribir simple convertidor (a Calendar en este ejemplo, pero se puede cambiar fácilmente a Joda-Time):

public class XsdDateTimeConverter { 

    public static Calendar unmarshal(String dateTime) { 
     final GregorianCalendar calendar = new GregorianCalendar(); 
     calendar.setTime(DatatypeConverter.parseDate(dateTime).getTime()); 
     return calendar; 
    } 

    public static String marshal(Calendar calendar) { 
     return DatatypeConverter.printDate(calendar); 
    } 

} 

Usted tiene que introducir su convertidor a JAXB (xjb archivo):

<globalBindings> 

    <javaType 
      name="java.util.Calendar" 
      xmlType="xs:dateTime" 
      parseMethod="XsdDateTimeConverter.unmarshal" 
      printMethod="XsdDateTimeConverter.marshal" 
      /> 
    <javaType 
      name="java.util.Calendar" 
      xmlType="xs:date" 
      parseMethod="XsdDateTimeConverter.unmarshal" 
      printMethod="XsdDateTimeConverter.marshal" 
      /> 
</globalBindings> 

En los modelos JAXB generados xjc produjeron la siguiente anotación:

@XmlJavaTypeAdapter(Adapter2.class) 
@XmlSchemaType(name = "date") 
protected Calendar date; 

Donde Adapter2.class es un adaptador generado que envuelve su convertidor POJO. Como puede ver, se usa Calendar en lugar del torpe javax.xml.datatype.XMLGregorianCalendar. Si ajustas este ejemplo a Joda-Time, por favor, compártelo con nosotros.

+1

Como estoy escribiendo las clases de Java a mano con las anotaciones de JAXB, supongo que no hay ningún problema yendo en dirección inversa y omitiendo el archivo xjb todos juntos? – jaxzin

+0

También otro punto, usted está reiterando los ejemplos fáciles de mapeo de campos de clase JAXB, pero mi pregunta era específicamente sobre los parámetros de un método expuesto como un servicio SOAP a través de anotaciones JAX-WS. ¿Tiene alguna experiencia o ejemplos de adaptación de tipo JAXB en ese contexto? – jaxzin

3

Bueno siguiente plantilla solución anterior

1.) Crear un adaptador XSML

import java.util.Date; 

import javax.xml.bind.annotation.XmlTransient; 
import javax.xml.bind.annotation.adapters.XmlAdapter; 

import org.joda.time.DateTime; 

@XmlTransient 
public class XSDDateTimeMarshaller extends XmlAdapter<Date, DateTime> { 

    @Override 
    public DateTime unmarshal(Date date) throws Exception { 
     return new DateTime(date.getTime()); 
    } 

    @Override 
    public Date marshal(DateTime dateTime) throws Exception { 
     return new Date(dateTime.getMillis()); 
    } 

} 

2.) Anotar JodaTime atributo con (snipet de una clase de entidad):

... 

@XmlRootElement(name="MyEntity", namespace="http://www.mycompany.com/module") 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(propOrder={"...", "...", "timeStamp", "...", "..."}) 
public class MyEntity 

...  

    @XmlElement(namespace="http://www.mysite.com/module") 
    @XmlJavaTypeAdapter(XSDDateTimeMarshaller.class) 

    @NotNull 
    @Type(type="org.joda.time.contrib.hibernate.PersistentDateTime") 
    @Column(name="TIME_STAMP") 
    private DateTime timeStamp; 

... 

} 

3 .) agregue tipos de enlaces a su myentity.xsd

<?xml version="1.0" encoding="UTF-8"?> 
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.w3.org/2001/XMLSchema http://www.w3.org/2001/XMLSchema.xsd" 
targetNamespace="http://www.mysite.com/module" 
xmlns:tns="http://www.mysite.com/module" 
attributeFormDefault="unqualified" 
elementFormDefault="qualified" 
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
jaxb:extensionBindingPrefixes="xjc" 
jaxb:version="2.1"> 
<xsd:annotation> 
    <xsd:appinfo> 
     <jaxb:globalBindings> 
      <jaxb:javaType name="org.joda.time.DateTime" 
       xmlType="xsd:dateTime" 
       parseMethod="com.mycompany.myproduct.marshaller.XSDDateTimeMarshaller.unmarshal" 
       printMethod="com.mycompany.myproduct.marshaller.XSDDateTimeMarshaller.marshal"/> 
      <jaxb:javaType name="org.joda.time.DateTime" 
       xmlType="tns:date" 
       parseMethod="com.mycompany.myproduct.marshaller.XSDDateTimeMarshaller.unmarshal" 
       printMethod="com.mycompany.myproduct.marshaller.XSDDateTimeMarshaller.marshal"/> 
     </jaxb:globalBindings> 
    </xsd:appinfo> 
</xsd:annotation> 

<xsd:element name="MyEntity" type="tns:MyEntity"/> 

<xsd:complexType name="MyEntity"> 
     <xsd:sequence> 
      ... 
      <xsd:element name="timeStamp" type="tns:date"/> 
      .... 
    </xsd:sequence> 
</xsd:complexType> 

<xsd:simpleType name="date"> 
    <xsd:restriction base="xsd:dateTime" /> 
</xsd:simpleType> 

</xsd:schema> 
+0

Consulte mi pregunta actualizada, no creo que la haya redactado correctamente cuando la escribí originalmente. – jaxzin

1

Aquí hay una solución Joda que no es de anotación. Hemos generado objetos de xsd y queremos que usen Joda en lugar de XmlGregorianCalendar.

Nota: Cuando traté de pasar un objeto XmlGregorianCalendar adecuado a los métodos unmarshal en las clases, obtuve errores del compilador JaxB que indicaban que era necesario el tipo String, no XmlGregorianCalendar. Probado con String, y parece estar funcionando bien. Aquí se maneja un error rápido y sucio, así que arregle eso como lo desee.

Espero que esto ayude.

Maven POM complemento fragmento:

 <plugin> 
      <groupId>org.jvnet.jaxb2.maven2</groupId> 
      <artifactId>maven-jaxb2-plugin</artifactId> 
      <configuration> 
       <schemaDirectory>src/main/resources/schemas/</schemaDirectory> 
       <removeOldOutput>true</removeOldOutput> 
      <bindingIncludes> 
      <bindingInclude>jaxb-custom-bindings.xml</bindingInclude> 
      </bindingIncludes> 
      </configuration> 
      <executions> 
      <execution> 
       <goals> 
       <goal>generate</goal> 
       </goals> 
      </execution> 
      </executions> 
     </plugin> 

JAXB-custom-fijaciones.archivo xml:

<?xml version="1.0" encoding="UTF-8"?> 
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" 
     version="2.0" 
     xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

<globalBindings> 
    <javaType 
      name="org.joda.time.DateTime" 
      xmlType="xs:dateTime" 
      parseMethod="com.yourcompanyname.XSDDateTimeToJodaDateTimeMarshaller.unmarshal" 
      printMethod="com.yourcompanyname.XSDDateTimeToJodaDateTimeMarshaller.marshal" 
      /> 
    <javaType 
      name="org.joda.time.LocalDate" 
      xmlType="xs:date" 
      parseMethod="com.yourcompanyname.XSDDateToJodaLocalDateMarshaller.unmarshal" 
      printMethod="com.yourcompanyname.XSDDateToJodaLocalDateMarshaller.marshal" 
      /> 
</globalBindings> 

public class XSDDateTimeToJodaDateTimeMarshaller { 

private static final Logger LOG = LoggerFactory.getLogger(XSDDateTimeToJodaDateTimeMarshaller.class); 

public static DateTime unmarshal(String xmlGregorianCalendar) { 
    DateTime result= new DateTime(xmlGregorianCalendar); 
    return result; 
} 

public static String marshal(DateTime dateTime) { 
    String result = "MARSHALLING_ERROR"; 
    try { 
     result = DatatypeFactory.newInstance().newXMLGregorianCalendar(dateTime.toGregorianCalendar()).toXMLFormat(); 
    } catch (DatatypeConfigurationException e) { 
     LOG.error("Error marshalling Joda DateTime to xmlGregorianCalendar",e); 
    } 
    return result; 
} 

}

public class XSDDateToJodaLocalDateMarshaller { 
private static final Logger LOG = LoggerFactory.getLogger(XSDDateToJodaLocalDateMarshaller.class); 


public static LocalDate unmarshal(String xmlGregorianCalendar) { 
    return new LocalDate(xmlGregorianCalendar); 
} 

public static String marshal(LocalDate localDate) { 
    String result = "MARSHALLING_ERROR"; 
    try { 
     result = DatatypeFactory.newInstance().newXMLGregorianCalendar(localDate.toDateTimeAtStartOfDay().toGregorianCalendar()).toXMLFormat(); 
    } catch (DatatypeConfigurationException e) { 
     LOG.error("Error marshalling Joda LocalDate to xmlGregorianCalendar",e); 
    } 
    return result; 
} 
} 
+0

Gracias por intentarlo, pero estoy buscando una respuesta a la pregunta tal como se establece, un (a) servicio web que puede aceptar objetos Joda DateTime como (en) WebParams. – jaxzin

+0

La etiqueta está en el lugar incorrecto, al menos para el complemento maven actual. Consulte [maven-cxf-codegen-plugin] (https://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html) para ver ejemplos de trabajo. Va dentro de pero el XML de varias líneas no funciona con comentarios. –

Cuestiones relacionadas