Spring boot Spring数据REST-JsonGenerationException:无法写入数字,应为字段名
我在使用SpringBootStarter的SpringDataREST应用程序中遇到了一个问题。我用各种关系定义了许多实体。我可以通过键(通常)检索它们,但是我在一些相同对象的集合中遇到了问题。我想知道这是一个JsonIdentityInfo问题,还是为了防止循环JSON生成而“破坏”了唯一标识符 公司表中约有500个条目,页面大小默认为20。转到默认端点(/company),它将返回以下错误。我可以调出没有问题的单个公司(/company/1),包括创建JSON异常时它试图生成的同一家公司 当我进入异常堆栈时,我看到它正在尝试为supportEmailAddress字段生成JSON。这是可以被多个公司行引用的行。公司也有在此表中包含电子邮件地址的联系人,但这些电子邮件地址通常不会在公司或联系人之间共享 注意:我已经用类似的堆栈跟踪查看了SO问题,但该问题似乎围绕自定义序列化程序展开。我不是使用自定义序列化程序 我试过几件事:Spring boot Spring数据REST-JsonGenerationException:无法写入数字,应为字段名,spring-boot,spring-data,spring-data-rest,jpa-2.1,jackson2,Spring Boot,Spring Data,Spring Data Rest,Jpa 2.1,Jackson2,我在使用SpringBootStarter的SpringDataREST应用程序中遇到了一个问题。我用各种关系定义了许多实体。我可以通过键(通常)检索它们,但是我在一些相同对象的集合中遇到了问题。我想知道这是一个JsonIdentityInfo问题,还是为了防止循环JSON生成而“破坏”了唯一标识符 公司表中约有500个条目,页面大小默认为20。转到默认端点(/company),它将返回以下错误。我可以调出没有问题的单个公司(/company/1),包括创建JSON异常时它试图生成的同一家公司
- 带和不带scope属性的JsonIdentityInfo
- JsonManagedReference和JsonBackReference
- @对@Id字段的访问(AccessType.PROPERTY)
ext['hibernate.version'] = '5.1.0.Final'
ext['hibernateVersion'] = '5.1.0.Final'
ext['springVersion'] = '2.5.1.RELEASE'
ext['springBootVersion'] = '1.3.5.RELEASE'
ext['springDataCommonsVersion'] = '1.12.1.RELEASE'
ext['springDataJpaVersion'] = '1.10.1.RELEASE'
ext['springIntegrationVersion'] = '4.2.6.RELEASE'
ext['querydslVersion'] = '4.1.0'
ext['jacksonVersion'] = '2.8.0'
ext['jacksonJsr310Version'] = '2.8.0'
我已尝试通过序列化进行调试,根本问题是序列化程序在处理company.supportEmailAddress.key时会混淆。它正试图输出键值,但序列化程序希望下一个是键名。当第二次引用相同的supportEmailAddress id时,会发生此错误
更新至Jackson 2.8.0。没有变化
我在最后添加了一个简化的手写JSON示例,以显示我所期望的结构。如您所见,这两家公司引用了相同的supportEmailAddress对象(相同的id)。如果我更改为其他id,它将正确呈现。我相信第二个引用实际上只会输出id,而不是对象的其余部分,因为它已经序列化了一次。据我所知,这是一个标准功能,我还没有做过任何与更改Jackson默认功能相关的事情
简化实体(省略访问器):
公司:
@Entity
@Table(name = "T_Company")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "key", scope = Company.class)
public class Company extends AbstractCustomEntity<Long> {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "COMPANY_ID")
private Long key;
@Size(max = 50)
@Column(name = "NAME", nullable = false, length = 50, unique = true)
private String name;
@OneToMany(orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "company")
private Set<Alias> aliases;
@ManyToMany(mappedBy = "company")
private Set<Owner> owner;
@OneToMany(mappedBy = "agency", cascade = CascadeType.ALL)
private Set<Contact> contacts;
@ManyToOne
@JoinColumn(name = "SUPPORT_EMAIL_ADDRESS_ID")
private EmailAddress supportEmailAddress;
JSON示例:
{
"_embedded" : {
"companies" : [ {
"key" : 1,
"name" : "company1",
"supportEmailAddress" : {
"key" : 1,
"emailAddrType" : "support",
"emailAddress" : "email@support.com"
}
"aliases" : [ ],
"contacts" : [ ],
"owner" : {
"key" : 1,
"name" : "owner 1",
"contacts" : [ ],
"_links" : {
"company" : {
"href" : "http://localhost:8080/company/1"
}
}
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/company/1"
},
"company" : {
"href" : "http://localhost:8080/company/1"
},
"aliases" : {
"href" : "http://localhost:8080/company/1/aliases"
},
"contacts" : {
"href" : "http://localhost:8080/company/1/contacts"
}
}
}, {
"key" : 2,
"name" : "company2",
"supportEmailAddress" : {
"key" : 1,
"emailAddrType" : "support",
"emailAddress" : "email@support.com"
}
"aliases" : [ ],
"contacts" : [ ],
"owner" : {
"key" : 2,
"name" : "owner 2",
"contacts" : [ ],
"_links" : {
"company" : {
"href" : "http://localhost:8080/company/2"
}
}
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/company/2"
},
"company" : {
"href" : "http://localhost:8080/company/2"
},
"aliases" : {
"href" : "http://localhost:8080/company/2/aliases"
},
"contacts" : {
"href" : "http://localhost:8080/company/2/contacts"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/company"
},
"profile" : {
"href" : "http://localhost:8080/profile/company"
},
"search" : {
"href" : "http://localhost:8080/company/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}
我在嵌套实体(例如,
@OneToMany(mappedBy=“owner”,cascade=CascadeType.ALL))上指定了EAGER fetch时遇到了相同的错误
私人设置联系人;
在您的所有者
实体上)
一旦嵌套集合中有1个以上的项,序列化就停止工作。我可以通过在嵌套集合上指定FetchType.LAZY
来解决这个问题,我想这样序列化程序就不会与递归混淆了吧
我想听听更熟悉杰克逊的人的合理解释
@Entity
@Table(name = "T_EMAIL_ADDR")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "key", scope = EmailAddress.class)
public class EmailAddress extends AbstractCustomEntity<Long> {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "EMAIL_ADDRESS_ID")
private Long key;
@Column(name = "EMAIL_ADDRESS_TYPE_NME")
@Enumerated(EnumType.STRING)
private EmailAddrType emailAddrType;
@Size(max = 200)
@Email
@Column(name = "EMAIL_ADDR", length = 200, nullable = false, updatable = false)
private String emailAddress;
@Entity
@Table(name = "T_CONTACT")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "CATG", length = 6)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "key", scope = Contact.class)
public abstract class Contact extends AbstractCustomEntity<Long> {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "CONTACT_ID")
private Long key;
@Column(name = "CONTACT_NME", length = 100)
@Size(max = 100)
private String name;
@OneToOne
@JoinColumn(name = "EMAIL_ADDRESS_ID")
private EmailAddress emailAddress;
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Can not write a number, expecting field name; nested exception is com.fasterxml.jackson.core.JsonGenerationException: Can not write a number, expecting field name
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:276)
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:222)
at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:183)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)
at org.springframework.data.rest.webmvc.ResourceProcessorHandlerMethodReturnValueHandler.handleReturnValue(ResourceProcessorHandlerMethodReturnValueHandler.java:113)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:832)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:743)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:220)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
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:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.fasterxml.jackson.core.JsonGenerationException: Can not write a number, expecting field name
at com.fasterxml.jackson.core.JsonGenerator._reportError(JsonGenerator.java:1676)
at com.fasterxml.jackson.core.json.UTF8JsonGenerator._verifyValueWrite(UTF8JsonGenerator.java:925)
at com.fasterxml.jackson.core.json.UTF8JsonGenerator.writeNumber(UTF8JsonGenerator.java:787)
at com.fasterxml.jackson.databind.ser.std.NumberSerializers$LongSerializer.serialize(NumberSerializers.java:188)
at com.fasterxml.jackson.databind.ser.impl.WritableObjectId.writeAsId(WritableObjectId.java:35)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase._serializeWithObjectId(BeanSerializerBase.java:584)
at com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanSerializer.serialize(UnwrappingBeanSerializer.java:114)
at com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanPropertyWriter.serializeAsField(UnwrappingBeanPropertyWriter.java:127)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
at com.fasterxml.jackson.databind.SerializerProvider.defaultSerializeValue(SerializerProvider.java:985)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer.serialize(PersistentEntityJackson2Module.java:193)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer.serialize(PersistentEntityJackson2Module.java:140)
at com.fasterxml.jackson.databind.SerializerProvider.defaultSerializeValue(SerializerProvider.java:985)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$NestedEntitySerializer.serialize(PersistentEntityJackson2Module.java:356)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:672)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase._serializeWithObjectId(BeanSerializerBase.java:600)
at com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanSerializer.serialize(UnwrappingBeanSerializer.java:114)
at com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanPropertyWriter.serializeAsField(UnwrappingBeanPropertyWriter.java:127)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
at com.fasterxml.jackson.databind.SerializerProvider.defaultSerializeValue(SerializerProvider.java:985)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer.serialize(PersistentEntityJackson2Module.java:193)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer.serialize(PersistentEntityJackson2Module.java:140)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:616)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:519)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:31)
at org.springframework.hateoas.hal.Jackson2HalModule$HalResourcesSerializer.serialize(Jackson2HalModule.java:340)
at org.springframework.hateoas.hal.Jackson2HalModule$HalResourcesSerializer.serialize(Jackson2HalModule.java:302)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:672)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:130)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1428)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:930)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:269)
... 57 more
{
"_embedded" : {
"companies" : [ {
"key" : 1,
"name" : "company1",
"supportEmailAddress" : {
"key" : 1,
"emailAddrType" : "support",
"emailAddress" : "email@support.com"
}
"aliases" : [ ],
"contacts" : [ ],
"owner" : {
"key" : 1,
"name" : "owner 1",
"contacts" : [ ],
"_links" : {
"company" : {
"href" : "http://localhost:8080/company/1"
}
}
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/company/1"
},
"company" : {
"href" : "http://localhost:8080/company/1"
},
"aliases" : {
"href" : "http://localhost:8080/company/1/aliases"
},
"contacts" : {
"href" : "http://localhost:8080/company/1/contacts"
}
}
}, {
"key" : 2,
"name" : "company2",
"supportEmailAddress" : {
"key" : 1,
"emailAddrType" : "support",
"emailAddress" : "email@support.com"
}
"aliases" : [ ],
"contacts" : [ ],
"owner" : {
"key" : 2,
"name" : "owner 2",
"contacts" : [ ],
"_links" : {
"company" : {
"href" : "http://localhost:8080/company/2"
}
}
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/company/2"
},
"company" : {
"href" : "http://localhost:8080/company/2"
},
"aliases" : {
"href" : "http://localhost:8080/company/2/aliases"
},
"contacts" : {
"href" : "http://localhost:8080/company/2/contacts"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/company"
},
"profile" : {
"href" : "http://localhost:8080/profile/company"
},
"search" : {
"href" : "http://localhost:8080/company/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}