当前位置: 首页 > 知识库问答 >
问题:

Jersey 2枚举作为方法参数引发异常

谢修真
2023-03-14

我目前正在将Jersey 1. x项目迁移到2.4.1,并在使用枚举作为参数(PathParam、QueryParam等)时遇到错误。基本上,此枚举应该是有效的,基于泽西对方法参数的第三个要求

有一个名为valueOf或fromString的静态方法,它接受一个String参数(例如,请参见Integer.valueOf(String)和java.util.UUID.fromStriing(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

由于它是在 JaxbStringReaderProvider 解组期间触发的,因此当我生成的类没有 xml 注释时,情况不应该如此。处理枚举类型方法参数的最佳方法是什么,而无需为每个所需的枚举类型创建带有字符串构造函数的包装器对象?

共有2个答案

胡国兴
2023-03-14

in 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,这样当遇到错误的枚举字符串值时,它会抛出一个异常。

在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());
袁晋鹏
2023-03-14

您应该实现自定义的ParamConverterProvider和ParamConverter,并将您的实现注册到JAX-RS运行时(使用JAX-RS 应用程序或< code>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;
        }
    }
}
 类似资料:
  • 问题内容: 如何从枚举构造函数中引发异常?例如: 产生错误 未处理的异常类型IOException 问题答案: 由于实例是在静态初始化程序中创建的,因此请抛出ExceptionInInitializerError。

  • 我将尽最大努力用一个场景来解释我的问题: 我有一个ClassA,它只包含一个ClassB的非静态实例,许多影响ClassB实例的非静态方法(我们可以调用EFFECTS)和最后一个返回ClassB实例的非静态getter方法。 我有ClassC,它包含ClassB实例的非静态数组。在ClassC中,我有两个非静态方法,一个从数组中获取ClassB的单个实例,另一个通过给定的索引值设置ClassB的单

  • 问题内容: 如果参数无效,如何使用JSR-303验证方法参数并引发异常? 例如像这样:? 现在,我检查方法主体中的每个方法参数,例如 而且我觉得这很丑。 PS作为参考实现,我使用Hibernate-validator 4.1.0.Final 问题答案: 如果可以升级到Hibernate Validator 4.2.0或更高版本,则可以使用其方法验证功能,该功能为方法参数和返回值的验证提供支持。 可

  • 我是Spring启动的新手,并试图使用枚举作为Rest请求的参数。 这是我的枚举类: 在我的控制器类中,我使用了以下方法: 这是我的JSON: 但它不起作用。。我收到以下错误: