JAX-RS中使用@Required Annotation所需的@QueryParam在ContainerRequestFilter中不起作用

时间:2016-07-28 15:06:11

标签: java rest jax-rs wildfly

我遇到了同样的问题并尝试了Zero3的解决方案(Required @QueryParam in JAX-RS (and what to do in their absence)),但在我的情况下parameter.isAnnotationPresent(Required.class)总是返回false

这是我的必需注释:

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;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Required {
    // This is just a marker annotation, so nothing in here.
}

我还尝试使用BeanParam注释并相应地修改了过滤器,但结果相同 - null始终获得isAnnotionPresen

我正在使用WildFly 9(RESTeasy)自动注册请求过滤器。

我的REST资源如下所示:

@GET
@Path("/{type}/{id}")
public Response getAllByTypeAndId(@Required @BeanParam RequiredQueryParams requiredQueryParams,
                                  @Required @QueryParam("mandant") String mandant,
                                  @PathParam("type") String type,
                                  @PathParam("id") Long id) {
...doSomething...
}

运行调试器为参数.declaredAnnotations显示HashMap中BeanParam的两个条目:

0 interface my.annotations.Required -> @my.annotations.Required()
1 interface javax.ws.rs.BeanParam -> @javax.ws.rs.BeanParam()

QueryParam

0 interface my.annotations.Required -> @my.annotations.Required()
1 interface javax.ws.rs.QueryParam -> @javax.ws.rs.QueryParam(value=mandant)

欢迎任何提示 - 谢谢!

2 个答案:

答案 0 :(得分:1)

根据您问题中的信息和评论中的其他信息,我想我对这里发生的事情有一个大概的了解。让我们从原始问题开始:

  

parameter.isAnnotationPresent(Required.class)始终返回false

现在让我们看一下Java 8中AnnotatedElement#isAnnotationpresent(Class<? extends Annotation>)的实现:

default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
    return getAnnotation(annotationClass) != null;
}

这引导我们实施Parameter#getAnnotation(Class<T>)

public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
    Objects.requireNonNull(annotationClass);
    return annotationClass.cast(declaredAnnotations().get(annotationClass));
}

Object#cast(Object)的文档指出:

  

铸造后@return对象,如果obj为null,则返回null

所以看起来declaredAnnotations().get(annotationClass)返回null。 Parameter#declaredAnnotations()返回Map<Class<? extends Annotation>, Annotation>,实际上是HashMap,包含注释类到相关参数的注释实例的映射。 Map#get(Object)的文档指出:

  

@return指定键映射到的值,如果此映射不包含键的映射,则返回null

这与您的评论一致,该评论指出您的Required.class对象与相关参数上存在的Required注释的类对象不相等(也没有相同的哈希码)。

这引出了我们问题的核心:为什么你的注释类不等于它自己?毕竟,Object#equals(object)的实现方式如下:

public boolean equals(Object obj) {
    return (this == obj);
}

对于equals(Object)的{​​{1}}工作实现Class<T>对象(继承实现),假设每个类只有一个这样的类对象。据我所知,在比较由同一个类加载器加载的类对象时,情况也是如此。这可能是在Java规范中的某个地方指定的,也可能是某些类的加载文档。我不知道,但我们假设这就是事情的运作方式。

但是,在更高级的应用程序中,类可能会由应用程序的各个层上的不同类加载器加载,从而使单例假设无效,从而导致您遇到的问题。所以我的猜测是WildFly应用程序服务器使用不同的类加载器加载了Required注释,而不是后来用来获取Required.class对象引用的类加载器。

我对WildFly知之甚少,但我确实知道Java应用程序服务器通常依赖于一些非常官僚的类加载器层次结构来加载类(出于安全性和其他原因)。我建议查看WildFly文档,希望有更多相关信息。

TL; DR:我认为您的Required.class对象代表了Required注释类的副本,而不是参数中存在的副本。确保使用相同的类加载器来加载它们。

答案 1 :(得分:0)

作为parameter.isAnnotationPresent(Required.class)中非工作ContainerRequestFilter的解决方法我现在正在使用此方法:

private boolean isRequired(Parameter parameter) {
    for (Annotation annotation : parameter.getDeclaredAnnotations()) {
        if (Required.class.getName().equals(annotation.annotationType().getName())) {
            return true;
        }
    }
    return false;
}

无论如何我想知道为什么isAnnotionaPresent()不起作用?!