Как внедрить объект в контекст запроса Джерси?

У меня есть такой сценарий, в котором я хочу написать фильтр, и я хочу, чтобы этот фильтр вставлял некоторый объект в текущий запрос и передавал его так, чтобы, когда класс ресурса получал запрос, он мог использовать объект.

Класс фильтра

@Override
public void filter(ContainerRequestContext request) throws IOException {
    MyObject obj = new MyObject();
    // Inject MyObject to request which I dont know how
}

Ресурсный класс

@PUT @Consumes("application/json")
@Path("/")
public String create(
        JSONParam sample,
        @Context MyObject obj) {

    System.out.println(obj.getName());

    return "";
}

2 ответа

Решение

Вы могли бы просто использовать ContainterRequestContext.setProperty(String, Object), Затем просто введите ContainerRequestContext

@Override
public void filter(ContainerRequestContext crc) throws IOException {
    MyObject obj = new MyObject();
    crc.setProperty("myObject", myObject);
}

@POST
public Response getResponse(@Context ContainerRequestContext crc) {
    return Response.ok(crc.getProperty("myObject")).build();
}

Еще один вариант, чтобы ввести MyObject напрямую использовать функциональность HK2, которую предлагает Jersey 2.

Создать фабрику залить ContainerRequestContext и вернуть MyObject, Например

import javax.inject.Inject;
import javax.ws.rs.container.ContainerRequestContext;
import jetty.plugin.test.domain.MyObject;
import org.glassfish.hk2.api.Factory;

public class MyObjectFactory implements Factory<MyObject> {

    private final ContainerRequestContext context;

    @Inject
    public MyObjectFactory(ContainerRequestContext context) {
        this.context = context;
    }

    @Override
    public MyObject provide() {
        return (MyObject)context.getProperty("myObject");
    }

    @Override
    public void dispose(MyObject t) {}  
}

Затем вам нужно привязать фабрику:

public class InjectApplication extends ResourceConfig {

    public InjectApplication() {
        ...
        register(new AbstractBinder(){
            @Override
            protected void configure() {
                bindFactory(MyObjectFactory.class)
                        .to(MyObject.class)
                        .in(RequestScoped.class);
            } 
        });
    }
}

С такой же настройкой свойства, как в примере фильтра выше, вы можете просто вставить MyObject с @Context

@GET
public Response getTest(@Context MyObject myObject) {
    return Response.ok(myObject.getMessage()).build();
}

  • Смотрите больше на Custom Injection

ОБНОВИТЬ

Пожалуйста, посмотрите этот вопрос для проблемы с этой реализацией.

Смотрите также:

У меня есть решение для этого, которое не требует контейнера DI, но все же дает большую часть выгоды.

Там две части. Во-первых, как получить экземпляры в механизм внедрения @Context вместо предоставления классов в объекте ApplicationConfig.

Вот техника для этого:

private static class CustomContextResteasyBootstrap extends org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap{
    private final Map<Class<?>, Object> additionalContextObjects = new HashMap<Class<?>, Object>();

    public <E> CustomContextResteasyBootstrap addContextObject(Class<? super E> clazz, E obj){
        additionalContextObjects.put(clazz, obj);
        return this;
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {
        super.contextInitialized(event);
        deployment.getDispatcher().getDefaultContextObjects().putAll(additionalContextObjects);
    }

}

и вы используете это так:

        webAppContext.addEventListener(
                new CustomContextResteasyBootstrap()
                    .addContextObject(MyCustom.class, myCustom)
                    .addContextObject(AnotherCustom.class, anotherCustom)
                    // additional objects you wish to inject into the REST context here
            );

теперь вы можете использовать эти классы с аннотацией @Context:

@GET
public MyCustom echoService(@Context MyCustom custom) {
    return custom;
}

Следующая часть головоломки состоит в том, как предоставить объекты контекста для каждого запроса. Для этого добавьте следующий код где-то в верхней части иерархии вызовов jax-rs (в основном, все, что вызывается ниже этой строки, получит доступ к объекту контекста):

    ResteasyProviderFactory.pushContext(MyContextSpecific.class, new MyContextSpecific());

Затем вы можете ссылаться на это с помощью инъекции в любом месте ниже этого уровня:

@GET
public String contextSpecificEchoService(@Context MyContextSpecific contextSpecific) {
    return custom.toString();
}

Это DI для бедных, но он действительно хорошо работает для встроенных серверов отдыха.

Другие вопросы по тегам