我有两门课:
public class A{
private String property;
private Set<B> bs = new HashSet<B>();
}
public class B{
private String property;
private A owner;
}
我创建了一个基本的 JAX-RS + Spring boot 应用程序,我想返回 A。
问题是 A 包含 Set<B>
,所以我遇到了无限嵌套级别问题。
我找到了一个解决方案:提供一个链接而不是资源本身,这样我就可以得到这个:
{ "property" : "value", "bs" : "http://mywebsite/api/a/2/bs" }
而且我没有遇到任何嵌套级别问题,因为每个级别都是单独序列化的。
如何在我的 JAX-RS 应用程序中实现这样的事情?我什么也没找到,但我知道这是可能的,因为 Spring Data Neo4j REST正在使用它,并且效果很好。
最佳答案
我可以想到以下可能的方法来实现这一目标。
使用 XmlAdapter 在序列化期间将集合转换为 URI
@XmlRootElement
public class A
{
private int id;
private String property;
@XmlJavaTypeAdapter(BsAdapter.class)
private Set<B> bs = new HashSet<B>();
}
public class BsAdapter extends XmlAdapter<URI, Set<B>>
{
@Override
public Set<B> unmarshal(URI v) throws Exception
{
return new HashSet<>();
}
@Override
public URI marshal(Set<B> v) throws Exception
{
return URI.create(
Optional.ofNullable(v)
.filter(b -> !b.isEmpty())
.map(b -> "/" + b.stream().findFirst().get().getOwner().getId() + "/bs")
.orElse(""));
}
}
如果 A 的 id 是 URI 的一部分,则仅当集合不为空时才能检索它。结果是相对 URI,因为没有可用的进一步信息。
作为替代方法,手动设置 URI。
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class A
{
private int id;
private String property;
@XmlTransient
private Set<B> bs = new HashSet<B>();
@XmlElement(name = "bs")
private URI bsUri;
}
并设置 URL,如下所示:
@Context
UriInfo uriInfo;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getA()
{
// ...
a.setBsUri(UriBuilder.fromUri(uriInfo.getAbsolutePath())
.path("a")
.path("{id}")
.path("bs")
.build(2));
return Response.ok().entity(a).build();
}
或者,如果 HTTP header 中的链接也可以,只需这样做即可,这样您就不必使用 URI 扩展 A 类。
return Response.ok().entity(a).link(UriBuilder.fromUri(uriInfo.getAbsolutePath())
.path("a")
.path("{id}")
.path("bs")
.build(2), "bs").build();
关于java - 提供链接而不是序列化集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35435710/