spring

Spring JdbcBeanDefinitionReader Example

This article is about the Spring JdbcBeanDefinitionReader. When would you use this class? When you want to dynamically add externally defined bean definitions in Spring. The Spring JdbcBeanDefinitionReader is a bean definition reader that reads values from a database table and expects columns for bean name, property name and value as String. The formats for each are identical to the properties format recognized by PropertiesBeanDefinitionReader.

1. Tools

  1. Apache Maven
  2. Mars Eclipse
  3. Spring Boot
  4. H2 Database Engine
  5. JdbcBeanDefinitionReader Javadoc

2. Assumptions

This article assumes that you know your way around Eclipse. You are familiar with Maven. And you are familiar with Spring Boot. Basically, you have done some coding. This project has been created using Eclipse Mars so all instructions are based on this IDE.

3. Project Setup

To start, we create our project. This can be done by going to File -> New -> Maven Project and fill up what is required.

Our pom.xml should look like the one below:

pom.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.javacodegeeks.example</groupId>
  <artifactId>spring-jdbcbeandefinitionreader</artifactId>
  <version>0.0.1-SNAPSHOT</version>
   
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.9.RELEASE</version>
  </parent>
   
  <properties>
    <java.version>1.8</java.version>
  </properties>
 
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      </dependency>
    </dependencies>
 
    <build>
      <plugins>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
      </plugins>
    </build>
</project>

As shown above, our project has 2 dependencies. We are using spring-boot-starter-jdbc which means that we can use all the Spring modules included in it. For example, the Spring Core and Spring JDBC modules will be available for us to use plus many more. The next dependency is the H2 Database Engine. We will be utilizing H2’s in-memory database for this example.
The Spring Boot Maven plugin enables us to package the project as an executable jar.

4. POJOs

Below are the plain old Java objects used in this example. In this example, you’ll be using using coffee beans as your Java objects. The author has a weird imagination or no imagination at all :) Arabica and Barako are of type Seed. And CoffeeBean is a concrete class.

Seed.java

1
2
3
4
5
package com.javacodegeeks.example;
 
public interface Seed {
    public String getWeight();
}

Arabica.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.javacodegeeks.example;
 
public class Arabica implements Seed {
 
    private String weight;
     
    public Arabica() {}
     
    public Arabica(String weight) {
        setWeight(weight);
    }
     
    public void setWeight(String weight) {
        this.weight = weight;
    }
     
    @Override
    public String getWeight() {
        return this.weight;
    }
 
    @Override
    public String toString() {
        return "Arabica [weight=" + weight + "]";
    }
 
}

Barako.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.javacodegeeks.example;
 
public class Barako implements Seed {
 
    private String weight;
     
    public Barako(Arabica w1, CoffeeBean w2) {
        setWeight(w1.getWeight() + w2.getWeight());
    }
     
    public void setWeight(String weight) {
        this.weight = weight;
    }
     
    @Override
    public String getWeight() {
        return this.weight;
    }
 
    @Override
    public String toString() {
        return "Barako [weight=" + weight + "]";
    }
 
}

CoffeeBean.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.javacodegeeks.example;
 
public class CoffeeBean {
 
    private String weight;
     
    public CoffeeBean() {}
     
    public CoffeeBean(String weight) {
        this.weight = weight;
    }
 
    public String getWeight() {
        return weight;
    }
 
    public void setWeight(String weight) {
        this.weight = weight;
    }
 
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((weight == null) ? 0 : weight.hashCode());
        return result;
    }
 
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        CoffeeBean other = (CoffeeBean) obj;
        if (weight == null) {
            if (other.weight != null)
                return false;
        } else if (!weight.equals(other.weight))
            return false;
        return true;
    }
 
    @Override
    public String toString() {
        return "CoffeeBean [weight=" + weight + "]";
    }
     
}

5. Code Walkthrough

Our code below performs the basic operations of how to use JdbcBeanDefinitionReader. Skim through the code below but peruse the explanation after it.

Main.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.javacodegeeks.example;
 
import java.sql.ResultSet;
import java.sql.SQLException;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.support.JdbcBeanDefinitionReader;
 
@SpringBootApplication
public class Main implements CommandLineRunner {
     
    @Autowired
    JdbcTemplate jdbcTemplate;
     
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
     
