【问题标题】:Autowiring a Class<T extends BaseEntity> when Autowiring a DAO bean自动装配 DAO bean 时自动装配 Class<T extends BaseEntity>
【发布时间】:2017-08-18 19:22:02
【问题描述】:

所以我已经尝试过到处寻找这个拦截器,并尝试了许多不同的方法来找到解决方案,但我无法理解它。我是 Spring 的初学者,我创建了一个通用 DAO,它接受任何扩展 BaseEntity 的 T。我有以下代码:

    private Class<T> clazz;
@Autowired
public void setClazz(Class<T> clazz){
    System.out.println("In class Autowired Setter");
    this.clazz = clazz;
}

@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Class<T> getClazz(){
    return clazz;
}

我已将其放入我的 BaseDAOImpl。然后我使用这个构造函数:

public BaseDAOImpl() {
    this.collection = MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz);
}

为 MongoDB 创建一个 JacksonDbCollection。在我的 CustomerServiceImpl 中,我自动装配我的 BaseDAO bean,以便我可以使用我的 DAO 进行持久性。

  @Autowired
public void setBaseDAO(BaseDAO<CustomerEntity> baseDAO) {
    this.baseDAO = baseDAO;
}

所以当我运行一个使用我的 BaseDAOImpl 的方法时,我得到一个 NullPointerException,我很确定这是因为类没有拾取我的 CustomerEntity。我的问题是当我自动装配我的 baseDao bean 时,如何让 Class 拿起 CustomerEntity?或者你有什么建议让我解决我的问题?我只是需要一个不同的观点,并认为我会在这里提出要求。

非常感谢您的帮助。

更新

BaseDAOImpl

package za.co.thekeeper.dao;
import org.mongojack.DBCursor;
import org.mongojack.DBQuery;
import org.mongojack.JacksonDBCollection;
import org.mongojack.WriteResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition; 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import za.co.thekeeper.entities.BaseEntity;
import za.co.thekeeper.mongo.MongoConnection;
import za.co.thekeeper.mongo.MongoDbUtil;
import java.util.ArrayList;
import java.util.List;

@Repository
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class BaseDAOImpl<T extends BaseEntity> implements BaseDAO<T> {

private JacksonDBCollection<T, String> collection;

/**Dependency Injections**/
private MongoConnection mongoConnection;
@Autowired
public void setMongoConnection(MongoConnection mongoConnection) {
    System.out.println("In autowired setter");
    this.mongoConnection = mongoConnection;
}

private Class<T> clazz;
@Autowired
public void setClazz(Class<T> clazz){
    System.out.println("In class Autowired Setter");
    this.clazz = clazz;
}

@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Class<T> getClazz(){
    return clazz;
}

public BaseDAOImpl() {
    this.collection = MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz);
}

@Override
public T create(T entity) {
    entity.activate();
    entity.beforePersist();
    WriteResult<T, String> inserted = this.collection.insert(entity);
    return inserted.getSavedObject();
}

@Override
public void delete(T entity) {
    deactivate(entity);
}

@Override
public T activate(T entity) {
    entity.activate();
    return update(entity);
}

@Override
public T deactivate(T entity) {
    entity.deactivate();
    return update(entity);
}

@Override
public void activate(String id) {
    T entity = getById(id);

    if (entity == null) {
        throw new NullPointerException("Entity not found with id: " + id);
    }

    activate(entity);
}

@Override
public void deactivate(String id) {
    T entity = getById(id);

    if (entity == null) {
        throw new NullPointerException("Entity not found with id: " + id);
    }

    deactivate(entity);
}

@Override
public T update(T entity) {
    entity.beforePersist();
    WriteResult<T, String> saved = this.collection.save(entity);
    return saved.getSavedObject();
}

@Override
public void deleteById(String id) {
    deactivate(id);
    update(getById(id));
}

@Override
public T getById(String id) {
    return this.collection.findOneById(id);
}

@Override
public List<T> findByField(String field, Object o) {
    DBQuery.Query query = DBQuery.is(field, o);
    DBCursor<T> cursor = this.collection.find(query);
    return readCursor(cursor);
}

