java - 我如何在 Jersey 中使用 supportsNullCreation()?

标签 java dependency-injection jersey jersey-2.0 hk2

我有一个可注入(inject)的提供程序,它可能返回 null,也可能返回 null。当它为空时出现异常。我将提供程序注册为 Singleton,我是否可以将其注册为我自定义的 SingletonContext 类型,以便为 supportsNullCreation() 返回 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;
   ...

我得到的异常(exception)是...

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层。就我个人而言,我什至在 DAO 和 REST 层之间添加了一个服务层,但您可以只使用一个 DAO 层。

例如,我要做的是为数据访问调用创建一个通用抽象接口(interface)。

public interface DataService {
    Data getData();
}

然后创建数据库访问的实现

public class WithDbService implements DataService {
    private EntityManagerFactory emf;

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

    @Override
    public Data getData() {
        ...
    }
}

然后创建另一个没有数据库访问权限的实现。

public class WithoutDbService implements DataService {
    @Override
    public Data getData() {}
}

然后您可以使用Factory 来创建DataService。您要做的是使用 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(..);

然后你可以在每个地方注入(inject)DataService。只要这两个实现遵循契约,它就应该可以正常工作。

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

关于java - 我如何在 Jersey 中使用 supportsNullCreation()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32877526/

相关文章:

java - Controller 测试中没有类型 'org.springframework.boot.actuate.health.HealthEndpoint' 的合格 bean

oop - 依赖注入(inject)必须以牺牲封装为代价吗?

java - 使用 Jersey 客户端的 HTTPS

json - Spring REST 服务、Jersey REST 服务和 Spring+Jersey 解决方案有什么区别?

java - glassfish 的基本身份验证失败

java - Accordion 菜单在 java 中显示一组图像

java - Jpanel 中的动画组件

java - 使用 Swing GUI 的简单客户端-服务器程序

Spring找不到Autowired接口(interface)实现

java - 如何将 thenReturn() 与注入(inject)的 @Mock 类一起使用?