2012-05-31 1 views
11

Ho appena aggiunto una API REST al mio server Spring + BlazeDS + Hibernate esistente e tutto sembra funzionare quando i dati vengono recuperati e serializzati come JSON ma quando provo e i dati POST vengono de- serializzato in un POJO ottengo l'eccezione.JsonMappingException: impossibile istanziare il valore di tipo [tipo semplice, a.b.c.Company] da JSON String; nessun costruttore/metodo factory di stringa singola

Avevo l'impressione che le annotazioni a molla e la presenza dei vasi Jackson nel percorso di classe fossero tutto ciò che era necessario, almeno era per la mia lista, ottenere, eliminare metodi che avevano parametri semplici.

org.codehaus.jackson.map.JsonMappingException: Can not instantiate value of type [simple type, class com.twoh.dto.Company] from JSON String; no single-String constructor/factory method 

Ecco il metodo di essere chiamato:

public abstract class BaseEntityService<T extends BaseEntity> implements IBaseEntityService<T> { 

private IBaseEntityDAO<T> DAO; 

@Autowired 
private ValidationResultHelper validationResultHelper; 

public void setDAO(IBaseEntityDAO<T> DAO) { 
    this.DAO = DAO; 
} 

... 
@Secured("ROLE_USER") 
@RequestMapping(value="/create", method=RequestMethod.POST) 
public @ResponseBody ValidationResult create(@RequestBody T entity) { 
    ValidationResult result = null; 
    try { 
     result = DAO.persistEntity(entity); 
    } catch(JDBCException e) { 
     result = ExceptionHelper.getValidationResult(e); 
    } catch(DataIntegrityViolationException e) { 
     result = ExceptionHelper.getValidationResult(e); 
    } 
    validationResultHelper.log(DAO.getSession(), entity.getId(), entity.getClass(), result); 
    return result; 
} 
} 

e qui è l'eccezione completo:

org.codehaus.jackson.map.JsonMappingException: Can not instantiate value of type [simple type, class com.twoh.dto.Company] from JSON String; no single-String constructor/factory method 
at org.codehaus.jackson.map.deser.std.StdValueInstantiator._createFromStringFallbacks(StdValueInstantiator.java:379) 
at org.codehaus.jackson.map.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:268) 
at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromString(BeanDeserializer.java:759) 
at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:585) 
at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2723) 
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1914) 
at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:135) 
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:154) 
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.readWithMessageConverters(HandlerMethodInvoker.java:633) 
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestBody(HandlerMethodInvoker.java:597) 
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:346) 
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:171) 
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436) 
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424) 
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790) 
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719) 
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:669) 
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:585) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198) 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:311) 
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116) 
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:101) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:182) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) 
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) 
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173) 
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237) 
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) 
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) 
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) 
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857) 
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) 
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) 
at java.lang.Thread.run(Unknown Source) 

Aggiornamento: aggiunto definizione di società DTO

@CheckDictionaryProperty.List({ 
    @CheckDictionaryProperty(propertyName="partyId", dictionaryName="Party") 
}) 
@Unique.List({ 
    @Unique(properties = {"code"}, message = "UNIQUE_CODE"), 
    @Unique(properties = {"name"}, message = "UNIQUE_NAME") 
}) 
@Entity 
@FXClass 
@Table(name="edrcompany") 
@JsonAutoDetect 
public class Company extends BaseEntity { 

    private static final long serialVersionUID = 1L; 

    public Company(){} 

    @NotBlank 
    @Column 
    private String name; 
    public String getName(){ return this.name; } 
    public void setName(String name){ this.name = name; } 

    @Column 
    private String code; 
    public String getCode() { return this.code; } 
    public void setCode(String code) { this.code = code; } 

    @NotNull 
    @Column(name="party_id") 
    private Integer partyId; 
    public Integer getPartyId() { return this.partyId; } 
    public void setPartyId(Integer partyId) { this.partyId = ValueHelper.isNullOrZero(partyId) ? null : partyId; } 

    @ElementCollection(targetClass=Integer.class, fetch=FetchType.EAGER) 
    @Fetch(FetchMode.SUBSELECT) 
    @CollectionTable(name="edrcompanyadminlink", joinColumns={@JoinColumn(name="company_id")}) 
    @Column(name="user_id") 
    private Collection<Integer> adminUserIdList = new HashSet<Integer>(); 
    public Collection<Integer> getAdminUserIdList() { return this.adminUserIdList; } 
    public void setAdminUserIdList (Collection<Integer> adminUserIdList) { this.adminUserIdList = adminUserIdList; }  


} 


