Java 如何在Jersey中使用SupportsAllCreation()?

Java 如何在Jersey中使用SupportsAllCreation()?,java,dependency-injection,jersey,jersey-2.0,hk2,Java,Dependency Injection,Jersey,Jersey 2.0,Hk2,我有一个可注入的提供者,它可能返回null,也可能返回null。当它为空时,我得到一个异常。我将提供程序注册为Singleton,是否可以将其注册为一种SingletonContext类型,并对其进行自定义,以便为SupportsAllCreation()返回true?我想如果我能做到这一点,那么即使findOrCreate()返回null,我的代码仍然会运行,这正是我想要的 @ApplicationPath("rest") public class MyApplication extends

我有一个可注入的提供者,它可能返回null,也可能返回null。当它为空时,我得到一个异常。我将提供程序注册为Singleton,是否可以将其注册为一种SingletonContext类型,并对其进行自定义,以便为SupportsAllCreation()返回true?我想如果我能做到这一点,那么即使findOrCreate()返回null,我的代码仍然会运行,这正是我想要的

@ApplicationPath("rest")
public class MyApplication extends ResourceConfig 
{
    public MyApplication()
    {
        ...
    // Provider of DB
    this.register( new AbstractBinder()
    {
       @Override
       public void configure()
       {
 bindFactory(DbManager.class).to(EntityManagerFactory.class).in(Singleton.class);
       }
    });
}
然后是这样使用的:

@Singleton
@Path("myservice")
public class WebServiceClass
{
   // NOTE: Right now I have to comment this to run without a DB
   @Inject
   private EntityManagerFactory entityManagerFactory = null;
   ...
我得到的例外是

java.lang.IllegalStateException: Context 
 org.jvnet.hk2.internal.SingletonContext@6cae5847 findOrCreate returned a null for 
descriptor SystemDescriptor(
    implementation=com.db.DbManager
    contracts={javax.persistence.EntityManagerFactory}
    scope=javax.inject.Singleton
    qualifiers={}
    descriptorType=PROVIDE_METHOD
    descriptorVisibility=NORMAL
    metadata=
    rank=0
    loader=org.glassfish.hk2.utilities.binding.AbstractBinder$2@7050f2b1
    proxiable=null
    proxyForSameScope=null
    analysisName=null
    id=145
    locatorId=0
    identityHashCode=863132354
    reified=true)
    at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2075)
...

我建议改变一下设计。在资源类中使用
EntityManagerFactory
不是很好的设计。剩下的代码如下

public class Resource {
    private EntityManagerFctory emf;

    @POST
    public Response get(Entity e) {
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        em.persist(e);
        em.getTransaction().commit();
        em.close();
    }
}
这幅画有很多地方不对劲。首先,你违反了[单一责任原则][1]。其次,这不允许您优雅地处理
null
EMF,即使这是可能的。你到处都是这个

if (emf != null) {
    // do code above
} else {
    // do something else.
}
此外,它对测试也没有好处。常见的模式是使用图层。就我个人而言,我甚至在DAO和REST层之间添加了一个服务层,但您只需要一个DAO层就可以了

例如,我要做的是为数据访问调用创建一个公共抽象接口

public interface DataService {
    Data getData();
}
然后为db访问创建一个实现

public class WithDbService implements DataService {
    private EntityManagerFactory emf;

    public WithDbService(EntityManagerFactory emf) {
        this.emf = emf;
    }

    @Override
    public Data getData() {
        ...
    }
}
然后创建另一个没有db访问权限的实现

public class WithoutDbService implements DataService {
    @Override
    public Data getData() {}
}
然后可以使用
工厂
创建
数据服务
。您将要做的是使用
ServiceLocator
尝试查找EMF。如果不为空,则返回
WithDbService
否则返回
WithoutDbService

public class DataServiceFatory implements Factory<DataService> {

    private DataService dataService;

    @Inject
    public DataServiceFactory(ServiceLocator locator) {
        // abbreviated for brevity
        EMF emf = locator.getService(EMF.class);
        if (emf != null) {
            dataService = new WithDbService(emf);
        } else {
            dataService = new WithoutDbService();
        }
    }

    @Override
    public DataService provider() { return dataService; }
}
[...]
bindFactory(DataServiceFactory.class).to(DataService.class).in(..);
公共类DataServiceFactory实现{
私有数据服务数据服务;
@注入
公共数据服务工厂(ServiceLocator定位器){
//为简洁而缩写
EMF=locator.getService(EMF.class);
if(emf!=null){
dataService=newwithdbservice(emf);
}否则{
dataService=newwithoutdbservice();
}
}
@凌驾
公共数据服务提供程序(){return DataService;}
}
[...]
bindFactory(DataServiceFactory.class).to(DataService.class).in(..);
然后,您可以在任何地方注入
DataService
。只要这两个实现遵循契约,它就应该工作得很好


可能会有一些设计改进,但这比直接在资源类中使用EMF有了很大的进步。

非常感谢!这完全解决了问题,而且设计也更好。