2013-11-14 97 views
4

我目前正在将球衣1.x项目迁移到2.4.1,并且在使用枚举作为参数(PathParam,QueryParam等)时出现错误。基本上,此枚举应根据泽西的方法参数第3的要求,即泽西岛2枚举作为方法参数抛出异常

有有效名为valueOf的或fromString静态方法接受单个 字符串参数(见,例如,Integer.valueOf(字符串)和 java.util.UUID.fromString(String));

由于本项目使用的XSD作为合同生成的Java类,我有:

<xs:simpleType name="status"> 
    <xs:restriction base="xs:string"> 
     <xs:enumeration value="ACTIVE" /> 
     <xs:enumeration value="INACTIVE" /> 
    </xs:restriction> 
</xs:simpleType> 

产生:

@GET 
public Response search(@QueryParam("status") my.package.Status status) { 
//..other code here 
} 

@XmlType(name = "status") 
@XmlEnum 
public enum Status { 

    ACTIVE, 
    INACTIVE; 

    public String value() { 
     return name(); 
    } 

    public static Status fromValue(String v) { 
     return valueOf(v); 
    } 

} 

当它的二手

它产生:

org.glassfish.jersey.server.internal.inject.ExtractorException: Error unmarshalling JAXB object of type "class my.package.Status". 
    at org.glassfish.jersey.server.internal.inject.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:195) 
    at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.convert(AbstractParamValueExtractor.java:138) 
    at org.glassfish.jersey.server.internal.inject.AbstractParamValueExtractor.fromString(AbstractParamValueExtractor.java:129) 
    at org.glassfish.jersey.server.internal.inject.SingleValueExtractor.extract(SingleValueExtractor.java:83) 
    at org.glassfish.jersey.server.internal.inject.QueryParamValueFactoryProvider$QueryParamValueFactory.provide(QueryParamValueFactoryProvider.java:88) 
    at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:81) 
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:121) 
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:152) 
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104) 
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:367) 
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:349) 
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:106) 
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:259) 
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) 
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) 
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315) 
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297) 
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267) 
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318) 
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236) 
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:983) 
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:361) 
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372) 
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335) 
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218) 
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) 
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:401) 
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) 
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) 
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766) 
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450) 
    at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) 
    at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114) 
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) 
    at org.mortbay.jetty.Server.handle(Server.java:326) 
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) 
    at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:928) 
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549) 
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212) 
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) 
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410) 
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582) 
Caused by: javax.xml.bind.UnmarshalException 
- with linked exception: 
[org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.] 
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335) 
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:512) 
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:209) 
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:181) 
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:232) 
    at org.glassfish.jersey.server.internal.inject.JaxbStringReaderProvider$RootElementProvider$1.fromString(JaxbStringReaderProvider.java:192) 
    ... 41 more 
Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog. 
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198) 
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177) 
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:441) 
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:368) 
    at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1388) 
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:998) 
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:607) 
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:116) 
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:489) 
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:835) 
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764) 
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123) 
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1210) 
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:568) 
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:203) 
    ... 44 more 

由于它在JaxbStringReaderProvider反编组期间被触发,并且它不应该是我生成的类没有xml注释的情况。什么是最好的方式来处理枚举类型方法params而不创建包含每个需要枚举类型的字符串构造函数的包装对象?

回答

6

您应该实现自定义ParamConverterProviderParamConverter并将您的实现注册到JAX-RS运行时(使用JAX-RS Applicationweb.xml)。喜欢的东西:

@Provider 
public class GeneratedEnumParamConverterProvider implements ParamConverterProvider { 

    @Override 
    public <T> ParamConverter<T> getConverter(final Class<T> rawType, final Type genericType, 
               final Annotation[] annotations) { 
     try { 
      final Method fromValueMethod = rawType.getMethod("fromValue", String.class); 

      return new ParamConverter<T>() { 
       @Override 
       public T fromString(final String value) { 
        try { 
         return rawType.cast(fromValueMethod.invoke(null, value)); 
        } catch (Exception e) { 
         throw new IllegalArgumentException("Given value (" + value + ") cannot be converted to parameter of type" + rawType); 
        } 
       } 

       @Override 
       public String toString(final T value) { 
        return value.toString(); 
       } 
      }; 
     } catch (Exception e) { 
      return null; 
     } 
    } 
} 
+0

嗨米哈尔感谢您的回答不过,我已经试过这一个增加它在web.xml的ServletContainer ​​jersey.config。 server.provider.packages my.package.poc.provider; my.package.poc.resource 但是我得到相同的错误。根据检查代码,AggregatedProvider的paramConverters的顺序首先添加JaxbStringReaderProvider,这会触发相同的异常。 – geneqew

+0

您可以检查'ParamConverterProvider'是否在您的设置中实例化? –

+0

嗨米歇尔,看起来像我第一次加入它没有被拿起,因为在启动时出现错误,因为行 ' final Method fromValueMethod = rawType.getMethod(“fromValue”,String.class); ' 我已将get转换器实现修改为: ' final方法valueOf = AccessController.doPrivileged(ReflectionHelper.getValueOfStringMethodPA(rawType)); ' 谢谢!我只是好奇,但是如何确定提供者的顺序。 – geneqew

0

在org.eclipse.persistence.jaxb.JAXBContext 它发起DEFAULT_VALIDATION_EVENT_HANDER这样:

protected static final ValidationEventHandler DEFAULT_VALIDATION_EVENT_HANDER = new ValidationEventHandler() { 
    public boolean handleEvent(ValidationEvent event) { 
     return event.getSeverity() < ValidationEvent.FATAL_ERROR; 
    } 
}; 

它提出的水平致命错误,我认为应该是错误。 所以上面的代码可以是:

protected static final ValidationEventHandler DEFAULT_VALIDATION_EVENT_HANDER = new DefaultValidationEventHandler(); 

我用反射创建服务器时修改DEFAULT_VALIDATION_EVENT_HANDER它,然后遇到了错误的枚举字符串值时,它可以抛出一个异常。

的代码来修改DEFAULT_VALIDATION_EVENT_HANDER在JAXBContext中:

final Field field = JAXBContext.class.getDeclaredField("DEFAULT_VALIDATION_EVENT_HANDER"); 
    field.setAccessible(true); 

    Field modifiersField = Field.class.getDeclaredField("modifiers"); 
    modifiersField.setAccessible(true); 
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 
    field.set(null, new DefaultValidationEventHandler());