@MappedSuperclass 
@FXClass 
public abstract class BaseEntity implements Serializable { 

    private static final long serialVersionUID = 1L; 

    public BaseEntity(){} 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "id") 
    private Integer id; 
    public Integer getId() { return id; } 
    public void setId(Integer id) { this.id = ValueHelper.isNullOrZero(id) ? null : id; } 

    @Column(name="ENTITY_UID", unique=true, nullable=false, updatable=false, length=36) 
    /* Assign a default whenever this class is instantiated Hibernate will 
    * overwrite it when retrieving an entity from the DB. 
    */ 
    private String uid = UUID.randomUUID().toString(); 
    public String getUID() { return uid; }; 
    public void setUID(String uid) { this.uid = uid; } 

    @Version 
    @Column 
    private Integer version; 
    @FXIgnore 
    public Integer getVersion() { return this.version; } 
    public void setVersion(Integer version) { this.version = version; } 

    // Fake property so that DTO2FX will put it in 
    public String getClassName() { return this.getClass().getName(); } 
    @JsonIgnore 
    public void setClassName(String className) { throw new UnsupportedOperationException(); } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 

     if (o == null || !(o instanceof BaseEntity)) return false; 

     BaseEntity other = (BaseEntity) o; 

     // if the id is missing, return false 
     if (uid == null) return false; 

     // equivalence by uid 
     return uid.equals(other.getUID()); 
    } 

    @Override 
    public int hashCode() { 
     if (uid != null) { 
      return uid.hashCode(); 
     } else { 
      return super.hashCode(); 
     } 
    } 

    @Override 
    public String toString() { 
     return this.getClassName() + ": " + this.getId(); 
    } 

} 

Aggiornamento Se si modifica il DTO in modo che Jackson ignori la proprietà Company.adminUserIdList, il record viene creato correttamente.

@JsonIgnore 
public Collection<Integer> getAdminUserIdList() { return this.adminUserIdList; } 
@JsonIgnore 
public void setAdminUserIdList (Collection<Integer> adminUserIdList) { this.adminUserIdList = adminUserIdList; }  

Aggiornamento Ecco il JSON come restituito dal metodo /company/get/1 utilizzando Firefox RESTClient

{ 
    "partyId":1, 
    "adminUserIdList":[21], 
    "name":"2H Mechanical LLC", 
    "code":null, 
    "uid":"fc5e15e7-a9a7-11e1-be90-7d08b05cbb96", 
    "id":1, 
    "className":"com.twoh.dto.Company", 
    "version":0 
} 

Io sto usando un modello simile (meno il "id" e un "uid" diverso) per la chiamata /compamy/create con un'intestazione Content-type=application/json

+0

Non dovrebbe 'com.twoh.dto.Company' avere un costruttore di stringa singola in base al messaggio di errore? – Stan

+0

Questo è ciò che implica il messaggio, ma se serializza automaticamente su JSON perché no nella direzione opposta. Se devo scrivere un metodo che fa il lavoro sembra sconfiggere l'oggetto. In una domanda simile http://stackoverflow.com/questions/8369260/jackson-throws-jsonmappingexception-on-deserialize-demands-single-string-constr è ciò che è stato fatto ma nessuno degli esempi che ho visto dei servizi Spring REST suggerire che questo è necessario per ciascuno dei POJO. – hairyone

+0

Potresti fornire una dichiarazione della classe com.twoh.dto.Company? – Stan

risposta

11

Ho risolto lo stesso problema risolvendo il JSON che stavo inviando al server; non era valido Ho rimosso i caratteri "," alla fine degli ultimi attributi e ha funzionato. Spero che aiuti

+2

Problema simile per me ... Stavo inviando il json come '{" currency ":" 1 "}' per essere mappato su un POJO che avrebbe dovuto restituire '' nel suo formato xml. .. ma ho affrontato l'errore di cui parlavo in questo thread ... fino a quando ho corretto il mio json in "{" currency ": {" id ":" 1 "}}' – pulkitsinghal

0

Nel mio caso, mi mancava iniziare e terminare parentesi graffe.