resteasy-links中的AddLinks功能实现
本文分析resteasy-links当中,AddLinks的功能实现。首先分析resteasy-links提供的RESTUtils。这个RESTUtils工具类是resteasy-link自己提供的,在项目里查找用到它的地方:
$ grep -rl 'RESTUtils' *
resteasy-links/src/main/java/org/jboss/resteasy/links/impl/LinkDecorator.java
resteasy-links/src/main/java/org/jboss/resteasy/links/impl/RESTUtils.java
$
可以看到是LinkDecorator在使用。下面是使用之处:
$ grep -rl 'LinkDecorator' *
resteasy-links/src/main/java/org/jboss/resteasy/links/impl/LinkDecorator.java
resteasy-links/src/main/java/org/jboss/resteasy/links/AddLinks.java
$
以下是LinkDecorator的具体实现:
public class LinkDecorator implements DecoratorProcessor<Marshaller, AddLinks> {
public Marshaller decorate(Marshaller target, final AddLinks annotation,
Class type, Annotation[] annotations, MediaType mediaType) {
target.setListener(new Listener() {
@Override
public void beforeMarshal(Object entity) {
UriInfo uriInfo = ResteasyContext.getContextData(UriInfo.class);
ResourceMethodRegistry registry = (ResourceMethodRegistry) ResteasyContext.getContextData(Registry.class);
// find all rest service classes and scan them
RESTUtils.addDiscovery(entity, uriInfo, registry);
}
});
return target;
}
}
可以看到decorate方法的重点是往Marshaller target里面添加一个listener。而这个listener干的事情是把RESTUtils.addDiscovery(..)方法执行一下,注入ResourceMethodRegistry。这样,RESTUtils就可以在运行时工作了。下面这个是RESTUtils的类图:

回到 LinkDecorator,它是一个DecoratorProcessor,用于decorate的Marshaller,用户给需要decorate的class标注AddLinks标记。下面是AddLinks的源代码:
package org.jboss.resteasy.links;
import org.jboss.resteasy.annotations.Decorator;
import org.jboss.resteasy.links.impl.LinkDecorator;
import javax.xml.bind.Marshaller;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Use on any JAX-RS method if you want RESTEasy to inject the RESTServiceDiscovery
* to every entity in the response. This will only inject RESTServiceDiscovery instances
* on entities that have a field of this type, but it will be done recursively on the response's
* entity.
* @author <a href="mailto:stef@epardaud.fr">Stéphane Épardaud</a>
*/
@Target( { ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER,
ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Decorator(processor = LinkDecorator.class, target = Marshaller.class)
@Documented
public @interface AddLinks {
}
查找@AddLinks使用到的地方:
$ grep -rl 'AddLinks' * | grep java
resteasy-links/src/test/java/org/jboss/resteasy/links/test/BookStoreMinimal.java
resteasy-links/src/test/java/org/jboss/resteasy/links/test/SecureBookStore.java
resteasy-links/src/test/java/org/jboss/resteasy/links/test/SecureBookStoreMinimal.java
resteasy-links/src/test/java/org/jboss/resteasy/links/test/el/BookStoreInvalidEL.java
resteasy-links/src/test/java/org/jboss/resteasy/links/test/el/BookStoreNoPackage.java
resteasy-links/src/test/java/org/jboss/resteasy/links/test/BookStore.java
resteasy-links/src/test/java/org/jboss/resteasy/links/test/IDServiceTest.java
resteasy-links/src/main/java/org/jboss/resteasy/links/impl/LinkDecorator.java
resteasy-links/src/main/java/org/jboss/resteasy/links/AddLinks.java
resteasy-links/src/main/java/org/jboss/resteasy/links/RESTServiceDiscovery.java
可以看到一些resteasy-links的tests使用到了@AddLinks功能并进行测试。后续分析这些测试就可以学习AddLinks的整套工作机制。