@Override
public void createDBRef(String databaseName, String collectionName, String id) {

}

@Override
public List<T> findAll() {
    return findByField("activate", Boolean.TRUE);
}

/**
 * Cursor
 **/
private List<T> readCursor(DBCursor<T> cursor) {
    if (cursor.size() > 0) {
        List<T> found = new ArrayList<>();
        while (cursor.hasNext()) {
            found.add(cursor.next());
        }
        return found;
    }
    return null;
}
}

CustomerServiceImpl

package za.co.thekeeper.service;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import za.co.thekeeper.dao.BaseDAO;
import za.co.thekeeper.dao.BaseDAOImpl;
import za.co.thekeeper.entities.CustomerEntity;
import za.co.thekeeper.entities.MerchantEntity;
import za.co.thekeeper.entities.ReceiptEntity;
import za.co.thekeeper.mongo.MongoConnection;

import java.util.List;
import java.util.UUID;

@Service

public class CustomerServiceImpl implements CustomerService {

private BaseDAO<CustomerEntity> baseDAO;

@Autowired
public void setBaseDAO(BaseDAO<CustomerEntity> baseDAO) {
    this.baseDAO = baseDAO;
}

@Override
public CustomerEntity registerNewCustomer(CustomerEntity customer) {
    if (customer.getId() == null) {
        customer.setId(UUID.randomUUID().toString());
    }

    CustomerEntity entity = baseDAO.create(customer);
    System.out.println(entity.toString());
    return entity;
}

@Override
public CustomerEntity getCustomer(String cellNumber) {
    List<CustomerEntity> entities = baseDAO.findByField("cellNumber", cellNumber);
    return entities.get(0);
}

@Override
public CustomerEntity updateCustomerDetails(CustomerEntity customer) {

    return baseDAO.update(customer);
}

@Override
public void deleteCustomer(CustomerEntity customer) {
    baseDAO.delete(customer);
}
}

应用程序上下文

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
   http://www.springframework.org/schema/context  
   http://www.springframework.org/schema/context/spring-context-4.0.xsd">

<context:annotation-config/>

<context:component-scan base-package="za.co.thekeeper"/>

根据要求。

新更新

BaseDAO

package za.co.thekeeper.dao;

import za.co.thekeeper.entities.BaseEntity;
import za.co.thekeeper.mongo.MongoConnection;

import java.util.List;

public interface BaseDAO<T extends BaseEntity> {

T create(T entity);

void delete(T entity);

T activate(T entity);

T deactivate(T entity);

void activate(String id);

void deactivate(String id);

T update(T entity);

void deleteById(String id);

T getById(String id);

List<T> findByField(String id, Object o);

void createDBRef(String databaseName, String collectionName, String id);

List<T> findAll();
}

【问题讨论】:

  • 能否请您完整发布 BaseDAOImpl 代码而不是分块发布?还请将 CustomerServiceImpl 与您的 spring 配置一起完全发布。
  • 我们去@yaswanth

标签: java spring mongodb generics


【解决方案1】:

您现有的 BaseDAOImpl:

private MongoConnection mongoConnection;
@Autowired
public void setMongoConnection(MongoConnection mongoConnection) {
    System.out.println("In autowired setter");
    this.mongoConnection = mongoConnection;
}

private Class<T> clazz;
@Autowired
public void setClazz(Class<T> clazz){
    System.out.println("In class Autowired Setter");
    this.clazz = clazz;
}

@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Class<T> getClazz(){
    return clazz;
}

public BaseDAOImpl() {
    this.collection = MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz);
}

这不是初始化这个 bean 的正确方法。

  1. 您正在对mongoConnection 进行setter 注入并在默认构造函数中访问它。 MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz); 在调用 setter 之前调用构造函数。这将导致 NPE。
  2. 没有人设置 clazz 变量。
  3. setter 上的 @Autowired 和 getter 上的 @Bean 毫无意义。
  4. @Repository 注释不是必需的。您可以使用@Component

