异常信息:
2022-04-24 16:07:43 [http-nio-8080-exec-4] ERROR com.pagoda.config.MyExceptionHandler - 异常信息
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.pagoda.bo.TagConditionsBo]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `TagConditionsBo` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (PushbackInputStream); line: 5, column: 9] (through reference chain: com.pagoda.bo.MaterialListBo["tagConditions"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:386)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:342)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:185)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:160)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:133)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at com.pagoda.config.PdWebFilter.doFilter(PdWebFilter.java:48)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `TagConditionsBo` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (PushbackInputStream); line: 5, column: 9] (through reference chain: com.pagoda.bo.MaterialListBo["tagConditions"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1904)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1349)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1415)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:351)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:184)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4674)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3682)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:378)
... 46 common frames omitted
问题来源: 同事在某一次提交了一份代码,增加了以下功能: 有一个字段为Long类型,在返回前端时,尾部的几个数据变成0,导致数据报错,他增加这样一个配置用来将Long类型转化成为String类型
@EnableWebMvc
@Configuration
public class WebJsonConverterConfig extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
jackson2HttpMessageConverter.setObjectMapper(objectMapper);
converters.add(jackson2HttpMessageConverter);
}
}
异常原因: ObjectMapper在转化json为对象时,需要对象存在无参构造方法。而对象上增加了Lombok 的@Builder注解时,是不会增加无参构造方法的。
实验代码:
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Student {
private String name;
private int age;
}
编译之后:
public class Student {
private String name;
private int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
public static Student.StudentBuilder builder() {
return new Student.StudentBuilder();
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Student)) {
return false;
} else {
Student other = (Student)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name == null) {
return this.getAge() == other.getAge();
}
} else if (this$name.equals(other$name)) {
return this.getAge() == other.getAge();
}
return false;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Student;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.getName();
int result = result * 59 + ($name == null ? 43 : $name.hashCode());
result = result * 59 + this.getAge();
return result;
}
public String toString() {
return "Student(name=" + this.getName() + ", age=" + this.getAge() + ")";
}
public static class StudentBuilder {
private String name;
private int age;
StudentBuilder() {
}
public Student.StudentBuilder name(String name) {
this.name = name;
return this;
}
public Student.StudentBuilder age(int age) {
this.age = age;
return this;
}
public Student build() {
return new Student(this.name, this.age);
}
public String toString() {
return "Student.StudentBuilder(name=" + this.name + ", age=" + this.age + ")";
}
}
}
单独使用@Data时是会创建对象无参构造方法的,加上@Builder之后,无参构造就没了 并且在对象内手动增加无参构造编译也不通过
解决方法: 1,使用@Tolerate 增加一个构造方法,在构造方法上增加注解,这是lombok提供的一个冲突兼容方式
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Tolerate;
@Data
@Builder
public class Student {
private String name;
private int age;
@Tolerate
public Student() {
}
}
2,调整@Builder的位置至构造方法上 这是官方提供的另一种解法 projectlombok.org/features/Bu…
import lombok.Builder;
import lombok.Data;
@Data
public class Student {
private String name;
private int age;
@Builder
public Student() {
}
}
@Builder可以添加在方法上,添加在构造方法上,可以实现和添加在类上同样的效果,并且兼容了无参构造方法 @Builder增加在普通方法上,好像没啥大用处
import lombok.Builder;
import lombok.Data;
@Data
public class Student {
private String name;
private int age;
@Builder
public void calcAge() {
}
}
public class Student {
private String name;
private int age;
public void calcAge() {
}
//主要是生成了这个方法
public entity.Student.VoidBuilder builder() {
return new entity.Student.VoidBuilder(this);
}
public Student() {
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Student)) {
return false;
} else {
Student other = (Student)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name == null) {
return this.getAge() == other.getAge();
}
} else if (this$name.equals(other$name)) {
return this.getAge() == other.getAge();
}
return false;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Student;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.getName();
int result = result * 59 + ($name == null ? 43 : $name.hashCode());
result = result * 59 + this.getAge();
return result;
}
public String toString() {
return "Student(name=" + this.getName() + ", age=" + this.getAge() + ")";
}
}