RESTEasy POJO json" embedded"对象作为链接/ id' s

时间:2015-07-23 15:51:41

标签: java json jpa jax-rs resteasy

我在如何将POJO中的嵌入对象表示为链接而不是直接嵌入它们时遇到了问题。

我与放弃提供商保持一致的RESTEasy。全部在3.0.11.Final版本。

Book.java POJO

public class Book
{
    private  Integer bookId;
    private  String title;
    private  Author author;
}

Author.java POJO

public class Author
{
    private  Integer authorId;
    private  String name;
}

当我使用RESTEasy生成书籍的XML或JSON表示时,我看到了:

<book>
    <bookId>1</bookId>
    <title>My book</title>
    <author>
        <authorId>2</authorId>
        <name>Andre Schild</name>
    </author>
</book>

但我不想这样做:

<book>
    <bookId>1</bookId>
    <title>My book</title>
    <author author="2"><atom:link rel="list" href="http://.../rest/authors/2"/></author>
</book>

由于我们使用JPA进行db后端连接,因此POJO直接包含作者POJO,而不仅仅是ID。

我也用球衣做了一些测试,但也遇到了同样的问题

1 个答案:

答案 0 :(得分:3)

由于没有人知道作者字段和URI之间的关系,因此不能自动发生。使用插件reasteasy-links,您可以使用两个注释@AddLinks@LinkResource来定义这些关系。您可以找到more information in the docs

此插件不会更改字段的值,但会向实体添加原子链接。它也适用于Jettison和JAXB。

这是一个使用Jackson的快速+脏示例,它真正取代了作者字段的值。

我们将使用此注释来定义POJO和资源之间的关系:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Linked {

    String path();

    String rel() default "";

}

此注释需要应用于Author类:

@Linked(path = "/rest/authors/{authorId}", rel = "list")
public class Author {}

在Book字段中,我们需要添加我们想要使用的Serializer:

public class Book {
    @JsonSerialize(using = LinkedSerializer.class)
    private Author author;
}

Serializer看起来像这样:

public class LinkedSerializer extends JsonSerializer<Object> {

    @Override
    public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        Linked linked = value.getClass().getAnnotation(Linked.class);
        Matcher matcher = Pattern.compile("\\{(.+?)\\}").matcher(linked.path());
        if (!matcher.find()) {
            return;
        }
        String param = matcher.group(1);
        try {
            Field field = value.getClass().getDeclaredField(param);
            field.setAccessible(true);
            Object paramValue = field.get(value);
            String path = linked.path().replaceFirst("\\{.*\\}", paramValue.toString());
            jgen.writeStartObject();
            jgen.writeFieldName("href");
            jgen.writeString(path);
            jgen.writeFieldName("rel");
            jgen.writeString(linked.rel());
            jgen.writeEndObject();
        } catch (NoSuchFieldException | SecurityException | IllegalAccessException ex) {
            throw new IllegalArgumentException(ex);
        }
    }

}

注意:我们在这里只使用路径而不是完整的URI,因为我们不知道基本URI,并且无法在此序列化程序中注入UriInfo或ServletRequest。但是你可以通过ResteasyProviderFactory.getContextData(HttpServletRequest.class)获得ServletRequest。