#315 - Add example for Spring Data JDBC usage with jOOQ

Demonstrating how to use jOOQ as the basis for an implementation of custom repository methods.

Original pull request: #385.
This commit is contained in:
Florian Lüdiger
2018-07-11 19:29:23 +02:00
committed by Jens Schauder
parent 3a4a9d27b2
commit b6b06121d1
13 changed files with 422 additions and 0 deletions

18
jdbc/jooq/README.adoc Normal file
View File

@@ -0,0 +1,18 @@
== Spring Data JDBC with jOOQ
The `JooqMethods` class demonstrates how to access a database with jOOQ in combination with Spring Data JDBC.
The domain model is based on the basic JDBC example for comparison.
Another interesting aspect of this code could be the jOOQ configuration in the `pom.xml` file.
To execute the tests, execute:
[indent=0]
----
$ mvn test
----
The code generator is automatically run when executing the tests.
If you want to rerun the code generator manually, just execute the following command:
[indent=0]
----
$ mvn clean generate-sources
----

75
jdbc/jooq/pom.xml Normal file
View File

@@ -0,0 +1,75 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-data-jdbc-jooq</artifactId>
<parent>
<groupId>org.springframework.data.examples</groupId>
<artifactId>spring-data-jdbc-examples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Spring Data JDBC - Usage with jOOQ</name>
<description>Sample project demonstrating Spring Data JDBC features</description>
<properties>
<jooq.version>3.11.0</jooq.version>
<spring-boot-starter-jooq.version>2.0.3.RELEASE</spring-boot-starter-jooq.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>${jooq.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jooq</artifactId>
<version>${spring-boot-starter-jooq.version}</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-meta-extensions</artifactId>
<version>${jooq.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<version>${jooq.version}</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<generator>
<database>
<name>org.jooq.meta.extensions.ddl.DDLDatabase</name>
<properties>
<property>
<key>scripts</key>
<value>${basedir}/src/main/resources/schema.sql</value>
</property>
</properties>
</database>
<target>
<packageName>example.springdata.jdbc.basics.simpleentity.domain</packageName>
<directory>${basedir}/gensrc/main/java</directory>
</target>
</generator>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2017-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jdbc.jooq;
/**
* Age group for which a LegoSet is intended.
*
* @author Jens Schauder
*/
public enum AgeGroup {
_0to3,
_3to8,
_8to12,
_12andOlder
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2017-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jdbc.jooq;
import lombok.Data;
import org.springframework.data.annotation.Id;
/**
* Coarse classification for LegoSets, like "Car", "Plane", "Building" and so on.
*
* @author Jens Schauder
* @author Florian Lüdiger
*/
@Data
public class Category {
private final @Id Long id;
private String name, description;
private AgeGroup ageGroup;
public Category(Long id, String name, String description, AgeGroup ageGroup) {
this.id = id;
this.name = name;
this.description = description;
this.ageGroup = ageGroup;
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2017-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jdbc.jooq;
import org.jooq.impl.DataSourceConnectionProvider;
import org.jooq.impl.DefaultConfiguration;
import org.jooq.impl.DefaultDSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
import org.springframework.data.jdbc.repository.config.JdbcConfiguration;
import org.springframework.data.relational.core.mapping.event.RelationalEvent;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import javax.sql.DataSource;
/**
* Contains infrastructure necessary for creating repositories and two listeners.
* <p>
* Not that a listener may change an entity without any problem.
*
* @author Jens Schauder
* @author Mark Paluch
* @author Florian Lüdiger
*/
@Configuration
@EnableJdbcRepositories
@Import(JdbcConfiguration.class)
public class CategoryConfiguration {
@Autowired
private DataSource dataSource;
@Bean
public ApplicationListener<?> loggingListener() {
return (ApplicationListener<ApplicationEvent>) event -> {
if (event instanceof RelationalEvent) {
System.out.println("Received an event: " + event);
}
};
}
@Bean
public DataSourceConnectionProvider connectionProvider() {
return new DataSourceConnectionProvider(new TransactionAwareDataSourceProxy(dataSource));
}
@Bean
DefaultDSLContext dsl() {
return new DefaultDSLContext(configuration());
}
public DefaultConfiguration configuration() {
DefaultConfiguration jooqConfiguration = new DefaultConfiguration();
jooqConfiguration.set(connectionProvider());
return jooqConfiguration;
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2017-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jdbc.jooq;
import org.springframework.data.repository.CrudRepository;
/**
* Repository for Categories.
*
* @author Jens Schauder
*/
interface CategoryRepository extends CrudRepository<Category, Long>, JooqRepository {
}

View File

@@ -0,0 +1,7 @@
package example.springdata.jdbc.jooq;
import java.util.List;
public interface JooqRepository {
List<Category> getCategoriesWithAgeGroup(AgeGroup ageGroup);
}

View File

@@ -0,0 +1,29 @@
package example.springdata.jdbc.jooq;
import org.jooq.DSLContext;
import java.util.List;
import static example.springdata.jdbc.basics.simpleentity.domain.tables.Category.CATEGORY;
/**
* Implementations for custom repository access using jOOQ.
*
* @author Florian Lüdiger
*/
public class JooqRepositoryImpl implements JooqRepository {
private final DSLContext dslContext;
public JooqRepositoryImpl(DSLContext dslContext) {
this.dslContext = dslContext;
}
public List<Category> getCategoriesWithAgeGroup(AgeGroup ageGroup) {
return this.dslContext
.select()
.from(CATEGORY)
.where(CATEGORY.AGE_GROUP.equal(ageGroup.name()))
.fetchInto(Category.class);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2017-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jdbc.jooq;
import lombok.experimental.UtilityClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Trivial class to print domain objects to the console in a somewhat readable format.
*
* @author Jens Schauder
*/
@UtilityClass
public class Output {
private final Logger LOG = LoggerFactory.getLogger(Output.class);
public static void list(Iterable<?> categories, String title) {
StringBuilder message = new StringBuilder(String.format("==== %s ====\n", title));
categories.forEach(category -> message.append(category.toString().replace(", ", ",\n\t")));
LOG.info(message.toString());
}
}

View File

@@ -0,0 +1,2 @@
logging.level.org.springframework.data=INFO
logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG

View File

@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS category (
id INTEGER IDENTITY PRIMARY KEY,
name VARCHAR(100),
description VARCHAR(2000),
age_group VARCHAR(20)
);

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2017-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jdbc.jooq;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureJdbc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Demonstrates simple CRUD operations with a simple entity without any references.
*
* @author Jens Schauder
* @author Florian Lüdiger
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = CategoryConfiguration.class)
@AutoConfigureJdbc
@ComponentScan
public class SimpleEntityTests {
@Autowired
CategoryRepository repository;
@Test
public void exerciseRepositoryForSimpleEntity() {
// create some categories
Category cars = new Category(null,"Cars", "Anything that has approximately 4 wheels", AgeGroup._3to8);
Category buildings = new Category(null,"Buildings", null, AgeGroup._12andOlder);
// save categories
repository.saveAll(asList(cars, buildings));
Output.list(repository.findAll(), "`Cars` and `Buildings` got saved");
assertThat(cars.getId()).isNotNull();
assertThat(buildings.getId()).isNotNull();
// update one
buildings.setDescription("Famous and impressive buildings incl. the 'bike shed'.");
repository.save(buildings);
Output.list(repository.findAll(), "`Buildings` has a description");
List<Category> categoryList = repository.getCategoriesWithAgeGroup(AgeGroup._3to8);
assertThat(categoryList.size()).isEqualTo(1);
assertThat(categoryList.get(0).getName()).isEqualTo(cars.getName());
assertThat(categoryList.get(0).getDescription()).isEqualTo(cars.getDescription());
assertThat(categoryList.get(0).getAgeGroup()).isEqualTo(cars.getAgeGroup());
}
}

View File

@@ -20,6 +20,7 @@
<module>basics</module>
<module>mybatis</module>
<module>r2dbc</module>
<module>jooq</module>
</modules>
<properties>