JAX-WS和Joda-Time?

时间:2011-02-24 15:51:11

标签: java soap jax-ws jodatime

如何编写JAX-WS服务,以便@WebMethod的@WebParam是像DateTime这样的Joda-Time类?参数上的@XmlTypeAdapter会起作用吗?我正在部署到GlassFish 2.1。

让我澄清一下这个问题,因为到目前为止这两个答案都集中在将自定义类型绑定到现有的JAXB类上,这与我要问的问题有关。如何使以下@WebService接受joda DateTime对象作为参数?

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

}

4 个答案:

答案 0 :(得分:9)

首先编写简单转换器(在此示例中为Calendar,但可以轻松更改为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);
    }

}

接下来,您必须将转换器引入JAXB(xjb文件):

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

在生成的JAXB模型中,xjc生成了以下注释:

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

其中Adapter2.class是包装POJO转换器的生成适配器。如您所见,Calendar被用来代替笨拙的javax.xml.datatype.XMLGregorianCalendar。如果您将此示例调整为Joda-Time,请与我们分享。

答案 1 :(得分:3)

以上解决方案模板

1。)创建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。)使用(来自实体类的snipet)注释jodatime属性:

...

@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.。)将类型绑定添加到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>

答案 2 :(得分:3)

您必须直接注释参数,例如下面的内容(我正在使用@DennisTemper编写的XSDDateTimeMarshaller作为您问题的答案之一,但可以替换为另一个......):

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

答案 3 :(得分:1)

这是一个非注释Joda解决方案。我们已经从xsd生成了对象,并希望它们使用Joda而不是XmlGregorianCalendar。

注意:当我尝试将正确的XmlGregorianCalendar对象传递给类中的unmarshal方法时,我得到了JaxB编译器错误,表示它需要类型String,而不是XmlGregorianCalendar。用String测试,它似乎工作正常。这里处理快速而肮脏的错误,所以请随意修复。

希望这有帮助。

Maven pom插件片段:

       <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文件:

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