RepositoryRestMvcConfiguration 的 ObjectMapper 与 Spring Boot 默认的 ObjectMapper?

Posted

技术标签:

【中文标题】RepositoryRestMvcConfiguration 的 ObjectMapper 与 Spring Boot 默认的 ObjectMapper?【英文标题】:RepositoryRestMvcConfiguration's ObjectMapper vs. Spring Boot default ObjectMapper? 【发布时间】:2017-05-01 11:14:07 【问题描述】:

我正在使用 RepositoryRestMvcConfiguration 来微调其余存储库的行为:

@Configuration
public class WebConfig extends RepositoryRestMvcConfiguration 
    @Override
    protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) 
      config.setReturnBodyOnCreate(true);

缺点是扩展类引入了它自己的 ObjectMapper bean,导致here 中描述的冲突。推荐的解决方法是使用扩展类将 ObjectMapper bean 标记为 @Primary,但是来自 RepositoryRestMvcConfiguration 的 bean 在序列化嵌套实体时具有不同的行为。

让我们假设以下实体:

@Entity class Parent 
    @Id Long id;
    @OneToMany @JsonManagedReference List<Child> children;
    // usual getters and setters for fields...


@Entity class Child 
    @Id Long id;
    @ManyToOne @JsonBackReference Parent parent;
    @ManyToOne @JsonBackReference School school;
    public getSchooldId()  return school.getId(); 
    // usual getters and setters for fields...


@Entity class School 
    @Id Long id;
    @OneToMany @JsonManagedReference List<Child> children;
    // usual getters and setters for fields...
 

使用默认的 Spring Boot ObjectMapper 会得到预期的结果(渲染嵌套实体):

"id": 1, "children":["id":2, "schoolId":7,"id":3, "schooldId":8]

但是来自RepositoryRestMvcConfiguration 的 ObjectMapper 忽略了子实体:

"id": 1

配置RepositoryRestMvcConfiguration ObjectMapper 以实现与 Spring Boot 默认相同的行为的正确方法是什么?

【问题讨论】:

【参考方案1】:

RepositoryRestMvcConfiguration 创建两个 objectMapper 对象。

    objectMapper 供内部框架使用。 halObjectMapper 负责渲染集合Resources 和Links。

您可以尝试通过使用限定符自动装配 objectMapper 来实现所需的结果:

@Qualifier('_halObjectMapper')

编辑:用于渲染关联/嵌套属性

默认情况下,Spring data-rest 不会呈现关联(reference),因为它们在 HATEOAS 规范下可用(您的 json 的 _link 部分)。 如果您想呈现关联,您只需要使用 Projections

这个Person有几个属性:id是主键,firstName和lastName是数据属性,address是指向另一个域对象的链接

@Entity
public class Person 

  @Id @GeneratedValue
  private Long id;
  private String firstName, lastName;

  @OneToOne
  private Address address;
  …

将被渲染:

   
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : 
    "self" : 
      "href" : "http://localhost:8080/persons/1"
    ,
    "address" : 
      "href" : "http://localhost:8080/persons/1/address"
    
    
    

默认情况下,Spring Data REST 将导出这个域对象,包括它的所有属性。 firstName 和 lastName 将作为它们的纯数据对象导出。关于地址属性有两个选项。一种选择是也为地址定义一个存储库。

还有另一条路线。如果 Address 域对象没有自己的存储库定义,Spring Data REST 将直接在 Person 资源中内联数据字段。

【讨论】:

不幸的是,这没有帮助。 1) objectMapper 也是 @Autowired 其他 Spring Boot 代码(例如,org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration 中的构造函数) 2) halObjectMapper 可以使用 @Override @Bean @Primary public ObjectMapper objectMapper() return super.halObjectMapper(); 设置为默认值,但结果与其他 objectMapper - 嵌套实体不呈现为 JSON 好的,现在我明白你的问题了。 这对于 Spring Data Rest 存储库端点是正确的,但不适用于 ObjectMapper 的独立使用(例如,在控制器中自动装配)。默认的 ObjectMapper(在 RepositoryRestMvcConfiguration 未扩展时可通过自动装配获得)即使没有投影也会按预期呈现嵌套实体。一旦我出于配置目的扩展RepositoryRestMvcConfiguration,objectMapper/halObjectMapper 在独立模式下使用时不再呈现嵌套实体。 我修复了限定符,它以_开头

以上是关于RepositoryRestMvcConfiguration 的 ObjectMapper 与 Spring Boot 默认的 ObjectMapper?的主要内容,如果未能解决你的问题,请参考以下文章