如何解决为什么ResponseBody和Jackson ObjectMapper不返回相同的输出?
我正在使用Spring Boot应用程序。
我的控制器中有一个返回一些资源的方法:
@ResponseBody
@Transactional(rollbackFor = Exception.class)
@GetMapping(value="data/{itemId}/items",produces="application/json")
public Resources<DataExcerpt> listMyData(@PathVariable("debateId") UUID debateId)){
List<DataExcerpt> dataExcerpts = dataService
.listMyData(id)
.stream()
.map(d -> this.projectionFactory.createProjection(DataExcerpt.class,d))
.collect(Collectors.toList());
return new Resources<>(dataExcerpts);
}
这将以以下形式返回内容:
{
"_embedded" : {
"items" : [ {
"position" : {
"name" : "Oui","id" : "325cd3b7-1666-4c44-a55f-1e7cc936a3aa","color" : "#51B63D","usedForPositionType" : "FOR_CON"
},"id" : "5aa48cfb-5505-43b6-b0a9-5481c895e2bf","item" : [ {
"index" : 0,"id" : "43c2dcd0-6bdb-43b0-be97-2a40b99bc753","description" : {
"id" : "021ad7cd-4bf1-4dce-9ea7-10980440a049","title" : "Item description","modificationCount" : 0
}
} ],"title" : "Item title","originalMaker" : {
"username" : "jeremieca","id" : "cfae1a04-cb00-4ad4-b4e8-6971eff64807","avatarUrl" : "user-16","_links" : {
"self" : {
"href" : "http://some-api-link"
}
}
},"itemState" : {
"itemState" : "LIVE",},"opinionImprovements" : [ ],"sourcesJson" : [ ],"makers" : [ {
"username" : "jeremieca","_links" : {
"self" : {
"href" : "http://some-api-link"
}
}
} ],"modificationsCounter" : 1,"originalBuyer" : "fd9b68f9-7c0c-4120-869c-c63d1680e7f0","updateTrace" : {
"createdOn" : "2020-05-25T08:12:56.846+0000","createdBy" : "cfae1a04-cb00-4ad4-b4e8-6971eff64807","updatedOn" : "2020-05-25T08:12:56.845+0000","updatedBy" : "cfae1a04-cb00-4ad4-b4e8-6971eff64807"
},"_links" : {
"self" : {
"href" : "some-api-link","templated" : true
},"newEditions" : {
"href" : "some-api-link","makers" : {
"href" : "http://some-api-link"
},"originalMaker" : {
"href" : "http://some-api-link"
}
}
} ]
}
}
另一方面,我也想在Redis中缓存这些答案,以避免每次都运行整个过程。为此,我正在使用Jackson的ObjectMapper将我的资源转换为字符串
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValueAsString(controller.listMyData(id)); // the same function as above
writeValueAsString 输出的结构与第一个不同:
"{content: [...],_links: []}"
因此,当我从具有缓存内容的API返回时,其结构与控制器在没有缓存的情况下向我发送的结构不同。
那是为什么? Jackson是否无法正确将Resources Hateoas结构写为字符串? 我想念什么吗?
编辑:
这是Resources.class:
package org.springframework.hateoas;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import org.springframework.util.Assert;
@XmlRootElement(name = "entities")
public class Resources<T> extends ResourceSupport implements Iterable<T> {
private final Collection<T> content;
protected Resources() {
this(new ArrayList(),(Link[])());
}
public Resources(Iterable<T> content,Link... links) {
this(content,(Iterable) Arrays.asList(links));
}
public Resources(Iterable<T> content,Iterable<Link> links) {
Assert.notNull(content,"Content must not be null!");
this.content = new ArrayList();
Iterator var3 = content.iterator();
while (var3.hasNext()) {
T element = var3.next();
this.content.add(element);
}
this.add(links);
}
public static <T extends Resource<S>,S> Resources<T> wrap(Iterable<S> content) {
Assert.notNull(content,"Content must not be null!");
ArrayList<T> resources = new ArrayList();
Iterator var2 = content.iterator();
while (var2.hasNext()) {
S element = var2.next();
resources.add(new Resource(element,new Link[0]));
}
return new Resources(resources,new Link[0]);
}
@XmlAnyElement
@XmlElementWrapper
@JsonProperty("content")
public Collection<T> getContent() {
return Collections.unmodifiableCollection(this.content);
}
public Iterator<T> iterator() {
return this.content.iterator();
}
public String toString() {
return String.format("Resources { content: %s,%s }",this.getContent(),super.toString());
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj != null && obj.getClass().equals(this.getClass())) {
Resources<?> that = (Resources) obj;
boolean contentEqual = this.content == null ? that.content == null : this.content.equals(that.content);
return contentEqual ? super.equals(obj) : false;
} else {
return false;
}
}
public int hashCode() {
int result = super.hashCode();
result += this.content == null ? 0 : 17 * this.content.hashCode();
return result;
}
}
谢谢。
解决方法
原因是,当Spring使用HATEOAS配置MVC或Spring Boot应用程序时,它将配置自定义的Jackson模块,以处理Resources
类以及对象的其余部分的序列化和反序列化过程API公开的模型。
如果要获得类似的结果,可以执行以下操作:
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
// ...
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jackson2HalModule());
objectMapper.writeValueAsString(controller.listMyData(id));
,
我的建议是提供扩展hateoas
'ResourceSupport
的POJO,(反序列化)将通过POJO进行。
ResourcesJson(根元素)
public class ResourcesJson extends ResourceSupport {
@JsonProperty("_embedded")
private ResourcesEmbeddedListJson embedded;
//getters and setters
}
嵌入“包装器”
public class ResourcesEmbeddedListJson extends ResourceSupport {
private Collection<T> content;
//getters and setters
}
或者,如果您不想让它变得丑陋,可以使用此org.springframework.hateoas.client.Traverson
组件。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。