13

The simplest of cases is causing me problems. I've run into it the first time. I am able to unmarshal slightly more complex json but this simple one fails.

What would cause this and why is jackson having trouble with just a single string?

A simple class holding the name of the user's role.

public class UpdateUserRole {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }    
}

Inside the controller

public void updateUserRole(@PathVariable Long id, @RequestBody UpdateUserRoleReq req) {
}

As soon as Jackson sees this, it throws this error

org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Can not instantiate value of type [simple type, class com.mycompany.UpdateUserRoleReq] from String value ('{"name":"admin_1407445357682"}'); no single-String constructor/factory method; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class com.mycompany.UpdateUserRoleReq] from String value ('{"name":"admin_1407445357682"}'); no single-String constructor/factory method
    at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:228)
    at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.read(MappingJackson2HttpMessageConverter.java:220)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:183)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:98)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:79)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:157)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:124)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:874)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:649)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextFilterConfiguration$1.doFilterInternal(EndpointWebMvcAutoConfiguration.java:257)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
Alexey Gavrilov
  • 10,593
  • 2
  • 38
  • 48
sat
  • 5,489
  • 10
  • 63
  • 81
  • Can you post your JSON string? – Alexey Gavrilov Aug 08 '14 at 06:20
  • Just to be sure, can you confirm that when you said `UpdateUserRole`, you actually meant `UpdateUserRoleReq`? – ccjmne Aug 08 '14 at 06:38
  • @Alexey - Not sure how I can share the json. Its running through a integration tests. Unless I do a wireshark or something, its a http request. – sat Aug 09 '14 at 03:32
  • @ccjmne - Yes. It is set to use UpdateUserRoleReq correctly. If I create a constructor in UpdateUserRoleReq like so: UpdateUserRoleReq(String name), it starts to work. No idea why. I was following the instructions on the error message. It wanted a constructor/factory-method for a single String. – sat Aug 09 '14 at 03:34
  • @sat sounds like you are constructing an object out of a json string node, not from an object node. – Alexey Gavrilov Aug 09 '14 at 06:23

4 Answers4

12

I was able to solve a very similar problem by adhering exactly to the error message.

I added the equivalent in your case of a single-String constructor.

public class UpdateUserRole {

  private String name;

  public UpdateUserRole() {}

  public UpdateUserRole(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }    
}
Samuel Waggoner
  • 156
  • 1
  • 5
12

I my case. I was sending in double escaped JSON string e.g. "{\"name\":\"abc\", \"age\":21}" and my String constructor only receive the JSON string completely. The other attributes (age) was not updated at all. Once I changed the input to {"name":"abc", "age":21}. Jackson was able to automatically parse the JSON input into object(s).

Alvin Yue
  • 139
  • 1
  • 4
0

I folowed a Jira tutorial (https://developer.atlassian.com/server/jira/platform/oauth/) for OAuth. In my case, I used dto to json transformation with GSON lib, however I couldn't make it work. I'll provide source later, but for fast resolve, please see : https://stackoverflow.com/a/59981597/1551368

dobrivoje
  • 848
  • 1
  • 9
  • 18
-2

You have to add the construct method which contains single parameter. Just have a try.

Mike
  • 419
  • 1
  • 6
  • 16