【问题标题】:HTTP Put Enum using JAX-RS REST-Service使用 JAX-RS REST-Service 的 HTTP Put Enum
【发布时间】:2016-08-22 19:15:57
【问题描述】:

尝试通过 HTTP PUT 更新包含枚举的实体时,我在 Jax-RS REST-Service 中遇到问题。

我将实体编码为 JSON,因此我在此 JSON 中使用的枚举作为字符串传递。

我收到以下错误:

Exception [EclipseLink-43] (Eclipse Persistence Services - 2.6.2.qualifier): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Missing class for indicator field value [AGENT] of type [class java.lang.String].
Descriptor: XMLDescriptor(de.org.app.business.account.Account --> [DatabaseTable(account)])
    at org.eclipse.persistence.exceptions.DescriptorException.missingClassForIndicatorFieldValue(DescriptorException.java:940)
    at org.eclipse.persistence.internal.oxm.QNameInheritancePolicy.classFromRow(QNameInheritancePolicy.java:278)
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.classFromRow(TreeObjectBuilder.java:182)
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.classFromRow(TreeObjectBuilder.java:1)
    at org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.initializeRecord(UnmarshalRecordImpl.java:512)
    at org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.startElement(UnmarshalRecordImpl.java:748)
    at org.eclipse.persistence.internal.oxm.record.json.JsonStructureReader.parseRoot(JsonStructureReader.java:187)
    at org.eclipse.persistence.internal.oxm.record.json.JsonStructureReader.parse(JsonStructureReader.java:140)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:978)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:425)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:375)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:708)
    at org.eclipse.persistence.internal.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:643)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:339)
    at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.readFrom(MOXyJsonProvider.java:668)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:256)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:235)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
    at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundReadFrom(MappableExceptionWrapperInterceptor.java:74)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1085)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
    at org.glassfish.jersey.server.ContainerRequest.readEntity(ContainerRequest.java:271)
    at org.glassfish.jersey.server.internal.inject.EntityParamValueFactoryProvider$EntityValueFactory.provide(EntityParamValueFactoryProvider.java:96)
    at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.provide(ParamValueFactoryWithSource.java:71)
    at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:94)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:127)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$VoidOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:143)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
    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:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
    at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:471)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:425)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:383)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:336)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:223)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:416)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:283)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:283)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
    at java.lang.Thread.run(Thread.java:745)

字段值 AGENT 是实体 Account 中的枚举。

我只在包含枚举的实体中收到此错误,在其他情况下 HTTP PUT 工作正常。

我的猜测是,由于“代理”在 JSON 中以字符串形式传递,因此无法解析为枚举值。

我有什么简单的解决方法吗?

感谢您的帮助!

编辑更多代码:

好的,枚举是这样定义的:

@XmlType(name = "type")
@XmlEnum
public enum AccountType implements TranslatableEnum {
    @XmlEnumValue(value = "lov.account.type.customer")
    CUSTOMER("lov.account.type.customer"),
    @XmlEnumValue(value = "lov.account.type.agent")
    AGENT("lov.account.type.agent")
    //just getter/setter things following
}

REST-Service 中的 HTTP PUT 如下:

@PUT
@Path(value = "{id}")
@Consumes(value = MediaType.APPLICATION_JSON)
public void edit(@PathParam(value = "id") final String id, final T entity) {
    getRepository().update(entity);
}

带有更新功能:

public T update(@Observes @Update T entity) {
    getEntityManager().merge(entity);
    return entity;
}

有什么建议吗?

【问题讨论】:

  • 您是否尝试过以下解决方案:stackoverflow.com/a/12292355/1346996?
  • 感谢您的建议,我试过了,但错误仍然存​​在。
  • 你能添加传入的 json 和应该反序列化的类吗?

标签: java json enums jax-rs moxy


【解决方案1】:

这不是完全相同的场景,但我在 Jersey 使用 JSON 和 Enums 时遇到了类似的问题。

我在您的枚举定义中看到的一件事是您为枚举指定了一个自定义名称

AGENT("lov.account.type.agent")

但您似乎在 JSON 数据中发送 AGENT。您不应该发送“lov.account.type.agent”吗?

【讨论】:

    【解决方案2】:

    @XmlEnumValue 注释声明哪个字符串值映射到带注释的枚举常量。即当你写的时候

    @XmlEnumValue(value = "lov.account.type.customer")
    CUSTOMER("lov.account.type.customer")
    

    然后CUSTOMER 常量被映射到lov.account.type.customer 字符串。

    所以如果你想要CUSTOMER 常量被映射到CUSTOMER 字符串那么你需要写

    @XmlEnumValue(value = "CUSTOMER")
    CUSTOMER("lov.account.type.customer")
    

    或删除@XmlEnumValue注释即

    @XmlEnum
    public enum AccountType implements TranslatableEnum {
        CUSTOMER("lov.account.type.customer"),
        AGENT("lov.account.type.agent")
        //...
    }
    


    UPD 现在我看到问题的根源是继承。如果您尝试反序列化继承的类 EclipseLink 默认使用 @type 字段来确定应该为哪个输入实例化哪个类。见this answer。因此,根据您的情况,您有几种方法可供选择。

    第一种方法(够脏)
    您可以尝试使用 @XmlDiscriminatorNode("fakeField") 注释您的超类型它仅适用于您有一个子类

    第二种方式
    如果您在AccountType 常量和子类之间有确切的关系,则需要使用@XmlDiscriminatorValue 注释来注释每个子类。
    示例:

    @XmlRootElement
    public static class Parent {
        AccountType type;
    
        public AccountType getType() {
            return type;
        }
    
        public void setType(AccountType type) {
            this.type = type;
        }
    }
    
    
    @XmlDiscriminatorValue("AGENT")
    public static class Agent extends Parent {
    
    }
    
    @XmlDiscriminatorValue("CUSTOMER")
    public static class Customer extends Parent {
    
    }
    

    【讨论】:

    • 感谢您的建议,但它仍然不起作用。还有其他建议吗?
    猜你喜欢
    • 1970-01-01
    • 2015-02-03
    • 2012-06-26
    • 1970-01-01
    • 2012-03-19
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多