web-dev-qa-db-fra.com

Comment injecter un objet dans le contexte de demande de maillot?

J'ai ce scénario où je veux écrire un filtre et je veux que ce filtre insère un objet dans la demande en cours et le transmette de sorte que lorsque la classe de ressources obtient la demande, elle puisse utiliser l'objet.

Classe de filtre

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

Classe de ressources

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

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

    return "";
}
23
armin

Vous pouvez simplement utiliser ContainterRequestContext.setProperty(String, Object). Ensuite, injectez simplement le 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();
}

Une autre option pour injecter directement le MyObject est d'utiliser la fonctionnalité HK2 proposée par Jersey 2.

Créez une usine, injectez le ContainerRequestContext et retournez le MyObject. Par exemple

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

Vous devez ensuite lier l'usine:

public class InjectApplication extends ResourceConfig {

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

Avec le même paramètre de propriété que dans l'exemple de filtre ci-dessus, vous pouvez alors simplement injecter le MyObject avec le @Context

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


MISE À JOUR

Veuillez voir cette question pour un problème avec cette implémentation.

Voir aussi:

40
Paul Samsotha

J'ai une solution à cela qui ne nécessite pas de conteneur DI, mais qui donne toujours la plupart des avantages.

Il y a deux parties. La première consiste à obtenir des instances dans le mécanisme d'injection @Context au lieu de fournir des classes dans l'objet ApplicationConfig.

Voici une technique pour le faire:

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

}

et vous l'utilisez comme ceci:

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

vous pouvez maintenant utiliser ces classes avec l'annotation @Context:

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

La prochaine partie du puzzle est de savoir comment fournir des objets de contexte par demande. Pour ce faire, ajoutez le code suivant quelque part vers le haut de la hiérarchie des appels jax-rs (fondamentalement, tout ce qui est appelé sous cette ligne aura accès à l'objet contextuel):

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

Vous pouvez ensuite référencer cela via une injection n'importe où en dessous de ce niveau:

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

C'est l'ID du pauvre, mais cela fonctionne très bien pour les serveurs de repos intégrés.

1
Kevin Day