2
votes

It may seem an obvious mistake, but I am not able to find it. Following is my code and configuration:

Application Class

@SpringBootApplication
public class Application {
    public static void main(final String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

SQL Config Class

@Configuration
public class PostgreSQLConfig {
    @Bean
    public DataSource getDBDataSource() {
        final DriverManagerDataSource driverManagerDataSource
                = new DriverManagerDataSource(
                        "jdbc:postgresql://localhost:5432/applicationdb",
                        "username",
                        "password"
                );

        driverManagerDataSource.setDriverClassName("org.postgresql.Driver");
        return driverManagerDataSource;
    }


    @Bean
    public JdbcTemplate getJdbcTemplate(final DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

@Repository DAO CLASS

@Repository
public class CustomDAO {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    .
    .

@Component DAO Class

@Component
public class AnotherDAO {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    .
    .

The JdbcTemplate object gets populated for @Component annotated class. But the object is null for @Repository annotated class. I started spring boot with logging set to DEBUG, and couldn't find any error while creating JdbcTemplate bean. From logs, I can infer the method is called and the bean is created. The JdbcTemplate also has reference to DataSource.

If the @Repository annotation is changed to @Component the code works fine.

  1. When using spring jdbc, can we annotate a DAO class with @Repository?
  2. Why the dependency injection works with @Component but fails for @Repository?

As per the suggestion from M. Deinum, I have made following changes.

  • Removed PostgreSQLConfig class
  • Added application.properties file

application.properties

spring.datasource.url=jdbc:postgresql://localhost:5432/applicationdb
spring.datasource.user=username
spring.datasource.password=password
spring.datasource.driver-class-name=org.postgresql.Driver

Properties are loaded by spring application. Following are log messages:

2017-01-06 15:03:02 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.datasource.driver-class-name' in [applicationConfigurationProperties] with type [String]
2017-01-06 15:03:02 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.datasource.password' in [applicationConfigurationProperties] with type [String]
2017-01-06 15:03:02 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.datasource.user' in [applicationConfigurationProperties] with type [String]
2017-01-06 15:03:02 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.datasource.url' in [applicationConfigurationProperties] with type [String]

I receive an exception. Following are the details:

2017-01-06 15:03:05 [main] DEBUG o.s.b.d.LoggingFailureAnalysisReporter - Application failed to start due to an exception
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.jdbc.core.JdbcTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1474)

DAO classes are marked with @Repository annotation.

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.4.3.RELEASE'
    }
}


apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'idea'
apply plugin: 'application'
apply plugin: 'org.springframework.boot'


def applicationVersion = '0.0.1-SNAPSHOT'

def dependencyVersions = [
    slf4j: '1.7.22',
    logback: '1.1.8',
    postgresql: '9.4.1212',
    junit: '4.12'
]


group = 'com.appl'
version = applicationVersion
mainClassName = 'com.appl.Application'


war {
    baseName = 'my-custom-appl'
    version = applicationVersion
}

war.dependsOn test


repositories {
    mavenCentral()
}


sourceCompatibility = 1.8
targetCompatibility = 1.8


configurations.all {
    exclude group: 'commons-logging', module: 'commons-logging'
}


dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web'
    compile 'org.springframework.boot:spring-boot-starter-jdbc'
    compile 'org.springframework:spring-jdbc'
    compile "org.slf4j:jcl-over-slf4j:${dependencyVersions.slf4j}"
    compile "org.postgresql:postgresql:${dependencyVersions.postgresql}"
    compile "ch.qos.logback:logback-classic:${dependencyVersions.logback}"
    testCompile "junit:junit:${dependencyVersions.junit}"
    testCompile 'org.springframework.boot:spring-boot-starter-test'
}
1
Just to confirm did you checked your import statement !! - Aman Tuladhar
All annotations are imported correctly. For JdbcTemplate I verified twice myself. - Sneaky Mistake
I forgot to mention in the question, I am using Spring 4.3.5.RELEASE. I was developing for a POC product. - Sneaky Mistake
Remove your PostgreSQLConfig and just add some properties to application.properties, Spring Boot already configures a datasource and JdbcTemplate no need to do that yourself. dao/repo should be annotated with @Repository. - M. Deinum
Do you have spring-boot-starter-jdbc as a dependency? - M. Deinum

1 Answers

0
votes

I found the (what is happening part of) solution to the problem. Methods in DAO class were marked final, and @Repository doesn't works well with final method. From logs, I can infer that @Repository tries to create a proxy for DAO class, which fails.

When @Repository is replaced with @Component the code runs fine. Again from logs, I can see that @Component doesn't create a proxy and the final status of the method is ignored.

Following are the debug logs of Spring:

When method is final and DAO Class is marked as @Repository

2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Autowiring by type from bean name 'customDAO' via constructor to bean named 'getJdbcTemplate'
2017-01-08 09:19:03 [main] DEBUG c.j.l.d.CustomDAO - Received JdbcTemplate: org.springframework.jdbc.core.JdbcTemplate@3dedb4a6
2017-01-08 09:19:03 [main] INFO  c.j.l.d.CustomDAO - Constructor Called
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'customDAO' to allow for resolving potential circular references
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Creating CGLIB proxy: target source is SingletonTargetSource for target object [com.j.l.data.CustomDAO@19542407]
2017-01-08 09:19:03 [main] INFO  o.s.aop.framework.CglibAopProxy - Unable to proxy method [public final int com.j.l.data.CustomDAO.persistEvent(java.util.List)] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Found 'equals' method: public boolean java.lang.Object.equals(java.lang.Object)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public java.lang.String java.lang.Object.toString()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Found 'hashCode' method: public native int java.lang.Object.hashCode()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.springframework.aop.Advisor)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.aopalliance.aop.Advice)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isFrozen()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setTargetSource(org.springframework.aop.TargetSource)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(int,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setExposeProxy(boolean)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isExposeProxy()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isProxyTargetClass()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract org.springframework.aop.TargetSource org.springframework.aop.framework.Advised.getTargetSource()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setPreFiltered(boolean)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(int,org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isPreFiltered()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.Class[] org.springframework.aop.framework.Advised.getProxiedInterfaces()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isInterfaceProxied(java.lang.Class)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract org.springframework.aop.Advisor[] org.springframework.aop.framework.Advised.getAdvisors()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.removeAdvisor(int) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvisor(org.springframework.aop.Advisor)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.replaceAdvisor(org.springframework.aop.Advisor,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvice(org.aopalliance.aop.Advice)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.String org.springframework.aop.framework.Advised.toProxyConfigString()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.Class org.springframework.aop.TargetClassAware.getTargetClass()
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'customDAO'

When method is not final and DAO class is marked as @Repository

2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'getJdbcTemplate'
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Autowiring by type from bean name 'anotherDAO' via constructor to bean named 'getJdbcTemplate'
2017-01-08 09:19:03 [main] DEBUG c.j.l.data.AnotherDAO - Received JdbcTemplate: org.springframework.jdbc.core.JdbcTemplate@3dedb4a6
2017-01-08 09:19:03 [main] INFO  c.j.l.data.AnotherDAO - Constructor Called
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'anotherDAO' to allow for resolving potential circular references
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Creating CGLIB proxy: target source is SingletonTargetSource for target object [com.j.l.data.AnotherDAO@907f2b7]
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public void com.j.l.data.AnotherDAO.persistEvent(com.j.l.model.EmergencyUserResponse)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Found 'equals' method: public boolean java.lang.Object.equals(java.lang.Object)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public java.lang.String java.lang.Object.toString()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Found 'hashCode' method: public native int java.lang.Object.hashCode()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.springframework.aop.Advisor)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.aopalliance.aop.Advice)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isFrozen()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setTargetSource(org.springframework.aop.TargetSource)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(int,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setExposeProxy(boolean)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isExposeProxy()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isProxyTargetClass()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract org.springframework.aop.TargetSource org.springframework.aop.framework.Advised.getTargetSource()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setPreFiltered(boolean)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(int,org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isPreFiltered()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.Class[] org.springframework.aop.framework.Advised.getProxiedInterfaces()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isInterfaceProxied(java.lang.Class)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract org.springframework.aop.Advisor[] org.springframework.aop.framework.Advised.getAdvisors()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.removeAdvisor(int) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvisor(org.springframework.aop.Advisor)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.replaceAdvisor(org.springframework.aop.Advisor,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvice(org.aopalliance.aop.Advice)
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.String org.springframework.aop.framework.Advised.toProxyConfigString()
2017-01-08 09:19:03 [main] DEBUG o.s.aop.framework.CglibAopProxy - Method is declared on Advised interface: public abstract java.lang.Class org.springframework.aop.TargetClassAware.getTargetClass()
2017-01-08 09:19:03 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'anotherDAO'

When method is final / not final and DAO class is marked as @Component

2017-01-08 09:13:21 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Autowiring by type from bean name 'customDAO' via constructor to bean named 'getJdbcTemplate'
2017-01-08 09:13:21 [main] DEBUG c.j.l.d.CustomDAO - Received JdbcTemplate: org.springframework.jdbc.core.JdbcTemplate@67fe380b
2017-01-08 09:13:21 [main] INFO  c.j.l.d.CustomDAO - Constructor Called
2017-01-08 09:13:21 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'customDAO' to allow for resolving potential circular references
2017-01-08 09:13:21 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
2017-01-08 09:13:21 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'customDAO'

I am still unable to understand why @Repository creates a proxy and @Component skips it? Is there a way to mark method final and use @Repository on DAO class?

If required I can create a separate question for this.