2016-04-28 30 views
7

Rischio problemi in un servizio REST Jax-RS quando si tenta di aggiornare un'entità contenente enumerazioni tramite HTTP PUT.HTTP Put Enum utilizzando JAX-RS REST-Service

Sto inserendo l'entità codificata come JSON, quindi le enumerazioni che sto usando in questo JSON sono fornite come stringhe.

sto ottenendo seguente errore:

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) 

Campo Valore AGENT è un censimento nel conto entità.

Ho ricevuto questo errore solo in entità contenenti enumerazioni, in altri casi il PUT HTTP funziona correttamente.

La mia ipotesi è, come "AGENT" è consegnato come stringa in JSON, non può essere risolto in un valore enum.

C'è qualche soluzione semplice con cui potrei andare?

Grazie per il vostro aiuto!

Modifica per un po 'di codice:

Va bene, l'enumerazione si definisce in questo modo:

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

Il PUT HTTP REST-servizio come questo:

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

con update- funzione:

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

qualche suggerimento?

+0

Hai provato la seguente soluzione: http://stackoverflow.com/a/12292355/1346996? – aribeiro

+0

Grazie per il tuo suggerimento, l'ho provato, ma l'errore rimane lo stesso. – EsSuch

+1

È possibile aggiungere in ingresso json e classe a cui deve essere deserializzato? – Ilya

risposta

2

@XmlEnumValue annotation dichiara quale valore di stringa è mappato alla costante enum annotata. cioè quando si scrive

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

poi CUSTOMER costante viene mappato lov.account.type.customer stringa.

Quindi, se volete che CUSTOMER costante è mappato CUSTOMER stringa, allora avete bisogno di scrivere

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

o rimuovere @XmlEnumValue annotazione cioè

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


UPD Ora vedo che la radice di il problema è l'ereditarietà. Se si tenta di deserializzare una classe ereditata EclipseLink per impostazione predefinita usa il campo @type per determinare quale classe deve essere istanziata per quale input. Vedi this answer. Quindi hai diversi modi per andare a seconda delle circostanze.

Primo modo (abbastanza sporca)
Si può cercare di annotare il supertipo con @XmlDiscriminatorNode("fakeField") È applicabile solo se si dispone di un bambino di classe

Secondo modo
Se avete esatta relazione tra il AccountType costante e classe figlio è necessario annotare ogni classe figlia con annotazione @XmlDiscriminatorValue.
Esempio:

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

} 
+0

grazie per il consiglio, ma ancora non funziona. Qualche altro suggerimento? – EsSuch

+0

La stessa eccezione? – Ilya

+0

sì, identico al 100%. – EsSuch

1

non è esattamente lo stesso scenario, ma ho avuto un problema simile a Jersey utilizzando JSON e Enums.

Una cosa che vedo nella definizione enum è che si specifica un nome personalizzato per l'enumerazione

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

Ma sembra che si sta inviando AGENTE nei dati JSON. Non dovresti invece inviare "lov.account.type.agent"?