2015-10-01 6 views
2

У меня есть инъекционный поставщик, который может или может вернуть нуль. Я получаю исключение, когда оно равно null. Я зарегистрировал провайдера как Singleton, могу ли я зарегистрировать его как тип SingletonContext, который я настраиваю для возврата true для поддерживаетNullCreation()? Я думаю, что если я смогу это сделать, то даже если findOrCreate() вернет null, мой код все равно будет работать, и это то, что я хочу.Как использовать supportNullCreation() в Джерси?

@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 
[email protected] 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 
    [email protected]f2b1 
    proxiable=null 
    proxyForSameScope=null 
    analysisName=null 
    id=145 
    locatorId=0 
    identityHashCode=863132354 
    reified=true) 
    at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2075) 
... 

ответ

2

Я рекомендовал бы изменения конструкции немного. Использование класса 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]. Во-вторых, это не позволяет вам элегантно обрабатывать EMF null, даже если это было возможно. У вас это есть повсюду

if (emf != null) { 
    // do code above 
} else { 
    // do something else. 
} 

Также он отлично подходит для тестирования. Общая схема состоит в использовании слоя DAO. Лично я даже добавляю сервисный слой между DAO и уровнем REST, но вы можете уйти только с помощью слоя DAO.

Например, что бы я сделал, это создать общий абстракционный интерфейс для вызовов доступа к данным.

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(..); 

Тогда вы можете просто вводить DataService каждый где. Пока две реализации следуют контракту, он должен работать нормально.

Возможно, некоторые улучшения дизайна, но это большой шаг от использования EMF непосредственно в классе ресурсов.

+0

Большое вам спасибо! Это полностью разрешило проблему и значительно улучшило дизайн. – Coder1224