正确的做事方式是这样。

BaseDAOImpl 类 - 为简洁起见,仅包括该类的一部分

package za.co.thekeeper.dao;
import org.mongojack.DBCursor;
import org.mongojack.DBQuery;
import org.mongojack.JacksonDBCollection;
import org.mongojack.WriteResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition; 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import za.co.thekeeper.entities.BaseEntity;
import za.co.thekeeper.mongo.MongoConnection;
import za.co.thekeeper.mongo.MongoDbUtil;
import java.util.ArrayList;
import java.util.List;

public class BaseDAOImpl<T extends BaseEntity> implements BaseDAO<T> {

private JacksonDBCollection<T, String> collection;

/**Dependency Injections**/
private MongoConnection mongoConnection;

public void setMongoConnection(MongoConnection mongoConnection) {
    System.out.println("In autowired setter");
    this.mongoConnection = mongoConnection;
}

private Class<T> clazz;

public void setClazz(Class<T> clazz){
    System.out.println("In class Autowired Setter");
    this.clazz = clazz;
}

public Class<T> getClazz(){
    return clazz;
}

public BaseDAOImpl(MongoCollection mongoCollection, Class<T> clazz) {
    this.mongoCollection = mongoCollection;
    this.clazz = clazz;
    this.collection = MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz);
}
}

弹簧配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
   http://www.springframework.org/schema/context  
   http://www.springframework.org/schema/context/spring-context-4.0.xsd">

<context:annotation-config/>

<context:component-scan base-package="za.co.thekeeper"/>

<bean class="za.co.thekeeper.dao.BaseDAOImpl">
    <constructor-arg index="0" ref="mongoCollection"/>
    <constructor-arg index="1">
        <value type="java.lang.Class">CustomerEntity</value>
    </constructor-arg>
</bean>

Spring 将从第二个构造函数注入中检测到类型 T 并允许您自动装配 BaseDAOImpl&lt;CustomerEntity&gt; 类型的 bean。

注意:我假设 mongoCollection 在其他地方被声明为 spring bean。否则,您需要将其添加到 spring 配置文件中。

【讨论】:

  • 谢谢,会试一试。但是我怎样才能以可以使用任何实体的方式做到这一点。我至少有 4 个扩展 BaseEntity 的实体。
  • 您需要声明 4 个不同的 bean,它们具有不同的构造函数注入和不同的 bean id。没有其他办法。 bean 有状态,它们需要不同。您可以尝试使用@Lookup 注释。这可能会稍微简化您的代码,但整体逻辑不会改变。
  • 酷。该解决方案确实有效,但我必须删除 BaseDAOImpl 的 @Component 原型?
  • 你是对的。我将对答案进行编辑。感谢您指出。我们已经在 xml 中声明了 bean。
【解决方案2】:
private BaseDAO<CustomerEntity> baseDAO;

@Autowired
public void setBaseDAO(BaseDAO<CustomerEntity> baseDAO) {
    this.baseDAO = baseDAO;
}

尝试改用constructor-injection。检查是否有帮助

private BaseDAO<CustomerEntity> baseDAO;

@Autowired
public CustomerServiceImpl(BaseDAO<CustomerEntity> baseDAO) {
    this.baseDAO = baseDAO;
}

【讨论】:

  • 我试过了,还是不行。我主要关心的是如何将 Class 赋予 CustomerEntity。我很确定这就是我的 NullPointerException 的来源
  • 我的假设是您将创建一个 CustomerEntityDAO,您将在其中扩展 Base DAO 并提供 CustomerEntity 以生成所需的 DAO 对象
  • 如果我不使用 Spring 来实现这一点,而使用普通的 Java,我就不需要创建 CustomerEntityDAO,这就是我想使用 Spring 来实现的。我的项目中至少有 4 个实体,我不想为每个实体创建一个 DAO。如果这有意义?
  • 我们去@Anupama
猜你喜欢
  • 1970-01-01
  • 2018-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-22
相关资源
最近更新 更多