JsonMappingException: Can not instantiate value of type [simple type, a.b.c.Company] from JSON String; no single-String constructor/factory method

96,150

Solution 1

I solved the same problem by fixing the JSON I was sending to the server; it was invalid. I removed the "," characters at the end of the last attributes and it worked. I hope it helps

Solution 2

Similar to @Nirmal, I passed in JSON which was contained within double quotes:

"{ "SomeJSON":"Value" }"

instead of

{ "SomeJSON":"Value" }

Removing the "s resolved the issue.

Share:
96,150
hairyone
Author by

hairyone

Updated on April 06, 2021

Comments

  • hairyone
    hairyone about 3 years

    I have just added a REST api to my existing Spring + BlazeDS + Hibernate server and everything appears to work when data is retrieved and serialised as JSON but when I try and POST data to be de-serialised into a POJO I get the an exception.

    I was under the impression that the spring annotations and the presence of the Jackson jars in the class path would be all that was required, at least it was for my list, get, delete methods that had simple parameters.

    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
    

    Here's the method being called:

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

    and here is the full exception:

    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)
    

    Update: added definition of Company 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();
        }
    
    }
    

    Update If I amend the DTO so that Jackson ignores the Company.adminUserIdList property then the record is created successfully.

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

    Update Here is the Json as returned by the /company/get/1 method using 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
    }
    

    I was using a similar pattern (less the "id" and a different "uid")for the /compamy/create call with a Content-type=application/json header