java 注入 Jersey Resource 类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7985231/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 22:34:27  来源:igfitidea点击:

Injecting into a Jersey Resource class

javajerseyinject

提问by su_

I did try going through the following links How to wire in a collaborator into a Jersey resource?and Access external objects in Jersey Resource classBut still i am unable to find a working sample which shows how to inject into a Resource class. I am not using Spring or a web container.

我确实尝试通过以下链接 如何将合作者连接到 Jersey 资源?访问 Jersey Resource 类中的外部对象但我仍然无法找到显示如何注入 Resource 类的工作示例。我没有使用 Spring 或 Web 容器。

My Resource is

我的资源是

package resource;

import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/something")
public class Resource
{
    @MyResource
    Integer foo = null;
    private static String response = "SampleData from Resource";

    public Resource()
    {
        System.out.println("...constructor called :" + foo);
    }

    @Path("/that")
    @GET
    @Produces("text/plain")
    public String sendResponse()
    {
        return response + "\n";
    }
}

My Provider is

我的提供者是

package resource;

import javax.ws.rs.ext.Provider;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;

@Provider
public class MyResourceProvider implements InjectableProvider<MyResource, Integer>
{
    @Override
    public ComponentScope getScope()
    {
       return ComponentScope.PerRequest;
    }

     @Override
    public Injectable getInjectable(final ComponentContext arg0, final MyResource arg1, final Integer arg2)
    {
       return new Injectable<Object>()
        {
            @Override
            public Object getValue()
            {
              return new Integer(99);
            }
        };
    }
}

My EndpointPublisher is

我的 EndpointPublisher 是

import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.MediaType;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory;

