如何强制 Spring HATEOAS 资源渲染一个空的嵌入式数组?
How to force Spring HATEOAS resources to render an empty embedded array?
我有以下控制器方法:
@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
公开 Set<>
个 Exercise
个实体。当练习实体为空时,我得到一个 JSON 表示,如下所示:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/sessions/2/exercises"
}
}
}
所以基本上没有嵌入实体,而像下面这样的东西会更可取:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/sessions/2/exercises"
}
},
"_embedded": {
"exercises": []
}
}
知道如何执行吗?
Spring 默认使用 Jackson 解析器 serialize/deserialize json。根据 http://wiki.fasterxml.com/JacksonFeaturesSerialization Jackson 有一个名为 WRITE_EMPTY_JSON_ARRAYS 的功能,默认情况下启用。也许 WRITE_EMPTY_JSON_ARRAYS 在您的配置中设置为 false
。请重新检查您的消息转换器配置。
这里的问题是,如果不付出额外的努力,就无法发现空集合是 Exercise
的集合。 Spring HATEOAS 有一个助手 class 可以解决这个问题:
EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
EmbeddedWrapper wrapper = wrappers.emptyCollectionOf(Exercise.class);
Resources<Object> resources = new Resources<>(Arrays.asList(wrapper));
EmbeddedWrapper
允许您将要添加到 Resource
或 Resources
的对象显式标记为嵌入对象,甚至可能手动定义它们应该暴露的 rel。正如您在上面看到的那样,帮助程序还允许您将给定类型的空集合添加到 _embedded
子句。
可以使用 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);
}
我敢打赌它也适用于其他 ResourceAssembler。
如果你有一个 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 将注入它)。
我有以下控制器方法:
@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
公开 Set<>
个 Exercise
个实体。当练习实体为空时,我得到一个 JSON 表示,如下所示:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/sessions/2/exercises"
}
}
}
所以基本上没有嵌入实体,而像下面这样的东西会更可取:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/sessions/2/exercises"
}
},
"_embedded": {
"exercises": []
}
}
知道如何执行吗?
Spring 默认使用 Jackson 解析器 serialize/deserialize json。根据 http://wiki.fasterxml.com/JacksonFeaturesSerialization Jackson 有一个名为 WRITE_EMPTY_JSON_ARRAYS 的功能,默认情况下启用。也许 WRITE_EMPTY_JSON_ARRAYS 在您的配置中设置为 false
。请重新检查您的消息转换器配置。
这里的问题是,如果不付出额外的努力,就无法发现空集合是 Exercise
的集合。 Spring HATEOAS 有一个助手 class 可以解决这个问题:
EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
EmbeddedWrapper wrapper = wrappers.emptyCollectionOf(Exercise.class);
Resources<Object> resources = new Resources<>(Arrays.asList(wrapper));
EmbeddedWrapper
允许您将要添加到 Resource
或 Resources
的对象显式标记为嵌入对象,甚至可能手动定义它们应该暴露的 rel。正如您在上面看到的那样,帮助程序还允许您将给定类型的空集合添加到 _embedded
子句。
可以使用 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);
}
我敢打赌它也适用于其他 ResourceAssembler。
如果你有一个 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 将注入它)。