【问题标题】:How to force Spring HATEOAS resources to render an empty embedded array?如何强制 Spring HATEOAS 资源渲染一个空的嵌入式数组?
【发布时间】:2015-07-28 23:44:22
【问题描述】:

我有以下控制器方法:

@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE, value = "session/{id}/exercises")
public ResponseEntity<Resources<Exercise>> exercises(@PathVariable("id") Long id) {

  Optional<Session> opt = sessionRepository.findWithExercises(id);
  Set<Exercise> exercises = Sets.newLinkedHashSet();

  if (opt.isPresent()) {
    exercises.addAll(opt.get().getExercises());
  }

  Link link = entityLinks.linkFor(Session.class)
                         .slash(id)
                         .slash(Constants.Rels.EXERCISES)
                         .withSelfRel();

  return ResponseEntity.ok(new Resources<>(exercises, link));
}

所以基本上我试图为特定的Session 公开Exercise 实体的Set&lt;&gt;。但是,当练习实体为空时,我会得到这样的 JSON 表示:

{
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/sessions/2/exercises"
        }
    }
}

所以基本上没有嵌入式实体,而像下面这样的东西会更好:

{
    "_links": {
        "self": {
            "href": "http://localhost:8080/api/sessions/2/exercises"
        }
    }, 
    "_embedded": {
        "exercises": [] 
    }    
}

知道如何执行吗?

【问题讨论】:

    标签: spring spring-hateoas


    【解决方案1】:

    这里的问题是,如果不付出额外的努力,就无法找出空集合是Exercise 的集合。 Spring HATEOAS 有一个帮助类来解决这个问题:

    EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
    EmbeddedWrapper wrapper = wrappers.emptyCollectionOf(Exercise.class);
    Resources<Object> resources = new Resources<>(Arrays.asList(wrapper));
    

    EmbeddedWrapper 允许您将要添加到 ResourceResources 的对象显式标记为嵌入,甚至可以手动定义它们应该在其下公开的 rel。正如您在上面看到的,帮助程序还允许您将给定类型的空集合添加到 _embedded 子句。

    【讨论】:

    • 这会丢失泛型类型信息(这不是组装资源时的唯一情况)。我认为应该是EmbeddedWrapper&lt;T&gt; implements Resource&lt;T&gt;,但 Resource 不是接口,在我看来,这就是 Spring HATEOAS 中泛型问题的根源。
    • 对于 PagedResources 结果:List&lt;EmbeddedWrapper&gt; embedded = Collections.singletonList(wrapper); PagedResources pagedResources = new PagedResources(embedded, metadata, links);
    • 我也偶然发现了这一点,我可以使用 Object 而不是我的 EmbeddedWrapper 类型使其工作,但我真的不喜欢它。为什么这不是一个选项或默认值?当使用 spring data rest 时,空集合也是默认值。
    • @Oliver Gierke 而不是这种丑陋的解决方法,为什么不扩展构造函数呢? new Resources&lt;&gt;(Exercise.class, exercises, ...); 对我来说是可以接受的。
    • 请为github.com/spring-projects/spring-hateoas/issues/522投票(只需点击“添加您的反应”按钮)
    【解决方案2】:

    可以使用 PagedResourceAssembler::toEmptyResource() 方法。例如,以下工作:

    Page<EWebProduct> products = elasticSearchTemplate.queryForPage(query, EWebProduct.class);
    
    if(!products.hasContent()){
                PagedResources pagedResources = pageAssembler.toEmptyResource(products, WebProductResource.class,baseLink);
                return new ResponseEntity<PagedResources<WebProductResource>>(pagedResources, HttpStatus.OK);
    }
    

    我敢打赌它也适用于其他 ResourceAssemblers。

    【讨论】:

      【解决方案3】:

      如果你有一个Page,你可以这样转换:

       public static <T> PagedModel<EntityModel<T>> toModel(PagedResourcesAssembler<T> assembler,
                                                      Page<T> page) {
              if (!page.isEmpty()) {
                  return assembler.toModel(page);
              } else {
                  // toEmptyModel renders the _embedded field (with an empty array inside)
                  return (PagedModel<EntityModel<T>>) assembler.toEmptyModel(page, TenantSubscriptionResponseDto.class);
              }
          }
      

      (你可以通过简单地将它作为参数添加到Controller方法中来获得PagedResourcesAssembler 汇编器,Spring会注入它。

      【讨论】:

        【解决方案4】:

        Spring 默认使用 Jackson 解析器来序列化/反序列化 json。根据http://wiki.fasterxml.com/JacksonFeaturesSerialization Jackson 有一个名为 WRITE_EMPTY_JSON_ARRAYS 的功能,默认启用。也许 WRITE_EMPTY_JSON_ARRAYS 在您的配置中设置为 false。请重新检查您的消息转换器配置。

        【讨论】:

        • 我很确定不是这个,不是 JSON 数组,而是 Spring HATEOAS 中 _embedded 的整个层次结构。
        猜你喜欢
        • 2014-11-09
        • 2015-12-03
        • 1970-01-01
        • 1970-01-01
        • 2021-07-17
        • 2016-11-05
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        相关资源
        最近更新 更多