class EndpointPublisher
{
    public static void main(final String[] args)
    {

        final String address = "http://localhost:8080/";
        final Map<String, String> config = new HashMap<String, String>();
        config.put("com.sun.jersey.config.property.packages", "resource");
        try
        {
            GrizzlyWebContainerFactory.create(address, config);
            System.out.println("server started ....." + address);
            callGet();
        }
        catch (final Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void callGet()
    {
        Client client = null;
        ClientResponse response = null;
        client = Client.create();
        final WebResource resource =
                client.resource("http://localhost:8080/something");
        response = resource.path("that")
                .accept(MediaType.TEXT_XML_TYPE, MediaType.APPLICATION_XML_TYPE)
                .type(MediaType.TEXT_XML)
                .get(ClientResponse.class);
        System.out.println(">>>> " + response.getResponseDate());
    }
}

My annotation being

我的注释是

@Retention(RetentionPolicy.RUNTIME)
public @interface MyResource
{}

But when i execute my EndpointPublisher i am unable to inject foo!!

但是当我执行我的 EndpointPublisher 时,我无法注入 foo !!

回答by Martin Matula

Your InjectableProvider is not implemented correctly. The second type parameter should not be the type of the field you are trying to inject - instead it should be the context - either java.lang.reflect.Type class or com.sun.jersey.api.model.Parameter class. In your case, you would use Type. So, your InjectableProvider implementation should look as follows:

您的 InjectableProvider 未正确实现。第二个类型参数不应该是您尝试注入的字段的类型 - 而应该是上下文 - java.lang.reflect.Type 类或 com.sun.jersey.api.model.Parameter 类。在您的情况下,您将使用 Type。因此,您的 InjectableProvider 实现应如下所示:

package resource;

import javax.ws.rs.ext.Provider;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import java.lang.reflect.Type;

@Provider
public class MyResourceProvider implements InjectableProvider<MyResource, Type> {

    @Override
    public ComponentScope getScope() {
        return ComponentScope.PerRequest;
    }

    @Override
    public Injectable getInjectable(final ComponentContext arg0, final MyResource arg1, final Type arg2) {
        if (Integer.class.equals(arg2)) {
            return new Injectable<Integer>() {

                @Override
                public Integer getValue() {
                    return new Integer(99);
                }
            };
        } else {
            return null;
        }
    }
}

There is a helper class for per-request injectable providers (PerRequestTypeInjectableProvider) as well as singleton injectable providers (SingletonTypeInjectableProvider), so you can further simplify it by inheriting from that:

每个请求的可注入提供程序 (PerRequestTypeInjectableProvider) 和单例可注入提供程序 (SingletonTypeInjectableProvider) 都有一个辅助类,因此您可以通过继承它来进一步简化它:

package resource;

import javax.ws.rs.ext.Provider;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.PerRequestTypeInjectableProvider;

@Provider
public class MyResourceProvider extends PerRequestTypeInjectableProvider<MyResource, Integer> {
    public MyResourceProvider() {
        super(Integer.class);
    }

    @Override
    public Injectable<Integer> getInjectable(ComponentContext ic, MyResource a) {
        return new Injectable<Integer>() {
            @Override
            public Integer getValue() {
                return new Integer(99);
            }
        };
    }
}

Note that for these helper classes the second type parameter is the type of the field.

请注意,对于这些辅助类,第二个类型参数是字段的类型。

And one more thing - the injection happens afterthe constructor is called, so the constructor of your resource will still print out ...constructor called :null, but if you change your resource method to return foo, you'll see the response you'll get will be 99.

还有一件事——注入发生构造函数被调用之后,所以你的资源的构造函数仍然会打印出来...constructor called :null,但是如果你改变你的资源方法来返回 foo,你会看到你得到的响应是 99。

回答by Louis GRIGNON

This solution works well and I wanted to share what I found to enable CDI on jersey resources.

此解决方案运行良好,我想分享我发现的在球衣资源上启用 CDI 的方法。

Here is the simplest bean ever :

这是有史以来最简单的 bean:

package fr.test;

import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;

@RequestScoped
public class Test {

    private int i;

    @PostConstruct
    public void create() {
        i = 6;
    }

    public int getI() {
        return i;
    }
}

In your resource class, we just inject this bean, as we would do in a any normal context :

在您的资源类中,我们只注入这个 bean,就像我们在任何普通上下文中所做的那样:

package fr.test;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/login")
public class LoginApi {

    @Inject
    private Test test;

    @GET 
    @Produces("text/plain")
    public String getIt() {
        return "Hi there!" + test;
    }
}

And here is the key. We define a Jersey "InjectionProvider" which will be responsible of beans' resolution :

这是关键。我们定义了一个 Jersey“InjectionProvider”,它将负责 bean 的解析:

package fr.test;

import javax.inject.Inject;

import java.lang.reflect.Type;
import javax.ws.rs.ext.Provider;

import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;

import fr.xxxxxxxxxx.ApplicationBeans;

@Provider
public class InjectionProvider implements InjectableProvider<Inject, Type> {

    public ComponentScope getScope() {
        // CDI will handle scopes for us
        return ComponentScope.Singleton;
    }

    @Override
    public Injectable<?> getInjectable(ComponentContext context,
            Inject injectAnno, Type t) {
        if (!(t instanceof Class))
            throw new RuntimeException("not injecting a class type ?");

        Class<?> clazz = (Class<?>) t;

        final Object instance = ApplicationBeans.get(clazz);

        return new Injectable<Object>() {
            public Object getValue() {
                return instance;
            }
        };
    }
}

InjectableProvideris typed with the kind of annotation we are handling, and the context type (here, normal java type)

InjectableProvider使用我们正在处理的注释类型和上下文类型(这里是普通的 java 类型)进行类型化

ApplicationBeans is just a simple helper for bean resolution. Here is its content :

ApplicationBeans 只是一个简单的 bean 解析助手。这是它的内容:

package fr.xxxxxxxxxx;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import fr.xxxxxxxxxxxxx.UnexpectedException;

/**
 * Gives direct access to managed beans - Designed to be used from unmanaged code
 * 
 * @author lgrignon
 * 
 */
@ApplicationScoped
public class ApplicationBeans
{

  protected static ApplicationBeans instance;

  @Inject
  private BeanManager beanManager;

  /**
   * Gets instance
   * 
   * @return Instance from managed environment
   */
  public static ApplicationBeans instance()
  {
    if (instance == null)
    {
      BeanManager beanManager;
      InitialContext ctx = null;
      try
      {
        ctx = new InitialContext();
        beanManager = (BeanManager)ctx.lookup("java:comp/BeanManager");
      }catch(NamingException e)
      {
        try
        {
          beanManager = (BeanManager)ctx.lookup("java:app/BeanManager");
        }catch(NamingException ne)
        {
          throw new UnexpectedException("Unable to obtain BeanManager.", ne);
        }
      }

      instance = getBeanFromManager(beanManager, ApplicationBeans.class);
    }

    return instance;
  }

  /**
   * Gets bean instance from context
   * 
   * @param <T>
   *          Bean's type
   * @param beanType
   *          Bean's type
   * @param annotations
   *          Bean's annotations
   * @return Bean instance or null if no
   */
  public static <T> T get(final Class<T> beanType, Annotation... annotations)
  {
    return instance().getBean(beanType, annotations);
  }

  /**
   * Gets bean instance from context
   * 
   * @param <T>
   *          Bean's type
   * @param beanType
   *          Bean's type
   * @param annotations
   *          Bean's annotations
   * @return Bean instance or null if no
   */
  public <T> T getBean(final Class<T> beanType, Annotation... annotations)
  {
    return getBeanFromManager(beanManager, beanType, annotations);
  }

  @SuppressWarnings("unchecked")
  private static <T> T getBeanFromManager(BeanManager beanManager, final Class<T> beanType, Annotation... annotations)
  {
    Set<Bean<?>> beans = beanManager.getBeans(beanType, annotations);
    if (beans.size() > 1)
    {
      throw new UnexpectedException("Many bean declarations found for type %s (%s)", beanType.getSimpleName(), beansToString(beans));
    }

    if (beans.isEmpty())
    {
      throw new UnexpectedException("No bean declaration found for type %s", beanType.getSimpleName());
    }

    final Bean<T> bean = (Bean<T>)beans.iterator().next();
    final CreationalContext<T> context = beanManager.createCreationalContext(bean);
    return (T)beanManager.getReference(bean, beanType, context);
  }

  private static String beansToString(Collection<Bean<?>> beans)
  {
    String[] beansLabels = new String[beans.size()];
    int i = 0;
    for (final Bean<?> bean : beans)
    {
      beansLabels[i++] = bean.getName();
    }

    return Arrays.toString(beansLabels);
  }

}

Hope this will help those who want to enable CDI injection in their Jersey resources.

希望这能帮助那些想要在泽西岛资源中启用 CDI 注入的人。

Bye !

再见 !