Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
2a0f96f
Add TestContainers sample for Doma Spring Boot (Fixes #290)
devin-ai-integration[bot] May 19, 2025
448f356
Revise TestContainers sample to use Spring Boot's native TestContaine…
devin-ai-integration[bot] May 19, 2025
5198bb1
Fix code formatting issues
devin-ai-integration[bot] May 19, 2025
1e42f72
Update TestContainers sample to use Spring Initializr generated approach
devin-ai-integration[bot] May 19, 2025
06610a1
Remove old TestContainersConfig.java file
devin-ai-integration[bot] May 19, 2025
45661c4
Update TestContainers sample based on feedback: use RestClient, remov…
devin-ai-integration[bot] May 19, 2025
87b5535
Update TestContainers sample based on feedback: remove explicit diale…
devin-ai-integration[bot] May 19, 2025
237ea2d
Change page and size parameters to integers in ApplicationTest
devin-ai-integration[bot] May 19, 2025
487094d
Update transaction manager logging to use JdbcTransactionManager
devin-ai-integration[bot] May 19, 2025
2a5fa14
Use diamond operator for ParameterizedTypeReference
devin-ai-integration[bot] May 19, 2025
ccf7bfc
Add Maven wrapper info to README and remove redundant application-tes…
devin-ai-integration[bot] May 19, 2025
ccbf51f
Add Maven wrapper files to TestContainers sample
devin-ai-integration[bot] May 19, 2025
cf62c8e
Address PR comments: add SQL logging, remove useless comment, remove …
devin-ai-integration[bot] May 19, 2025
5f6bdc4
Remove JUnit comment from pom.xml
devin-ai-integration[bot] May 19, 2025
5f5aa9a
Remove TestContainers comment from pom.xml
devin-ai-integration[bot] May 19, 2025
37dc226
Remove PostgreSQL Driver comment and fix README.md to remove H2 refer…
devin-ai-integration[bot] May 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Doma Spring Boot Sample with TestContainers

This sample demonstrates how to use [TestContainers](https://www.testcontainers.org/) with Doma and Spring Boot.

## Running the Sample

To run this sample, you need:
- Java 17 or later
- Maven
- Docker (for running TestContainers)

### Build and Run Tests

```bash
./mvnw clean test
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add maven wrapper

```

### Run with TestContainers

```bash
./mvnw spring-boot:test-run
```

This will start the application with a PostgreSQL container.

## Features Demonstrated

- Using TestContainers to start a PostgreSQL database for tests
- Spring Boot's native TestContainers integration with `@ServiceConnection`
- Using TestContainers at development time with `SpringApplication.from()`
- Running Doma queries against a real PostgreSQL database in tests
- Configuration for both development (H2) and test (PostgreSQL) environments
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

H2 is not used

Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<artifactId>doma-spring-boot-sample-testcontainers</artifactId>
<packaging>jar</packaging>

<name>doma-spring-boot-sample-testcontainers</name>
<description>Demo project for Spring Boot with Doma and TestContainers</description>

<parent>
<groupId>org.seasar.doma.boot</groupId>
<artifactId>doma-spring-boot-samples</artifactId>
<version>2.5.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<dependencies>
<dependency>
<groupId>org.seasar.doma</groupId>
<artifactId>doma-core</artifactId>
<version>${doma.version}</version>
</dependency>
<dependency>
<groupId>org.seasar.doma</groupId>
<artifactId>doma-processor</artifactId>
<version>${doma.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.seasar.doma.boot</groupId>
<artifactId>doma-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- PostgreSQL Driver -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this comment

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- H2 for local development -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks to Testcontainers support. PostgreSQL can be used for local development as well.
H2 is no longer needed in this project.

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

junit is managed by Spring Boot

<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- TestContainers dependencies -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TestContainers dependencies are managed by Spring Boot

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.seasar.doma.boot.sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

@SuppressWarnings("resource")
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.seasar.doma.boot.sample;

import org.seasar.doma.*;

@Entity
@Table(name = "messages")
public class Message {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer id;

public String text;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.seasar.doma.boot.sample;

import java.util.List;

import org.seasar.doma.boot.Pageables;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use path attriubte

public class MessageController {

private final MessageDao messageDao;

public MessageController(MessageDao messageDao) {
this.messageDao = messageDao;
}

@GetMapping
List<Message> list(@PageableDefault Pageable pageable) {
return messageDao.selectAll(Pageables.toSelectOptions(pageable));
}

@GetMapping(params = "text")
Message add(@RequestParam String text) {
Message message = new Message();
message.text = text;
messageDao.insert(message);
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.seasar.doma.boot.sample;

import java.util.List;

import org.seasar.doma.Dao;
import org.seasar.doma.Insert;
import org.seasar.doma.Select;
import org.seasar.doma.boot.ConfigAutowireable;
import org.seasar.doma.jdbc.SelectOptions;
import org.springframework.transaction.annotation.Transactional;

@Dao
@ConfigAutowireable
@Transactional
public interface MessageDao {
@Select
List<Message> selectAll(SelectOptions options);

@Insert
int insert(Message message);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT id, text FROM messages ORDER BY id;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Development configuration using H2
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.sql.init.mode=always

# Doma configuration
doma.dialect=H2
doma.naming=SNAKE_LOWER_CASE
logging.level.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DataSourceTransactionManager is old. Use JdbcTransactionManager instead.

logging.level.org.springframework.jdbc.support.JdbcTransactionManager=DEBUG

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE TABLE IF NOT EXISTS messages (
id SERIAL PRIMARY KEY,
text VARCHAR(255)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.seasar.doma.boot.sample;

import static org.junit.jupiter.api.Assertions.*;

import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.web.util.UriComponentsBuilder;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@Testcontainers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a project with Spring Initializr.
And import TestcontainersConfiguration class included in the generated project instead of @Testcontainers and @Container.

class ApplicationTest {
@Autowired
private TestRestTemplate restTemplate;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modernize the test code by using RestClient instead of TestRestTemplate.

    RestClient restClient;

    @BeforeEach
    void setUp(@Autowired RestClient.Builder restClientBuilder) {
        this.restClient = restClientBuilder.defaultStatusHandler(__ -> true, (req, res) -> {
        }).build();
    }

private final ParameterizedTypeReference<List<Message>> typedReference = new ParameterizedTypeReference<List<Message>>() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicit type argument List<Message> can be replaced with <>

};
@LocalServerPort
private int port;

@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");

@DynamicPropertySource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DynamicPropertySource is no longer needed as JdbcConnectionDetails is provided via Testconatiners support.

static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
registry.add("doma.dialect", () -> "POSTGRES");
}

@Test
void testWithTestContainers() {
Message message1 = restTemplate.getForObject(
UriComponentsBuilder.fromUriString("http://localhost").port(port)
.queryParam("text", "hello").build().toUri(),
Message.class);
assertEquals(1, message1.id);
assertEquals("hello", message1.text);
Message message2 = restTemplate.getForObject(
UriComponentsBuilder.fromUriString("http://localhost").port(port)
.queryParam("text", "world").build().toUri(),
Message.class);
assertEquals(2, message2.id);
assertEquals("world", message2.text);

{
List<Message> messages = restTemplate.exchange(
UriComponentsBuilder.fromUriString("http://localhost").port(port)
.build().toUri(),
HttpMethod.GET, HttpEntity.EMPTY,
typedReference).getBody();
assertEquals(2, messages.size());
assertEquals(message1.id, messages.get(0).id);
assertEquals(message1.text, messages.get(0).text);
assertEquals(message2.id, messages.get(1).id);
assertEquals(message2.text, messages.get(1).text);
}

{
List<Message> messages = restTemplate.exchange(
UriComponentsBuilder.fromUriString("http://localhost").port(port)
.queryParam("page", "1").queryParam("size", "1").build()
.toUri(),
HttpMethod.GET, HttpEntity.EMPTY, typedReference)
.getBody();
assertEquals(1, messages.size());
assertEquals(message2.id, messages.get(0).id);
assertEquals(message2.text, messages.get(0).text);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.seasar.doma.boot.sample;

import org.springframework.boot.SpringApplication;

public class TestApplication {

public static void main(String[] args) {
SpringApplication.from(Application::main)
.with(TestContainersConfig.class)
.run(args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.seasar.doma.boot.sample;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.utility.DockerImageName;

@TestConfiguration(proxyBeanMethods = false)
public class TestContainersConfig {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a project with Spring Initializr.
And use TestcontainersConfiguration class included in the generated project.


@Bean
@ServiceConnection
public PostgreSQLContainer<?> postgresContainer() {
return new PostgreSQLContainer<>(DockerImageName.parse("postgres:15"))
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Test configuration for PostgreSQL
spring.sql.init.mode=always
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant file

1 change: 1 addition & 0 deletions doma-spring-boot-samples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<module>doma-spring-boot-sample-event-handler</module>
<module>doma-spring-boot-sample-two-datasource</module>
<module>doma-spring-boot-sample-unified-criteria</module>
<module>doma-spring-boot-sample-testcontainers</module>
</modules>

<properties>
Expand Down
Loading