HTTP Put Enum using the JAX-RS REST service

I am encountering problems in a Jax-RS REST service when trying to update an object containing enumerations via HTTP PUT.

I put an object encoded as JSON, so the enums I use in this JSON are passed as strings.

I get the following error:

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) 

The value of the AGENT field is an enumeration in the entity account.

I get this error only in objects containing enums, in other cases HTTP PUT works fine.

My assumption is that as "AGENT" is supplied as a string in JSON, it cannot be resolved to an enum value.

Is there any easy workaround?

Thank you for your help!

Change another code:

Well, an enumeration is defined as follows:

 @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 } 

HTTP PUT in REST-Service:

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

with update function:

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

any suggestions?

+7
java json enums jax-rs moxy
source share
2 answers

@XmlEnumValue annotation announces which string value maps to the annotated constant enum. those. when you write

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

then the CUSTOMER constant is displayed in the line lov.account.type.customer .

So, if you want the CUSTOMER constant to be matched with the CUSTOMER string, then you need to write

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

or remove the annotation @XmlEnumValue ie

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


UPD Now I see that the root of the problem is inheritance. If you try to deserialize an inherited class, EclipseLink uses the @type field by default to determine which class should be created for input. See this answer . So you have several ways to go, depending on your circumstances.

The first way (dirty enough)
You can try to annotate your supertype with @XmlDiscriminatorNode("fakeField") . This only applies if you have one child class.

Second way
If you have an exact relationship between the AccountType constant and the child class, you need to annotate each child class with the @XmlDiscriminatorValue annotation.
Example:

 @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 { } 
+2
source

This is not exactly the same scenario, but I had a similar problem in Jersey using JSON and Enums.

One thing that I see in the definition of an enumeration is that you provide your own name for the enumeration

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

But it looks like you are sending AGENT to JSON data. Don't you send "lov.account.type.agent" instead?

+1
source

All Articles