2011-05-29 118 views
3

我一直在我的Web服务的JAXB绑定中遇到问题几个小时:XmlAdapter到JAXB绑定Joda时间间隔?

为了准备一个更大的Web服务,它必须返回Joda时间类实例(即时,持续时间,间隔等),我已经开始与只有一个方法返回的区间中的Web服务:

package jodaws; 

import javax.jws.WebService; 
import javax.xml.ws.Endpoint; 

import org.joda.time.Interval; 

@WebService(name = "JodaWS") 
public class JodaWebService { 

    public Interval readInterval() { 
     return new Interval(30, 40); 
    } 

    public static void main(String[] args) { 
     Endpoint.publish("http://localhost:10100/JodaWS", new JodaWebService()); 
    } 
} 

发布此Web服务,我收到一个异常,指出“org.joda.time.Interval没有一个不-arg默认构造函数“:

29.05.2011 17:24:07 com.sun.xml.internal.ws.model.RuntimeModeler getRequestWrapperClass 
INFO: Dynamically creating request wrapper Class jodaws.jaxws.ReadInterval 
29.05.2011 17:24:07 com.sun.xml.internal.ws.model.RuntimeModeler getResponseWrapperClass 
INFO: Dynamically creating response wrapper bean Class jodaws.jaxws.ReadIntervalResponse 
Exception in thread "main" javax.xml.ws.WebServiceException: Unable to create JAXBContext 
    at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:153) 
    at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.postProcess(AbstractSEIModelImpl.java:83) 
    at com.sun.xml.internal.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:244) 
    at com.sun.xml.internal.ws.server.EndpointFactory.createSEIModel(EndpointFactory.java:312) 
    at com.sun.xml.internal.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:178) 
    at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:456) 
    at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:475) 
    at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.createEndpoint(EndpointImpl.java:213) 
    at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(EndpointImpl.java:143) 
    at com.sun.xml.internal.ws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:102) 
    at javax.xml.ws.Endpoint.publish(Endpoint.java:170) 
    at jodaws.JodaWebService.main(JodaWebService.java:17) 
Caused by: java.security.PrivilegedActionException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions 
org.joda.time.Interval does not have a no-arg default constructor. 
    this problem is related to the following location: 
     at org.joda.time.Interval 
     at public org.joda.time.Interval jodaws.jaxws.ReadIntervalResponse._return 
     at jodaws.jaxws.ReadIntervalResponse 
org.joda.time.base.BaseInterval does not have a no-arg default constructor. 
    this problem is related to the following location: 
     at org.joda.time.base.BaseInterval 
     at org.joda.time.Interval 
     at public org.joda.time.Interval jodaws.jaxws.ReadIntervalResponse._return 
     at jodaws.jaxws.ReadIntervalResponse 

    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:140) 
    ... 11 more 
Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions 
org.joda.time.Interval does not have a no-arg default constructor. 
    this problem is related to the following location: 
     at org.joda.time.Interval 
     at public org.joda.time.Interval jodaws.jaxws.ReadIntervalResponse._return 
     at jodaws.jaxws.ReadIntervalResponse 
org.joda.time.base.BaseInterval does not have a no-arg default constructor. 
    this problem is related to the following location: 
     at org.joda.time.base.BaseInterval 
     at org.joda.time.Interval 
     at public org.joda.time.Interval jodaws.jaxws.ReadIntervalResponse._return 
     at jodaws.jaxws.ReadIntervalResponse 

    at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91) 
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:436) 
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:277) 
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1100) 
    at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:143) 
    at com.sun.xml.internal.bind.api.JAXBRIContext.newInstance(JAXBRIContext.java:95) 
    at com.sun.xml.internal.ws.developer.JAXBContextFactory$1.createJAXBContext(JAXBContextFactory.java:97) 
    at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:148) 
    at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:140) 
    ... 13 more 

所以我读过一些教程等,最终写我自己的XmlAdapter为区间类 - 第一个实现返回有效,但常数值:

package jodaws; 

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

import org.joda.time.Interval; 

public class IntervalAdapter extends XmlAdapter<String, Interval> { 
    @Override 
    public Interval unmarshal(String v) throws Exception { 
     return new Interval(10, 20); 
    } 

    @Override 
    public String marshal(Interval v) throws Exception { 
     return "10-20"; 
    } 
} 

,另外我我的注释Web方法使用适配器:

package jodaws; 

import javax.jws.WebService; 
// import added 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 
import javax.xml.ws.Endpoint; 

import org.joda.time.Interval; 

@WebService(name = "JodaWS") 
public class JodaWebService { 

