在春季启动restapi响应中排除空的Hateoas“链接”

问题描述

我有一个扩展RepresentationModel的示例响应类。在某些情况下,我不会在响应中添加任何仇恨链接在这种情况下,我在json响应中得到一个链接字段

链接”:[]

我尝试在响应类中添加“ JsonInclude.Include.NON_EMPTY”,但是由于links字段在RepresentationModel中是最终的,因此它仍然在响应中带来了空的links字段。

如何避免响应中的空白链接字段?

解决方法

首先请确保您有充分的理由使用媒体类型为application/json而不是media type built for hypermedia的链接,例如HAL(application/hal+json)。

尽管RepresentationModel的字段为List<Link>,但getter返回Links而不是List<Link>。杰克逊将其视为简单类型(使用JsonSerializer)而不是集合类型(使用CollectionSerializer),因此JsonInclude.Include.NON_EMPTY不能正常工作。>

public class RepresentationModel<T extends RepresentationModel<? extends T>> {

    private final List<Link> links;

    @JsonProperty("links")
    public Links getLinks() {
        return Links.of(links);
    }
}

public class Links implements Iterable<Link> { }

public abstract class JsonSerializer<T> {
    public boolean isEmpty(SerializerProvider provider,T value) {
        return (value == null);
    }
}

public class CollectionSerializer {
    @Override
    public boolean isEmpty(SerializerProvider prov,Collection<?> value) {
        return value.isEmpty();
    }
}

一种解决方案是覆盖吸气剂getLinks()并使用自定义过滤器。

class User extends RepresentationModel<User> {

    // ...

    @JsonProperty("links")
    // if links is an empty JSON array,exclude it
    @JsonInclude(value = JsonInclude.Include.CUSTOM,valueFilter = EmptyLinksFilter.class)
    @Override
    public Links getLinks() {
        return super.getLinks();
    }
}

/* The word "filter" is a bit ambiguous (included? or excluded?).
Here when the equals() of this class return true,the value will be excluded. 
Choose a class name to make yourself comfortable. */
class EmptyLinksFilter{

    @Override
    public boolean equals(Object obj) {

        if (obj == null || !(obj instanceof Links)) {
            return false;
        }
        Links links = (Links) obj;
        return links.isEmpty();
    }
}

完整代码位于Github中。

第二个解决方案可能是自定义混合,就像Spring HATEOAS已经为HAL构建的一样。相关代码为:

  • RepresentationModelMixin
  • Jackson2HalModule.HalLinkListSerializer
  • Jackson2HalModule
  • HalMediaTypeConfiguration

第二种解决方案非常复杂。这就是为什么我建议像HAL这样的媒体类型,对于这些类型,Spring HATEOAS已经具有良好的配置。

,

根据@yejianfengblue的回答,我创建了如下的自定义表示模型,并从响应Java类而不是Hateoas CustomRepresentationModel扩展了此RepresentationModel

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.lang.NonNull;

public class CustomRepresentationModel<T extends CustomRepresentationModel<? extends T>> extends
    RepresentationModel<T> {

  @JsonProperty("_links")
  @JsonInclude(value = JsonInclude.Include.CUSTOM,valueFilter = NonEmptyLinksFilter.class)
  @NonNull
  @Override
  public Links getLinks() {
    return super.getLinks();
  }

  static class NonEmptyLinksFilter {

    @Override
    public boolean equals(Object obj) {
      if (!(obj instanceof Links)) {
        return false;
      }
      Links links = (Links) obj;
      return links.isEmpty();
    }

    @Override
    public int hashCode() {
      return super.hashCode();
    }
  }

}