2013-02-21 6 views
2

Я настроил собственный общий сервис DAO для моего проекта spring/hibernate - идея заключается в том, что я могу легко использовать его у моих контроллеров.Имя класса Spring Generic Dao

Это по существу выглядит следующим образом:

public class DefaultService<T> { 

private Class<T> e; 

public String className(Class<T> e) { 
    String clip = e.getName(); 
    clip = clip.substring(clip.lastIndexOf('.') + 1, clip.length()); 
    return clip; 
} 
public List<T> getAll(Integer status) { 
    Session session = sessionFactory.getCurrentSession(); 
    Query query = session.createQuery("FROM " + className(e) + " WHERE status = " + status); 
    return query.list(); 
} 
... 

который получает ссылаются:

@Autowired 
public DefaultService<Address> addressService; 
addressService.get(1); 

Однако String clip = e.getName() линия бросает исключения нулевого указателя. Я могу заставить это работать, если переместить класс в секцию атрибутов (так что addressService.get(Address.class, 1), но я нахожу это несколько неопрятным, особенно при вызове нескольких разных классов.

Есть ли способ получить класс для генерации значение правильно без повторно добавлять его во все мои функции?

заранее спасибо.

ответ

5

я что-то подобное, вам нужно универсальный класс быть аргумент конструктора, а также, шахта использует зимуют объекты, но вы могли бы передать в строку имени таблицы.

public class DomainRepository<T> { 

    @Resource(name = "sessionFactory") 
    protected SessionFactory sessionFactory; 

public DomainRepository(Class genericType) { 
     this.genericType = genericType; 
    } 

@Transactional(readOnly = true) 
    public T get(final long id) { 
     return (T) sessionFactory.getCurrentSession().get(genericType, id); 
    } 

Вы можете затем подкласс (если необходимо), чтобы настроить или просто настроить вас боб в весеннем конфигурации, как показано ниже т:

<bean id="tagRepository" class="com.yourcompnay.data.DomainRepository"> 
     <constructor-arg value="com.yourcompnay.domain.Tag"/> 
</bean> 

Так что в вашем коде вы можете затем ссылаться tagRepository как так (нет другой трески эйс необходимо, чем размещены выше и ниже):

@Resource(name = "tagRepository") 
private DomainRepository<Tag> tagRepository; 

Кроме того, я бы назвал это хранилище не сервис, а сервис имеет дело с различными типами и их взаимодействий (не только один). И конкретно ваш пример использования SQL строки:

public final String tableName; 
public DomainRepository(String tableName) { 
     this.tableName = tableName; 
} 
public List<T> getAll(Integer status) { 
    Session session = sessionFactory.getCurrentSession(); 
    Query query = session.createQuery("FROM " + tableName + " WHERE status = " + status); 
    return query.list(); 
} 

и ваши бобы определяется как так

<bean id="addressRepository" class="com.yourcompnay.data.DomainRepository"> 
    <constructor-arg value="address"/> 
</bean> 

И тогда вы можете alsow создавать подклассы самостоятельно, вы, где это необходимо:

public class PersonRepository extends DomainRepository<Person> { 
    public PersonRepository(){ 
     super("person"); //assumes table name is person 
    } 
+0

Первая линия моего полного класса @Repository, поэтому я начну называть его, что теперь :) Поскольку это имя класса, которое я хочу, чтобы я мог создавать пользовательские запросы к базам данных и смотреть на ваш код, все, что мне нужно добавить в теорию 'public void e (Class genericType) {this.e = genericType; } '? – Toby

+0

см. Обновление, если файл подкласса пуст, если это необходимо, не подклассы ... onyl-подкласса. в Моем приложении У меня есть несколько репозиториев, которые являются просто экземплярами общего репозитория, а затем один или два репозитория, которые были подклассифицированы (где у них более сложные требования). th esolution, которую я предоставил, позволяет вам подклассы ... Я покажу вам, что aswel – NimChimpsky

+0

Итак, я переделал приложение, чтобы следовать этому (жалко создавая все эти дополнительные репозитории для каждой модели). Один последний вопрос - что делает боб? Кажется, что это нормально, без него, хотя мне нужно было удалить «final» модификатор «tableName» и добавить «public DomainRepository() {}' метод ... – Toby

0

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

  1. Установить вручную объект класса, как в комментарии NimChimpsky.
  2. Получить класс типа динамически. E.г, если вы используете Spring попробовать это один:

protected Class getEntityClass() { return GenericTypeResolver.resolveTypeArguments(getClass(), DefaultService.class)[0]; }

или some workaround here

+0

Должно ли это работать с моим текущим кодом? У меня есть хорошее базовое понимание того, что происходит, но я не могу понять, как эта строка будет вписываться? – Toby

+0

Да, этот метод должен быть полезен для вас. Эта строка показывает, как получить тип класса вашего конкретного родового типа. Чем вы можете работать с этим объектом класса: получите имя и другие вещи. –

0

Это лучше определить конкретный класс для адреса службы

public class AddressService extends DefaultService<Address>{ 
    public String getClassName(){ 
    return "Address"; 
    } 
} 

где

public String getClassName(); 

- это абстрактный метод, объявленный в DefaultService, и используется (например, ваш метод className()) в вашей логике доступа к данным.

Используя этот подход, вы будете иметь возможность добавлять специфическую логику доступа к данным (пример, getUsersByAddress)