java एचके 2 फैक्ट्री जर्सी फ़िल्टर से पहले लागू हो जाता है जब @ कन्टेक्ट का उपयोग सेटर/फील्ड/कन्स्ट्रक्टर इंजेक्शन के लिए किया जाता है



dependency-injection jersey-2.0 (1)

जर्सी अनुरोध के संदर्भ में किसी ऑब्जेक्ट को इंजेक्ट करने के तरीके के अनुसार, मैं अपने जर्सी संसाधन को एक फ़िल्टर से इंजेक्शन कर पाया हूं । यह मुझे एक विधि पैरामीटर को सफलतापूर्वक इंजेक्ट करने की अनुमति देता है:

@GET
public Response getTest(@Context MyObject myObject) { // this works

हालांकि, सेटर / फील्ड / कन्स्ट्रक्टर इंजेक्शन के लिए, एचबी 2 फैक्टरी को जर्सी फिल्टर से पहले लागू किया जाता है, जिसका मतलब है कि प्रदान () विधि रिटर्न नल:

@Override
public MyObject provide() {
    // returns null because the filter has not yet run,
    // and the property has not yet been set
    return (MyObject)context.getProperty("myObject");
}

क्या एचबी 2 फैक्टरी चलाएंगे, यह परिभाषित करने का एक तरीका है, ताकि फिल्टर चलाने के बाद इसे आमंत्रित किया जाए? यदि नहीं, तो समाधान एक अंतरफलक के रूप में MyObject को परिभाषित करना है और एक अतिरिक्त क्रियान्वयन परिभाषित करना है जो इसके कंटेनर में एक कंटेनरआरक्वेंसटेन्टेक्स लेता है; वास्तव में इस उदाहरण का उपयोग करने का कोई भी प्रयास तब आज़ादी से लागू होगा जो कंटेनररक्वेंस्ट कोंटेस्टेक्ट की संपत्ति पर सेट हो जाएगा (संभवत: आप वास्तव में इस उदाहरण का उपयोग तब तक नहीं करेंगे जब तक कि फिल्टर चलते नहीं - उस बिंदु पर संपत्ति सेट हो जाएगी)।

लेकिन मैं समझना चाहूंगा कि एचबी 2 फैक्टरी के उस बिंदु को विलंब करना संभव है, जिससे वह फिल्टर के बाद चलता है (यह पहले से ही पैरामीटर इंजेक्शन के मामले में फ़िल्टर के बाद चलता है)। यदि यह संभव नहीं है, तो मैं समझना चाहता हूं कि क्या मौलिक कारण क्यों है


अजीब तरह से यह मेरे लिए फिल्टर पर @PreMatching साथ ही काम करता है (जो कुछ चीजों तक पहुंच को सीमित करता है जिन्हें आप ज़रूरत नहीं दे सकते हैं या नहीं)। यह सुनिश्चित नहीं है कि हुड के नीचे क्या हो रहा है, जिसके कारण यह बिना काम नहीं करता है :-( नीचे। जर्सी टेस्ट फ्रेमवर्क का उपयोग कर एक पूर्ण परीक्षण है

import java.io.IOException;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Provider;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Assert;
import org.junit.Test;

public class FilterInjectionTest extends JerseyTest {

    private static final String MESSAGE = "Inject OK";
    private static final String OBJ_PROP = "myObject";

    public static class MyObject {

        private final String value;

        public MyObject(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }

    @PreMatching
    @Provider
    public static class MyObjectFilter implements ContainerRequestFilter {

        @Override
        public void filter(ContainerRequestContext context) throws IOException {
            MyObject obj = new MyObject(MESSAGE);
            context.setProperty(OBJ_PROP, obj);
        }
    }

    public static class MyObjectFactory
            extends AbstractContainerRequestValueFactory<MyObject> {

        @Override
        @RequestScoped
        public MyObject provide() {
            return (MyObject) getContainerRequest().getProperty(OBJ_PROP);
        }

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

    @Path("method-param")
    public static class MethodParamResource {

        @GET
        public String getResponse(@Context MyObject myObject) {
            return myObject.getValue();
        }
    }

    @Path("constructor")
    public static class ConstructorResource {

        private final MyObject myObject;

        @Inject
        public ConstructorResource(@Context MyObject myObject) {
            this.myObject = myObject;
        }

        @GET
        public String getResponse() {
            return myObject.getValue();
        }
    }

    @Path("field")
    public static class FieldResource {

        @Inject
        private MyObject myObject;

        @GET
        public String getResponse() {
            return myObject.getValue();
        }
    }

    @Override
    public Application configure() {
        ResourceConfig config = new ResourceConfig();
        config.register(MethodParamResource.class);
        config.register(MyObjectFilter.class);
        config.register(ConstructorResource.class);
        config.register(FieldResource.class);
        config.register(new AbstractBinder() {
            @Override
            protected void configure() {
                bindFactory(MyObjectFactory.class)
                        .to(MyObject.class).in(Singleton.class);
            }
        });
        return config;
    }

    @Test
    public void methoParamInjectionOk() {
        String response = target("method-param").request().get(String.class);
        Assert.assertEquals(MESSAGE, response);
        System.out.println(response);
    }

    @Test
    public void costructorInjectionOk() {
        String response = target("constructor").request().get(String.class);
        Assert.assertEquals(MESSAGE, response);
        System.out.println(response);
    }

    @Test
    public void fieldInjectionOk() {
        String response = target("field").request().get(String.class);
        Assert.assertEquals(MESSAGE, response);
        System.out.println(response);
    }
}

अद्यतन करें

समाधान, इसे @PreMatching फ़िल्टर बनाने के बिना, javax.inject.Provider साथ इंजेक्शन करना है। इससे आप ऑब्जेक्ट को आज़ादी से पुनः प्राप्त करने की अनुमति दे सकते हैं। मुझे लगता है कि कंस्ट्रक्टर और फील्ड इंजेक्शन के साथ क्या होता है, यह है कि संसाधन वर्ग के मिलान के बाद, यह तुरंत बनाया और इंजेक्शन क्योंकि फ़िल्टर अभी तक नहीं बुलाया गया है, कारखाने के लिए कोई वस्तु नहीं है। यह विधि इंजेक्शन के लिए काम करता है, क्योंकि यह किसी अन्य विधि कॉल की तरह है। ऑब्जेक्ट इसे पास किया जाता है जब विधि कहा जाता है। नीचे javax.inject.Provider साथ उदाहरण है

@Path("constructor")
public static class ConstructorResource {

    private final javax.inject.Provider<MyObject> myObjectProvider;

    @Inject
    public ConstructorResource(javax.inject.Provider<MyObject> myObjectProvider) {
        this.myObjectProvider = myObjectProvider;
    }

    @GET
    public String getResponse() {
        return myObjectProvider.get().getValue();
    }
}

@Path("field")
public static class FieldResource {

    @Inject
    private javax.inject.Provider<MyObject> myObjectProvider;;

    @GET
    public String getResponse() {
        return myObjectProvider.get().getValue();
    }
}




hk2