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
¿No debería 'com.twoh.dto.Company' tener un constructor de una sola cadena de acuerdo con el mensaje de error? – Stan
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
¿Podría posiblemente proporcionar una declaración de la clase com.twoh.dto.Company? – Stan