简体   繁体   中英

Autowiring a Class<T extends BaseEntity> when Autowiring a DAO bean

So I have tried searching all over for this blocker and tried many different ways of finding a solution but I cannot wrap my head around it. I am a beginner in Spring and I have created a generic DAO that takes in any T which extends BaseEntity. I have the following code:

    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;
}

Which I have put inside my BaseDAOImpl . Then I use this constructor:

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

to create a JacksonDbCollection for MongoDB. In my CustomerServiceImpl I Autowire my BaseDAO bean so that I can use my DAO for persistance.

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

So when I run a method that uses my BaseDAOImpl, I get a NullPointerException and I am pretty sure it is because of the Class that is not picking up my CustomerEntity. My question is how can I get Class to pick up CustomerEntity when I Autowire my baseDao bean? Or what suggestions do you have for me to solve my problem? I just need a different point of view and thought I would ask for it here.

Thank you in advanced for you assistance.

Update

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);
}
}

Application Context

<?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"/>

As requested.

New Update

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();
}
private BaseDAO<CustomerEntity> baseDAO;

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

Try using constructor-injection instead. Check if it helps

private BaseDAO<CustomerEntity> baseDAO;

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

You existing 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);
}

This is not the right way to initialize this bean.

  1. You are doing a setter injection on mongoConnection and accessing that in the default constructor. MongoDbUtil.getCollection(mongoConnection.mongoDb(), clazz); The constructor gets called before the setter is invoked. This is going to result in NPE.
  2. Nobody is setting the clazz variable.
  3. @Autowired on a setter and @Bean on a getter is meaningless.
  4. @Repository annotation is not required. You can use @Component

The right way to do things would be this.

BaseDAOImpl class - Including only a part of the class for brevity

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);
}
}

Spring configuration:

<?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 will detect the type T from the second constructor injection and allow you to autowire beans of type BaseDAOImpl<CustomerEntity> .

Note: I assume mongoCollection is declared as a spring bean elsewhere. Otherwise you need to add that in the spring configuration file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM