开发者

JAX-WS and Joda-Time?

How do I write a JAX-WS service so the @WebParam of my @WebMethod is a Joda-Time class like DateTime? Will @XmlTypeAdapter on a parameter work? I'm deploying to GlassFish 2.1.

Let me clarify the question because both answers so far have focused on binding custom types to existing JAXB classes, which is related but not the question I'm asking. How do I make the following @WebService accept joda DateTime objects as parameters?

import javax.jws.WebMethod;
import javax.j开发者_运维知识库ws.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
    );

}


First write simple converter (to Calendar in this example, but can be easily changed to 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);
    }

}

Next you have to introduce your converter to JAXB (xjb file):

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

In the generated JAXB models xjc produced the following annotation:

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

Where Adapter2.class is a generated adapter that wraps your POJO converter. As you can see Calendar is used instead of clumsy javax.xml.datatype.XMLGregorianCalendar. If you adjust this example to Joda-Time, please share it with us.


You have to annotate the parameter directly such as below (I am making use of XSDDateTimeMarshaller written by @DennisTemper as one of the answers to your question but feel free to substitute with another one...) :

@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
    );
}


Well following solution template above

1.) Create an XSML Adapter

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.) Annotate jodatime attribute with (snipet from an entity class):

...

@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.) add type bindings to your 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>


Here's a non-annotation Joda solution. We have generated objects from xsd's and want them to use Joda instead of XmlGregorianCalendar.

Note: When I tried to pass a proper XmlGregorianCalendar object to the unmarshal methods in the classes, I got JaxB compiler errors that said it required type String, not XmlGregorianCalendar. Tested with String, and it appears to be working fine. Quick and dirty error handling here, so fix that up as you please.

Hope this helps.

Maven pom plugin snippet:

       <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-bindings.xml file:

<?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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