【问题标题】:Java EE Interceptor change return typeJava EE 拦截器更改返回类型
【发布时间】:2019-07-01 20:08:48
【问题描述】:

我希望我的 Java EE 拦截器返回与 JAX-RS 服务方法中定义的类型不同的类型,但我收到了 ClassCastException。这是一个最小的例子:

    package com.example;

    @Augment
    @GET
    @Path("/me")
    @Produces(MediaType.APPLICATION_JSON)
    public User me() {
        return new User(...);
    }

    @Augment
    @Interceptor
    public class AugmentInterceptor {
        @AroundInvoke
        public Object intercept(InvocationContext ctx) throws Exception {
            runInNewResourceContext(resourceContext -> {
                Object original = ctx.proceed(); // is a User object
                return MoreData(original, resourceContext.getStats());
            }); // context resources are cleaned-up after the lambda runs
        }
    }

java.lang.ClassCastException: com.example.MoreData 不能 转换为 com.example.User 在 com.example.Service$Proxy$_$$_WeldSubclass.me(未知 来源)~[Service.class:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) ~[?:1.8.0_201] 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201] 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201] 在 java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201] 在 org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:52) ~[jersey-server.jar:?] 在 org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:124) ~[jersey-server.jar:?] 在 org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:167) ~[jersey-server.jar:?] 在 org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:219) ~[jersey-server.jar:?] 在 org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:79) ~[jersey-server.jar:?] 在 org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:469) ~[jersey-server.jar:?] 在 org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:391) ~[jersey-server.jar:?] 在 org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:80) ~[jersey-server.jar:?] 在 org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:253) [jersey-server.jar:?] 在 org.glassfish.jersey.internal.Errors$1.call(Errors.java:248) [jersey-common.jar:?] 在

我猜这是因为我的 Java EE 服务器是如何实现的:拦截器是从我的服务类的代理中调用的,并且代理需要返回代理类中定义的类型。

但是,从阅读 JSR 318 拦截器规范中可以看出,我认为这不是设计限制。我在规范中没有看到任何关于返回类型/值的信息,也没有提到“代理”这个词。

JSR 318 拦截器规范:

https://jcp.org/en/jsr/detail?id=318

https://download.oracle.com/otndocs/jcp/interceptors-1_2A-mrel3-spec/

顺便说一句,我使用的是 Payara 5.192(它使用 Jersey 2.29),但我怀疑它是否相关。

问题:

  1. 我是否遗漏了规范中的某些内容?或者是否有任何其他资源记录在案?

  2. 其他 Java EE 服务器是否以不同的方式实现拦截器?

【问题讨论】:

    标签: jakarta-ee jax-rs


    【解决方案1】:

    一般来说,JSR-318 拦截器不能更改方法的返回类型。尽管我无法在规范中明确找到这一点,但我确信这是由于 Java 语言限制造成的。例如。即使你说服拦截器机制返回一个不兼容的对象类型,被拦截方法的调用者无论如何都会得到ClassCastException

    从您展示的代码中,很明显您想要丰富 JAX-RS 方法的返回资源。对于另一种“拦截器”,即 JAX-RS 过滤器,这绝对是可行的。特别针对您的情况,ContainerResponseFilter 可以在调用资源方法后拦截调用。它可以使用ContainerResponseContext.getEntity() 访问返回的实体,并用ContainerResponseContext.setEntity(Object) 将其替换为MoreData 对象。

    示例代码:

    @Provider
    @Augment
    public class AugmentFilter implements ContainerResponseFilter {
        @Override
        public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
            Object original = responseContext.getEntity();
            responseContext.setEntity(MoreData(original));
        }
    }
    

    查看规范以了解绑定注释如何为 JAX-RS 工作,您可能需要消除一些缺陷,但原则是不变的。

    【讨论】:

    • 谢谢,但是 JAX-RS 响应过滤器对我不起作用;我应该指定的。我给出的极其简化的示例代码并没有表明拦截器需要处理对服务方法(ctx.proceed)本身的调用。
    【解决方案2】:

    我意识到我可以将me 的返回类型更改为Objectjavax.ws.rs.core.Response 或者我自己的泛型类型ReturnTypeHack<User>(类型擦除应该使AugmentInterceptor 返回ReturnTypeHack<MoreData>),但是我' d 而不是为了在服务中保留 Java 返回类型信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-23
      • 1970-01-01
      • 2021-04-17
      • 2013-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多