Affects: 5.1.10
I was trying to POST a json for a given model that have lombok's AllArgsConstructor as well as implicitly defined private constructor annotated with JsonCreate, similarly to this:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Example {
private String string1;
private String string2;
@JsonCreator
private Example(@JsonProperty("string1") String string1, @JsonProperty("string2") String string2) {
this.string1 = string1;
this.string2 = string2;
}
}
Sending this to an endpoint with proper request body defined will result in internal error caused by HttpMediaTypeNotSupportedException with explanation:
"Content type 'application/json;charset=utf-8' not supported"
However when I change log level to warn I can see the real cause of the problem: (logged before exception is thrown)
WARN [ ] org.springframework.http.converter.json.MappingJackson2HttpMessageConverter - Failed to evaluate Jackson deserialization for type [[simple type, class com.example.Example]]: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Conflicting property-based creators: already had explicitly marked creator [constructor for com.example.Example, annotations: {interface java.beans.ConstructorProperties=@java.beans.ConstructorProperties(value=[string1, string2])}], encountered another: [constructor for com.example.Example, annotations: {interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}]
So basically Jackson can't deserialize because I defined two deserializing constructors (lombok adds @ConstructorProperties annotation for its generated constructors).
The current behavior suggests that my application does not support content type given by headers, when in reality I have a class that is incorrectly designed. As a result I spent some time to check my application configuration because I thought we might have incorrectly configured message converters.
I believe that the exception thrown by Spring is misleading and some other exception should be thrown instead with a real cause of the problem explained.
Below is the important part of stack trace for received error:
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=utf-8' not supported
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:225) ~[spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:158) ~[spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:131) ~[spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:127) ~[spring-web-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167) ~[spring-web-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134) ~[spring-web-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893) ~[spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:798) ~[spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) [spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) [spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) [servlet-api.jar:?]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) [spring-webmvc-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [servlet-api.jar:?]
Comment From: rstoyanchev
Allowing canRead to return false and only logging the issue is by design as this may be expected, meaning that another subsequent converter is expected to handle it. Logging is done at WARN and it is one of the highest log levels which should be on by default in most environments.