it-swarm.com.de

Wie füge ich ein Objekt in den Jersey Request Kontext ein?

In diesem Szenario möchte ich einen Filter schreiben und möchte, dass dieser Filter ein Objekt in die aktuelle Anforderung einfügt und weiterleitet, damit die Ressourcenklasse das Objekt verwenden kann, wenn sie die Anforderung erhält.

Filterklasse

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

Ressourcenklasse

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

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

    return "";
}
23
armin

Sie könnten einfach ContainterRequestContext.setProperty(String, Object) verwenden. Dann spritze einfach den 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();
}

Eine andere Möglichkeit, die MyObject direkt zu injizieren, ist die Verwendung der HK2-Funktionalität, die Jersey 2 bietet.

Erstellen Sie eine Factory, die ContainerRequestContext injiziert und MyObject zurückgibt. Beispielsweise

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) {}  
}

Sie müssen dann die Fabrik binden:

public class InjectApplication extends ResourceConfig {

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

Mit der gleichen Einstellung der Eigenschaft wie im obigen Filterbeispiel können Sie dann einfach den MyObject mit dem @Context

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


AKTUALISIEREN

Bitte lesen Sie diese Frage für ein Problem mit dieser Implementierung.

Siehe auch:

40
Paul Samsotha

Ich habe eine Lösung für dieses Problem, die keinen DI-Container erfordert, aber dennoch den größten Vorteil bietet.

Es gibt zwei Teile. Die erste Möglichkeit besteht darin, Instanzen in den @ Context-Injection-Mechanismus einzubinden, anstatt Klassen im ApplicationConfig-Objekt bereitzustellen.

Hier ist eine Technik, um das zu tun:

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);
    }

}

und du verwendest es so:

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

jetzt können Sie diese Klassen mit der Annotation @Context verwenden:

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

Der nächste Teil des Puzzles ist das Bereitstellen von Kontextobjekten pro Anforderung. Fügen Sie dazu den folgenden Code irgendwo oben in der Aufrufhierarchie von jax-rs hinzu (im Grunde wird alles, was unterhalb dieser Zeile aufgerufen wird, Zugriff auf das Kontextobjekt erhalten):

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

Sie können dies dann durch Injektion an einer beliebigen Stelle unterhalb dieser Ebene referenzieren:

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

Dies ist die DI von Poor-Man, funktioniert aber sehr gut für eingebettete Restserver.

1
Kevin Day