我有一个扩展RepresentationModel的示例响应类。在某些情况下,我不会在响应中添加任何hateoas链接。在这种情况下,我在json响应中得到一个空的链接字段
"链接":[]
我尝试添加";JsonInclude.Include.NON_EMPTY";到响应类,但由于链接字段是RepresentationModel中的最终字段,因此它仍然在响应中引入空的链接字段。
如何避免响应中出现此空链接字段?
首先确保您有充分的理由使用媒体类型为application/json
的链接,而不是为HAL(application/hal+json
(等超媒体构建的媒体类型。
虽然RepresentationModel
的字段为List<Link>
,但getter返回的是Links
而不是List<Link>
。Jackson将其视为简单类型(使用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();
}
}
一种解决方案是覆盖gettergetLinks()
并使用customm过滤器。
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中。
第二个解决方案可能是自定义的mixin,就像Spring HATEOAS已经为HAL构建的一样。相关代码为:
- RepresentationModelMixin
- Jackson2HalModule.HalLinkListSerializer
- 插孔2半模块
- HalMediaType配置
第二个解决方案要复杂得多。这就是为什么我推荐像HAL这样的媒体类型,Spring HATEOAS已经为其提供了良好的配置。
根据@yejianfengblue的回答,我创建了一个如下所示的自定义表示模型,并从响应java类而不是HateoasRepresentationModel
扩展了这个CustomRepresentationModel
。
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();
}
}
}