2013-11-14 2 views
4

В настоящее время я переношу проект 1.x на игру до 2.4.1 и получил ошибку при использовании enums в качестве параметра (PathParam, QueryParam и т. Д.). В основном это перечисление должно быть действительным на основе 3-требование Джерси для параметра метода, которыйДжерси 2 enum as method параметр throws exception

Have статический метод valueOf или fromString, который принимает один аргумент типа String (см, например, Integer.valueOf (String) и 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> 

, который генерирует:

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

    ACTIVE, 
    INACTIVE; 

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

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

} 

, когда он используется в:

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

производит:

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 

Поскольку он запускается во время unmarshalling от JaxbStringReaderProvider, и это не должно быть, когда мой сгенерированный класс не имеет аннотаций xml. Каков наилучший способ обращения к параметрам метода enum type без создания объекта-оболочки с конструктором строк для каждого необходимого типа перечисления?

ответ

6

Вы должны выполнять пользовательские ParamConverterProvider и ParamConverter и зарегистрировать реализации в JAX-RS среды выполнения (с использованием JAX-RS Application или web.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

Привет Michal спасибо за ответ, однако, я попробовал этот добавить его в web.xml для ServletContainer jersey.config. server.provider.packages my.package.poc.provider; my.package.poc.resource однако я получаю ту же ошибку. в соответствии с проверкой кода, параметр paramConverters AggregatedProvider добавляет сначала JaxbStringReaderProvider, который вызывает одно и то же исключение. – geneqew

+0

Можете ли вы проверить, создан ли параметр ParamConverterProvider вообще в вашей настройке? –

+0

Привет Михал, похоже, что в первый раз я добавил, что он не подбирается, поскольку при запуске возникает ошибка при запуске из-за строки ' final Method fromValueMethod = rawType.getMethod (" fromValue ", String.class); ' Я изменил реализацию конвертера get: ' final Значение методаOf = 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; 
    } 
}; 

Он поднял уровень до Fatal Error, который я думаю, должно быть 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());