2012-05-31 19 views
11

acabo añadido una API REST para mi primavera + BlazeDS existente + Hibernate servidor y todo parece funcionar cuando los datos se recuperan y serializado como JSON pero cuando intento y datos Puesto que se de- serializado en un POJO tengo la excepción.JsonMappingException: no se puede crear una instancia del valor del tipo [tipo simple, a.b.c.Company] de JSON String; hay una sola cadena de constructor/fábrica método

Tenía la impresión de que las anotaciones de primavera y la presencia de las jarras Jackson en la ruta de clases serían todo lo que se requería, al menos era para mi lista, obtener, eliminar métodos que tenían parámetros simples.

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 

Aquí es el método que se llama:

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

y aquí está la excepción 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) 

Actualización: añadido definición de la empresa 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(); 
    } 

} 

actualización Si puedo modificar el DTO por lo que Jackson omite la propiedad Company.adminUserIdList el registro se ha creado correctamente.

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

actualización Aquí está el Json como devuelto por el método /company/get/1 usando 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 
} 

que estaba usando un patrón similar (menos la "id" y un "uid" diferente) para la llamada /compamy/create con un encabezado Content-type=application/json

+0

¿No debería 'com.twoh.dto.Company' tener un constructor de una sola cadena de acuerdo con el mensaje de error? – Stan

+0

Eso es lo que implica el mensaje, pero si se serializa a JSON automágicamente, ¿por qué no en la otra dirección? Si tengo que escribir un método que hace el trabajo parece derrotar el objeto. En una pregunta http://stackoverflow.com/questions/8369260/jackson-throws-jsonmappingexception-on-deserialize-demands-single-string-constr similar que es lo que se hizo, pero ninguno de los ejemplos que he visto de los servicios REST primavera sugieren que esto es necesario para cada uno de los POJO. – hairyone

+0

¿Podría posiblemente proporcionar una declaración de la clase com.twoh.dto.Company? – Stan

Respuesta

11

Resolví el mismo problema al arreglar el JSON que estaba enviando al servidor; fue inválido Quité los caracteres "," al final de los últimos atributos y funcionó. espero que ayude

+2

Problema similar para mí ... Estaba enviando el json como '{" currency ":" 1 "}' para mapearlo contra un POJO que debería haber arrojado '' en su formato xml. .. pero me enfrenté al error mencionado en este hilo ... hasta que arreglé mi json para que fuera '{" currency ": {" id ":" 1 "}}' – pulkitsinghal

0

En mi caso, me estaba perdiendo de inicio y fin llaves.

Cuestiones relacionadas