我目前正在将jersey 1.x项目迁移到2.4.1,并在使用枚举作为参数(PathParam,QueryParam等)时出错。基本上,这个枚举应该基于球衣对方法参数的第三个要求
有效有一个名为valueOf或fromString的静态方法,它接受一个 字符串参数(例如,参见Integer.valueOf(String)和 java.util.UUID.fromString(字符串));
由于这个项目使用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
因为它是在JaxbStringReaderProvider的解组期间触发的,所以当我生成的类没有xml注释时就不应该这样。处理枚举类型方法参数的最佳方法是什么,而不为每个需要的枚举类型创建带有字符串构造函数的包装器对象?
答案 0 :(得分: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;
}
}
}
答案 1 :(得分: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,我认为应该是错误的。 所以上面的代码可以是:
protected static final ValidationEventHandler DEFAULT_VALIDATION_EVENT_HANDER = new DefaultValidationEventHandler();
我在创建服务器时使用了反射来修改DEFAULT_VALIDATION_EVENT_HANDER,然后在遇到错误的枚举字符串值时会抛出异常。
在JAXBContext中修改DEFAULT_VALIDATION_EVENT_HANDER的代码:
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());