Получите доступ к аргументам метода ресурса из фильтра или перехватчика Джерси. Или используйте АОП с методом ресурса - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь обогащать MDC SLF4J при каждом запросе идентификатором пользователя. Проблема заключается в том, что идентификатор можно передавать разными способами, иногда в качестве параметра пути, иногда в теле, а иногда вводить с помощью пользовательского ValueFactoryProvider, который сначала его расшифровывает.

Если бы я мог как-то получить доступ ко всем введенным (то есть уже десериализованным ) значениям параметров, я мог бы легко обработать все эти случаи.

1008 * Е.Г. *

Для такого ресурса, как:

@GET
//@Encrypted params are injected by a custom ValueFactoryProvider
public Something getSomething(@Encrypted("userId") String userId) {
    return ...;
}

@POST
public Something getSomething(@RequestBody RequestWithUserId requestWithUserId) {
    return ...;
}

Я мог бы иметь фильтр, такой как:

public class MdcFilter implements ContainerRequestFilter, ContainerResponseFilter {

    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        Method theMethod = resourceInfo.getResourceMethod();
        for (Parameter parameter : theMethod.getParameters()) {
            //Deal with the @Encrypted case
            if (parameter.isAnnotationPresent(Encrypted.class) && parameter.getAnnotation(Encrypted.class).value().equals("userId")) {
                MDC.put("userId", somehowGetTheValue());
            }
            //Deal with the @RequestBody case
            if (parameter.isAnnotationPresent(RequestBody.class) && parameter.getType().equals(RequestWithUserId.class)) {
                MDC.put("userId", ((RequestWithUserId)somehowGetTheValue()).getUserId());
            }
            ... //other possibilities
        }
    }

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        MDC.clear();
    }
}

Но я не вижу способа реализовать somehowGetTheValue с помощью ContainerRequestFilter перехватчика или чего-то еще ...

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Джерси использует HK2 для защиты зависимостей. И HK2 имеет AOP поддержку . Один вариант для вашего варианта использования будет использовать эту поддержку АОП. Все, что вам нужно сделать, это реализовать MethodInterceptor и InterceptionService. В MethodInterceptor вы можете получить все аргументы из MethodInvocation и вы можете получить аннотацию параметра из Method

class MyMethodInteceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        Object[] args = invocation.getArguments();

        // do your logging or whatever with the args.

        // invoke method and get return value.
        Object returnValue = invocation.proceed();
        // if you want to do something with the return
        // value before returning it, you can.

        return returnValue;
    }
}

Чтобы использовать перехватчик, вы настраиваете InterceptionService.

public class MyInterceptionService implements InterceptionService {

    private final static MethodInterceptor METHOD_INTERCEPTOR 
            = new MyMethodInterceptor();
    private final static List<MethodInterceptor> METHOD_LIST
            = Collections.singletonList(METHOD_INTERCEPTOR);

    @Override
    public Filter getDescriptorFilter() {
        return BuilderHelper.allFilter();
    }

    @Override
    public List<MethodInterceptor> getMethodInterceptors(Method method) {
        // you implement shouldIntercept
        if (shouldIntercept(method)) {
            return METHOD_LIST;
        }
        return null;
    }

    @Override
    public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> constructor) {
        return null;
    }
}

Вы определяете, какой метод должен быть перехвачен в методе getMethodInterceptors(). Если метод должен быть перехвачен, тогда вернуть список перехватчиков, в противном случае вернуть ноль. Обычный способ справиться с этим - создать пользовательскую аннотацию и просто аннотировать метод. В приведенном выше методе просто отметьте

if (method.isAnnotationPresent(YourAnno.class)) {
    return METHOD_LIST;
}

Чтобы все это заработало, вам просто нужно зарегистрировать InteceptionService в HK2. Вы можете сделать это в AbstractBinder, который используется в приложении Джерси для настройки вашего DI.

ResourceConfig config = new ResourceConfig();
config.register(new AbstractBinder() {
    @Override
    protected void configure() {
        bind(MyInterceptionService.class)
                .to(InterceptionService.class)
                .in(Singleton.class);
    }
});

Вы можете увидеть полный пример в этом репозитории GitHub . Существует также официальный пример на сайте HK2. Просто посмотрите ссылку «Поддержка AOP» вверху поста.

0 голосов
/ 27 августа 2018

Вы можете получить это так

StringWriter stringWriter = new StringWriter();
IOUtils.copy(new InputStreamReader(requestContext.getEntityStream()), stringWriter);
System.out.println(stringWriter.toString());// String representation of the payload
requestContext.setEntityInputStream(new ByteArrayInputStream(requestEntity));

По сути, идея состоит в том, чтобы скопировать поток и выполнить любую обработку, а затем вернуть поток обратно. Потому что, если вы этого не сделаете, то в вашем методе контроллера вы получите null, потому что поток уже прочитан.

...