    public void run(String... arg0) throws Exception {
        System.out.println("Building tables");
        jdbcTemplate.execute("DROP TABLE coffee_beans IF EXISTS");
        jdbcTemplate.execute("CREATE TABLE coffee_beans(id SERIAL, beanName VARCHAR(255), property VARCHAR(255), value VARCHAR(255))");
         
        System.out.println("\nCreating the Spring Beans...");
        jdbcTemplate.update("INSERT INTO coffee_beans(beanName, property, value) VALUES (?, ?, ?)", "robusta", "(class)", "com.javacodegeeks.example.CoffeeBean");
        jdbcTemplate.update("INSERT INTO coffee_beans(beanName, property, value) VALUES (?, ?, ?)", "robusta", "(abstract)", "false");
        jdbcTemplate.update("INSERT INTO coffee_beans(beanName, property, value) VALUES (?, ?, ?)", "robusta", "weight", "1");
         
        jdbcTemplate.update("INSERT INTO coffee_beans(beanName, property, value) VALUES (?, ?, ?)", "arabica", "(class)", "com.javacodegeeks.example.Arabica"); // must be fully qualified
        jdbcTemplate.update("INSERT INTO coffee_beans(beanName, property, value) VALUES (?, ?, ?)", "arabica", "$0", "2"); // inject 2 as the constructor argument
         
        jdbcTemplate.update("INSERT INTO coffee_beans(beanName, property, value) VALUES (?, ?, ?)", "barako", "(class)", "com.javacodegeeks.example.Barako");
        jdbcTemplate.update("INSERT INTO coffee_beans(beanName, property, value) VALUES (?, ?, ?)", "barako", "$0(ref)", "arabica"); // inject arabica bean as the 0th constructor argument
        jdbcTemplate.update("INSERT INTO coffee_beans(beanName, property, value) VALUES (?, ?, ?)", "barako", "$1(ref)", "robusta"); // inject robusta bean as the 0th constructor argument
        jdbcTemplate.update("INSERT INTO coffee_beans(beanName, property, value) VALUES (?, ?, ?)", "barako", "(lazy-init)", "true"); // default is false. lazy initialization: delay 'expensive operation' until needed, store result so that 'expensive opearation isn't repeated
         
        readRecords();
         
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        JdbcBeanDefinitionReader beanReader = new JdbcBeanDefinitionReader(beanFactory);
        beanReader.setJdbcTemplate(jdbcTemplate);
        beanReader.loadBeanDefinitions("SELECT beanName, property, value FROM coffee_beans"); // we don't want to include id
         
        System.out.println();
        System.out.println("Number of Spring Beans in container: " + beanFactory.getBeanDefinitionCount());
        CoffeeBean robusta = (CoffeeBean) beanFactory.getBean("robusta");
         
        Seed arabica = (Seed) beanFactory.getBean("arabica");
        Seed barako = (Seed) beanFactory.getBean("barako");
         
        System.out.println("robusta: " + robusta);
        System.out.println("arabica: " + arabica);
        System.out.println("barako: " + barako);
    }
     
    private void readRecords() {
        System.out.println("Reading Spring Bean records...");
        System.out.printf("%-30.30s  %-30.30s %-30.30s%n", "Bean Name", "Property", "Value");
        jdbcTemplate.query("SELECT * FROM coffee_beans", new RowCallbackHandler() {
 
            public void processRow(ResultSet rs) throws SQLException {
                System.out.printf("%-30.30s  %-30.30s %-30.50s%n", rs.getString("beanName"), rs.getString("property"), rs.getString("value"));
            }
             
        });
    }
}

This article is about JdbcBeanDefinitionReader so we’ll go straight to the run() method. For explanations concerning Spring Boot and its annotations (e.g. @SpringBootApplication, @Autowired), have look at Spring Boot JDBC Example or Spring Boot and JPA Example.
First off, we created a database and populated it with a bean name, property and value. As stated above, JdbcBeanDefinitionReader expects columns for bean name, property name and value as String. The format for each are identical to the properties format recognized by PropertiesBeanDefinitionReader. We can look at it this way:

properties file

1
2
3
4
5
robusta.(class)=com.javacodegeeks.example.CoffeeBean
robusta.(abstract)=false                        
robusta.weight=1                            
arabica.(class)=com.javacodegeeks.example.Arabica
arabica.$0=2                            

What have we done? We have declared the robusta bean as a class of CoffeeBean. abstract=true means this bean can be instantiated directly and we have injected the weight value as 1. The arabica bean is of type Arabica and we have injected 2 as the first constructor argument. The barako bean is of type Barako and is injected with the arabica and robusta beans as its first and second constructor argument, respectively. Furtheremore, barako is initialized lazily.

The JdbcBeanDefinitionReader is typically applied to a DefaultListableBeanFactory. We provide the bean reader a JdbcTemplate and an SQL statement to load the bean definitions from the database. Any join and any other columns are permitted as long as the first three columns are bean name, property name and value.

The moment of truth. Once the bean definitions are loaded, we can check how many Spring Beans are in the container. We then get the beans we want and display them. Are the values correct? What do you think?

6. Spring JdbcBeanDefinitionReader Output

After running the code above (Run As -> Java Application), we should have an output that looks like the one below.

Console Output

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
Building tables
 
Creating the Spring Beans...
Reading Spring Bean records...
Bean Name                       Property                       Value                        
robusta                         (class)                        com.javacodegeeks.example.CoffeeBean
robusta                         (abstract)                     false                        
robusta                         weight                         1                            
arabica                         (class)                        com.javacodegeeks.example.Arabica
arabica                         $0                             2                            
barako                          (class)                        com.javacodegeeks.example.Barako
barako                          $0(ref)                        arabica                      
barako                          $1(ref)                        robusta                      
barako                          (lazy-init)                    true                         
 
Number of Spring Beans in container: 3
robusta: CoffeeBean [weight=1]
arabica: Arabica [weight=2]
barako: Barako [weight=21]

As we can clearly see, our beans have been defined and loaded correctly. Their corresponding weight values are correct. Job done.

7. Spring JdbcBeanDefinitionReader Summary

In summary, we include the spring-boot-starter-jdbc dependency to make available all the Spring modules we need to make JDBC operations. We then add the database dependency, in this case H2. We then passed JdbcTemplate to JdbcBeanDefinitionReader and supplied the SQL select statement. Once the beans were in the Spring container, we acquired it through the DefaultListableBeanFactory. That’s all folks.

8. Download the Source Code

This is an example about Spring JdbcBeanDefinitionReader.

Download
You can download the source code of this example here: spring-jdbcbeandefinitionreader.zip.

Joel Patrick Llosa

I graduated from Silliman University in Dumaguete City with a degree in Bachelor of Science in Business Computer Application. I have contributed to many Java related projects at Neural Technologies Ltd., University of Southampton (iSolutions), Predictive Technologies, LLC., Confluence Service, North Concepts, Inc., NEC Telecom Software Philippines, Inc., and NEC Technologies Philippines, Inc. You can also find me in Upwork freelancing as a Java Developer.
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button