    // annotation added 
    @XmlJavaTypeAdapter(IntervalAdapter.class) 
    public Interval readInterval() { 
     return new Interval(30, 40); 
    } 

    public static void main(String[] args) { 
     Endpoint.publish("http://localhost:10100/JodaWS", new JodaWebService()); 
    } 
} 

现在它应该工作。但是,当我再次启动Web服务时,我仍然收到一个异常,但是仍有一个异常:

29.05.2011 17:27:33 com.sun.xml.internal.ws.model.RuntimeModeler getRequestWrapperClass 
INFO: Dynamically creating request wrapper Class jodaws.jaxws.ReadInterval 
29.05.2011 17:27:34 com.sun.xml.internal.ws.model.RuntimeModeler getResponseWrapperClass 
INFO: Dynamically creating response wrapper bean Class jodaws.jaxws.ReadIntervalResponse 
Exception in thread "main" javax.xml.ws.WebServiceException: java.lang.IllegalArgumentException: value class jodaws.IntervalAdapter 
    at com.sun.xml.internal.ws.model.WrapperBeanGenerator.createResponseWrapperBean(WrapperBeanGenerator.java:269) 
    at com.sun.xml.internal.ws.model.RuntimeModeler.getResponseWrapperClass(RuntimeModeler.java:293) 
    at com.sun.xml.internal.ws.model.RuntimeModeler.processDocWrappedMethod(RuntimeModeler.java:688) 
    at com.sun.xml.internal.ws.model.RuntimeModeler.processMethod(RuntimeModeler.java:612) 
    at com.sun.xml.internal.ws.model.RuntimeModeler.processClass(RuntimeModeler.java:401) 
    at com.sun.xml.internal.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:240) 
    at com.sun.xml.internal.ws.server.EndpointFactory.createSEIModel(EndpointFactory.java:312) 
    at com.sun.xml.internal.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:178) 
    at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:456) 
    at com.sun.xml.internal.ws.api.server.WSEndpoint.create(WSEndpoint.java:475) 
    at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.createEndpoint(EndpointImpl.java:213) 
    at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(EndpointImpl.java:143) 
    at com.sun.xml.internal.ws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:102) 
    at javax.xml.ws.Endpoint.publish(Endpoint.java:170) 
    at jodaws.JodaWebService.main(JodaWebService.java:18) 
Caused by: java.lang.IllegalArgumentException: value class jodaws.IntervalAdapter 
    at com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter.newConstItem(ClassWriter.java:893) 
    at com.sun.xml.internal.ws.org.objectweb.asm.AnnotationWriter.visit(AnnotationWriter.java:185) 
    at com.sun.xml.internal.ws.model.WrapperBeanGenerator.createBeanImage(WrapperBeanGenerator.java:111) 
    at com.sun.xml.internal.ws.model.WrapperBeanGenerator.createResponseWrapperBean(WrapperBeanGenerator.java:265) 
    ... 14 more 

而这就是我卡住的地方。我究竟做错了什么?

回答

7

你是对的,你需要使用这个用例的XmlAdapter。下面是它如何工作的一个示例:

IntervalStringAdapter

下面的适配器将在格式开始结束时间间隔的情况下转换到/自字符串。

package blog.joda; 

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

import org.joda.time.Interval; 

public class IntervalStringAdapter extends XmlAdapter<String, Interval>{ 

    @Override 
    public Interval unmarshal(String v) throws Exception { 
     int dashIndex = v.indexOf('-'); 
     long start = Long.valueOf(v.substring(0, dashIndex)); 
     long end = Long.valueOf(v.substring(dashIndex + 1)); 
     return new Interval(start, end); 
    } 

    @Override 
    public String marshal(Interval v) throws Exception { 
     return v.getStartMillis() + "-" + v.getEndMillis(); 
    } 

} 

下面是如何将属性配置为使用适配器的例子:

package blog.joda; 

import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

import org.joda.time.Interval; 

@XmlRootElement 
public class Root { 

    private Interval interval; 

    @XmlJavaTypeAdapter(IntervalStringAdapter.class) 
    public Interval getInterval() { 
     return interval; 
    } 

    public void setInterval(Interval interval) { 
     this.interval = interval; 
    } 

} 

演示

package blog.joda; 

import java.io.File; 

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

public class Demo { 

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

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     Root root = (Root) unmarshaller.unmarshal(new File("src/blog/joda/input.xml")); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(root, System.out); 
    } 

} 

input.xml中

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<root> 
    <interval>10-20</interval> 
</root> 

更多信息