Falló la inyección de dependencias cableadas automáticamente

Estoy tratando de darme cuenta de lo mismo que en ¿Error de primavera al intentar administrar varias clases que comparten una clase base común?

Pero sigo recibiendo esta excepción:

Error creating bean with name 'com.example.model.CategoryTest': Injection of
autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not autowire
field: private com.example.model.CategoryService
com.example.model.CategoryTest.service; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean
of type [com.example.model.CategoryService] found for dependency: expected at
least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

Aquí están mis clases con la esperanza de que alguien pueda ayudarme a entender esto del cableado automático...

public abstract class BaseDAO<E>
{
    public abstract void delete( int id );
    public abstract void save( E entity );
    public abstract List<E> list();
}

public abstract class BaseService<E, D extends BaseDAO<E>>
{
    private final D dao;

    protected BaseService( D dao )
    {
        this.dao = dao;
    }

    @Transactional
    public void delete( int id )
    {
        dao.delete( id );
    }

    @Transactional
    public void save( E entity )
    {
        dao.save( entity );
    }

    @Transactional
    public List<E> list()
    {
        return dao.list();
    }
}

@Repository
public class CategoryDAO extends BaseDAO<Category>
{
    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public void delete( int id )
    {
        Category category = ( Category ) sessionFactory.getCurrentSession().load( Category.class, id );

        if ( category != null )
        {
            sessionFactory.getCurrentSession().delete( category );
        }
    }

    @Override
    public void save( Category category )
    {
        sessionFactory.getCurrentSession().save( category );
    }

    @Override
    public List<Category> list()
    {
        return sessionFactory.getCurrentSession().createQuery( "from Category" ).list();
    }
}

@Service
public class CategoryService extends BaseService<Category, CategoryDAO>
{
    @Autowired
    public CategoryService( CategoryDAO dao )
    {
        super( dao );
    }
}

ACTUALIZACIÓN

El contexto del servlet contiene esta línea: <context:component-scan base-package="com.example" /> El contexto de prueba (estoy usando maven) contiene esta línea: <context:annotation-config />

Sustitución <context:annotation-config /> con <context:component-scan base-package="com.example" /> da como resultado esta excepción:

org.springframework.beans.factory.BeanCreationException: Could not autowire field:
private com.example.model.CategoryService
com.example.controller.ExampleController.categoryService; 
nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'categoryService' defined in file
[/home/danny/example/target/classes/com/example/model/CategoryService.class]:
Initialization of bean failed; nested exception is
org.springframework.aop.framework.AopConfigException: Could not generate CGLIB
subclass of class [class com.example.model.CategoryService]: Common causes of
this problem include using a final class or a non-visible class; nested exception
is java.lang.IllegalArgumentException: Superclass has no null constructors but no
arguments were given

ACTUALIZAR2

Todavía recibo esta excepción, aquí está mi nuevo código (solo clases cambiadas):

public abstract class BaseService<E, D extends BaseDAO<E>>
{
    private D dao;

    /*protected BaseService( D dao )
    {
        this.dao = dao;
    }*/
    protected BaseService(){}

    protected void setDAO( D dao )
    {
        this.dao = dao;
    }

    @Transactional
    public void delete( int id )
    {
        dao.delete( id );
    }

    @Transactional
    public void save( E entity )
    {
        dao.save( entity );
    }

    @Transactional
    public List<E> list()
    {
        return dao.list();
    }
}

@Service
public class CategoryService extends BaseService<Category, CategoryDAO>
{
    @Autowired
    public CategoryService( CategoryDAO dao )
    {
        setDAO( dao );
    }
}

ACTUALIZAR3

La solución:

public abstract class BaseService<E, D extends BaseDAO<E>>
{
    protected D dao;

    public BaseService()
    {
    }

    protected D getDao()
    {
        return dao;
    }

    @Autowired
    protected void setDAO( D dao )
    {
        this.dao = dao;
    }

    // ...
}

@Service
public class CategoryService extends BaseService<Category, CategoryDAO>
{
    public CategoryService()
    {
        setDAO( dao );
    }
}

preguntado el 02 de julio de 12 a las 18:07

2 Respuestas

No parece que haya una instancia de CategoryService disponible para que Spring inyecte la dependencia en la prueba. Es posible que le falte el escaneo de componentes en su paquete de servicios: <context:component-scan base-package="..">

Actualizar: Según su actualización y esta publicación: Error al crear un bean con el nombre 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping # 0' definido en el recurso ServletContext , parece que tendrá que cambiar su BaseService, para tener un setter para dao en lugar de configurarlo usando un constructor. CGLIB con Spring AOP puede no funcionar bien con un constructor no predeterminado

contestado el 23 de mayo de 17 a las 13:05

Gracias, lo probaré con un setter cuando esté en casa. - borracho

¿Puede dar un ejemplo? Ver ACTUALIZACIÓN2 - borracho

Debes anotar tus clases con @Componente al menos, para que sean elegibles para la inyección autocableada.

Respondido 03 Jul 12, 03:07

Estoy usando @Repository, @Service y @Controller en lugar de. Pero en mi clase de prueba no puedo usar un @Controller anotación no? Es una clase de prueba JUnit. - borracho

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.