Возвращаемый тип перехватчика Java EE - PullRequest
0 голосов
/ 01 июля 2019

Я хочу, чтобы мой перехватчик 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:?] В 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 $ статических $ 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 (которая использует Джерси 2.29), однако я сомневаюсь, что это уместно.

Вопросы:

  1. Я что-то упустил в спецификации? Или есть другой ресурс, где это задокументировано?

  2. По-разному ли на других серверах Java EE используются перехватчики?

Ответы [ 2 ]

1 голос
/ 02 июля 2019

В общем случае перехватчики JSR-318 не могут изменить тип возвращаемого значения метода. Хотя я не могу найти это явно в спецификации, я вполне уверен, что это связано с ограничениями языка Java. Например. даже если вы убедите механизм перехватчика вернуть несовместимый тип объекта, вызывающий перехваченный метод все равно получит ClassCastException.

Из кода, который вы показали, очевидно, что вы хотите обогатить возвращаемый ресурс метода JAX-RS. Это абсолютно выполнимо с другим типом «перехватчика», фильтрами JAX-RS. Специально для вашего случая ContainerResponseFilter может перехватить вызов после вызова метода ресурса. Он может получить доступ к возвращенному объекту с помощью ContainerResponseContext.getEntity() и заменить его объектом MoreData на ContainerResponseContext.setEntity(Object).

Пример кода:

@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, и вам может понадобиться сгладить некоторые задержки, но принцип остается в силе.

0 голосов
/ 01 июля 2019

Я понимаю, что могу изменить тип возвращаемого значения me на Object или javax.ws.rs.core.Response или, возможно, мой собственный универсальный тип ReturnTypeHack<User> (стирание типа должно позволить AugmentInterceptor возвращать ReturnTypeHack<MoreData>), но я ' Скорее, не для того, чтобы сохранить информацию о типе возврата Java в сервисе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...