diff --git a/buildSrc/src/main/java/io/spring/start/PostgresqlDriver.java b/buildSrc/src/main/java/io/spring/start/PostgresqlDriver.java new file mode 100644 index 0000000000..a14fe7c8a0 --- /dev/null +++ b/buildSrc/src/main/java/io/spring/start/PostgresqlDriver.java @@ -0,0 +1,43 @@ +package io.spring.start; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.starter.application.ApplicationType; +import io.micronaut.starter.application.generator.GeneratorContext; +import io.micronaut.starter.build.dependencies.Dependency; +import io.micronaut.starter.feature.Feature; +import jakarta.inject.Singleton; + +@Singleton +public class PostgresqlDriver implements Feature { + + public static final Dependency DEPENDENCY_POSTGRESQL = Dependency.builder() + .groupId("org.postgresql") + .artifactId("postgresql") + .runtime() + .build(); + + @Override + public @NonNull String getName() { + return "postgresql-driver"; + } + + @Override + public boolean supports(ApplicationType applicationType) { + return true; + } + + @Override + public String getDescription() { + return "A JDBC and R2DBC driver that allows Java programs to connect to a PostgreSQL database using standard, database independent Java code."; + } + + @Override + public String getTitle() { + return "PostgreSQL Driver"; + } + + @Override + public void apply(GeneratorContext generatorContext) { + generatorContext.addDependency(DEPENDENCY_POSTGRESQL); + } +} diff --git a/buildSrc/src/main/java/io/spring/start/SpringBootDependencies.java b/buildSrc/src/main/java/io/spring/start/SpringBootDependencies.java index 020c17cb9b..08284212d1 100644 --- a/buildSrc/src/main/java/io/spring/start/SpringBootDependencies.java +++ b/buildSrc/src/main/java/io/spring/start/SpringBootDependencies.java @@ -21,6 +21,8 @@ public final class SpringBootDependencies { public static final String GROUP_ID_ORG_SPRINGFRAMEWORK_BOOT = "org.springframework.boot"; private static final String ARTIFACT_ID_SPRING_BOOT_STARTER = "spring-boot-starter"; private static final String ARTIFACT_ID_SPRING_BOOT_STARTER_WEB = "spring-boot-starter-web"; + + private static final String ARTIFACT_ID_SPRING_BOOT_STARTER_DATA_JPA = "spring-boot-starter-data-jpa"; private static final String ARTIFACT_ID_SPRING_BOOT_STARTER_TEST = "spring-boot-starter-test"; public static final Dependency.Builder DEPENDENCY_SPRINGBOOT_STARTER = Dependency.builder() @@ -32,6 +34,11 @@ public final class SpringBootDependencies { .groupId(GROUP_ID_ORG_SPRINGFRAMEWORK_BOOT) .artifactId(ARTIFACT_ID_SPRING_BOOT_STARTER_WEB) .compile(); + + public static final Dependency.Builder DEPENDENCY_SPRING_BOOT_STARTER_DATA_JPA = Dependency.builder() + .groupId(GROUP_ID_ORG_SPRINGFRAMEWORK_BOOT) + .artifactId(ARTIFACT_ID_SPRING_BOOT_STARTER_DATA_JPA) + .compile(); public static final Dependency.Builder DEPENDENCY_SPRINGBOOT_STARTER_TEST = Dependency.builder() .groupId(GROUP_ID_ORG_SPRINGFRAMEWORK_BOOT) .artifactId(ARTIFACT_ID_SPRING_BOOT_STARTER_TEST) diff --git a/buildSrc/src/main/java/io/spring/start/SpringBootStarterJpa.java b/buildSrc/src/main/java/io/spring/start/SpringBootStarterJpa.java new file mode 100644 index 0000000000..1ff949e09d --- /dev/null +++ b/buildSrc/src/main/java/io/spring/start/SpringBootStarterJpa.java @@ -0,0 +1,51 @@ +/* + * Copyright 2017-2023 original 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 + * + * https://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 io.spring.start; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.starter.application.generator.GeneratorContext; +import jakarta.inject.Singleton; + +import static io.spring.start.SpringBootDependencies.*; + +@Singleton +public class SpringBootStarterJpa implements SpringBootStarterFeature { + public static final String NAME = "spring-boot-starter-data-jpa"; + + @Override + @NonNull + public String getName() { + return NAME; + } + + @Override + public String getTitle() { + return "Spring Data JPA"; + } + + @Override + @NonNull + public String getDescription() { + return "Persist data in SQL stores with Java Persistence API using Spring Data and Hibernate."; + } + + @Override + public void apply(GeneratorContext generatorContext) { + generatorContext.addDependency(DEPENDENCY_SPRING_BOOT_STARTER_DATA_JPA); + generatorContext.addDependency(DEPENDENCY_SPRINGBOOT_STARTER_TEST); + } + +} diff --git a/buildSrc/src/main/java/io/spring/start/SpringBootTestcontainers.java b/buildSrc/src/main/java/io/spring/start/SpringBootTestcontainers.java new file mode 100644 index 0000000000..f4acac850c --- /dev/null +++ b/buildSrc/src/main/java/io/spring/start/SpringBootTestcontainers.java @@ -0,0 +1,55 @@ +package io.spring.start; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.starter.application.ApplicationType; +import io.micronaut.starter.application.generator.GeneratorContext; +import io.micronaut.starter.build.dependencies.Dependency; +import io.micronaut.starter.feature.Feature; +import io.micronaut.starter.feature.FeatureContext; +import io.micronaut.starter.feature.database.PostgreSQL; +import jakarta.inject.Singleton; + +@Singleton +public class SpringBootTestcontainers implements Feature { + + public static final Dependency DEPENDENCY_SPRINGBOOT_TESTCONTAINERS = Dependency.builder() + .groupId(SpringBootDependencies.GROUP_ID_ORG_SPRINGFRAMEWORK_BOOT) + .artifactId("spring-boot-testcontainers") + .test() + .build(); + + public static final Dependency DEPENDENCY_TESTCONTAINERS_POSTGRESQL = Dependency.builder() + .groupId("org.testcontainers") + .artifactId("postgresql") + .test() + .build(); + + private final TestContainersJunitJupiter testContainersJunitJupiter; + + public SpringBootTestcontainers(TestContainersJunitJupiter testContainersJunitJupiter) { + this.testContainersJunitJupiter = testContainersJunitJupiter; + } + + @Override + public void processSelectedFeatures(FeatureContext featureContext) { + featureContext.addFeatureIfNotPresent(TestContainersJunitJupiter.class, testContainersJunitJupiter); + } + + @Override + public @NonNull String getName() { + return "spring-boot-testcontainers"; + } + + @Override + public boolean supports(ApplicationType applicationType) { + return true; + } + + @Override + public void apply(GeneratorContext generatorContext) { + generatorContext.addDependency(DEPENDENCY_SPRINGBOOT_TESTCONTAINERS); + if (generatorContext.hasFeature(PostgresqlDriver.class)) { + generatorContext.addDependency(DEPENDENCY_TESTCONTAINERS_POSTGRESQL); + } + } +} diff --git a/buildSrc/src/main/java/io/spring/start/TestContainersJunitJupiter.java b/buildSrc/src/main/java/io/spring/start/TestContainersJunitJupiter.java new file mode 100644 index 0000000000..b3fee7209c --- /dev/null +++ b/buildSrc/src/main/java/io/spring/start/TestContainersJunitJupiter.java @@ -0,0 +1,31 @@ +package io.spring.start; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.starter.application.ApplicationType; +import io.micronaut.starter.application.generator.GeneratorContext; +import io.micronaut.starter.build.dependencies.Dependency; +import io.micronaut.starter.feature.Feature; +import jakarta.inject.Singleton; + +@Singleton +public class TestContainersJunitJupiter implements Feature { + public static final Dependency DEPENDENCY_TESTCONTAINERS_JUNIT_JUPITER = Dependency.builder() + .groupId("org.testcontainers") + .artifactId("junit-jupiter") + .test() + .build(); + @Override + public @NonNull String getName() { + return "testcontainers-junit-jupiter"; + } + + @Override + public boolean supports(ApplicationType applicationType) { + return true; + } + + @Override + public void apply(GeneratorContext generatorContext) { + generatorContext.addDependency(DEPENDENCY_TESTCONTAINERS_JUNIT_JUPITER); + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/metadata.json b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/metadata.json new file mode 100644 index 0000000000..7e640069c4 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/metadata.json @@ -0,0 +1,21 @@ +{ + "title": "Replace H2 with a real database for testing - Spring Boot to Micronaut Framework", + "intro": "This guide shows compares how replace H2 with a real database for testing in a Spring Boot application vs a Micronaut Framework application.", + "authors": ["Sergio del Amo"], + "tags": ["spring-boot"], + "categories": ["Spring Boot to Micronaut Framework"], + "publicationDate": "2023-08-01", + "languages": ["java"], + "apps": [ + { + "framework": "Spring Boot", + "testFramework": "junit", + "name": "springboot", + "features": ["spring-boot-starter-data-jpa", "postgresql-driver", "testcontainers-junit-jupiter", "spring-boot-testcontainers", "assertj"] + }, + { + "name": "micronautframework", + "features": ["data-jpa", "testcontainers", "assertj", "postgresql"] + } + ] +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/java/example/micronaut/JdbcProductRepository.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/java/example/micronaut/JdbcProductRepository.java new file mode 100644 index 0000000000..0d7c72460f --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/java/example/micronaut/JdbcProductRepository.java @@ -0,0 +1,28 @@ +package example.micronaut; + +import java.util.List; + +import jakarta.inject.Singleton; +import org.springframework.jdbc.core.JdbcTemplate; +@Singleton +public class JdbcProductRepository { + + private final JdbcTemplate jdbcTemplate; + + public JdbcProductRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List getAllProducts() { + + return jdbcTemplate.query( + "select id, code, name from products", + (rs, rowNum) -> { + long id = rs.getLong("id"); + String code = rs.getString("code"); + String name = rs.getString("name"); + return new Product(id, code, name); + } + ); + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/java/example/micronaut/Product.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/java/example/micronaut/Product.java new file mode 100644 index 0000000000..5567da88e8 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/java/example/micronaut/Product.java @@ -0,0 +1,51 @@ +package example.micronaut; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "products") +public class Product { + + @Id + private Long id; + + @Column(nullable = false, unique = true) + private String code; + + @Column(nullable = false) + private String name; + + public Product() {} + + public Product(Long id, String code, String name) { + this.id = id; + this.code = code; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/java/example/micronaut/ProductRepository.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/java/example/micronaut/ProductRepository.java new file mode 100644 index 0000000000..905f55148c --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/java/example/micronaut/ProductRepository.java @@ -0,0 +1,19 @@ +package example.micronaut; + +import io.micronaut.context.annotation.Parameter; +import io.micronaut.data.annotation.Query; +import io.micronaut.data.annotation.Repository; +import io.micronaut.data.repository.CrudRepository; + +@Repository +interface ProductRepository extends CrudRepository { + @Query( + value = """ + insert into products(id, code, name) + values(:#{#p.id}, :#{#p.code}, :#{#p.name}) + ON CONFLICT DO NOTHING + """, + nativeQuery = true + ) + void createProductIfNotExists(@Parameter("p") Product product); +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/resources/application.properties b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/resources/application.properties new file mode 100644 index 0000000000..4ef47819b9 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/resources/application.properties @@ -0,0 +1,8 @@ +micronaut.application.name=micronautguide +datasources.default.db-type=postgres +datasources.default.dialect=POSTGRES +datasources.default.driver-class-name=org.postgresql.Driver +datasources.default.url=jdbc\:postgresql\://localhost\:5432/postgres +datasources.default.password= +datasources.default.username=postgres +jpa.default.properties.hibernate.hbm2ddl.auto=update diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/resources/logback.xml b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/resources/logback.xml new file mode 100644 index 0000000000..44b79c40d4 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/java/example/micronaut/JdbcProductRepositoryTest.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/java/example/micronaut/JdbcProductRepositoryTest.java new file mode 100644 index 0000000000..1f047f3120 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/java/example/micronaut/JdbcProductRepositoryTest.java @@ -0,0 +1,43 @@ +package example.micronaut; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.net.URL; +import java.util.List; +import java.util.Optional; + +import io.micronaut.context.annotation.Property; +import io.micronaut.core.io.ResourceLoader; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.jdbc.core.JdbcTemplate; + +@MicronautTest +@Property(name = "datasources.default.driver-class-name", value = "org.testcontainers.jdbc.ContainerDatabaseDriver") +@Property(name = "datasources.default.url", value = "jdbc:tc:postgresql:15.2-alpine:///db?TC_INITSCRIPT=sql/init-db.sql") +class JdbcProductRepositoryTest { + + @Inject + private JdbcTemplate jdbcTemplate; + + @Inject + ResourceLoader resourceLoader; + + @Inject + JdbcProductRepository productRepository; + + @BeforeEach + void setUp() { + //Optional resource = resourceLoader.getResource("sql/seed-data.sql"); + String foo = ""; + } + + @Test + //@Sql("/sql/seed-data.sql") + void shouldGetAllProducts() { + List products = productRepository.getAllProducts(); + assertEquals(2, products.size()); + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/java/example/micronaut/ProductRepositoryTest.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/java/example/micronaut/ProductRepositoryTest.java new file mode 100644 index 0000000000..8fc48f4ce7 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/java/example/micronaut/ProductRepositoryTest.java @@ -0,0 +1,61 @@ +package example.micronaut; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import io.micronaut.test.support.TestPropertyProvider; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.MountableFile; + +@MicronautTest +@Testcontainers(disabledWithoutDocker = true) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ProductRepositoryTest implements TestPropertyProvider { + + @Container + static PostgreSQLContainer postgres = new PostgreSQLContainer<>( + "postgres:15.2-alpine" + ) + .withCopyFileToContainer( + MountableFile.forClasspathResource("sql/init-db.sql"), + "/docker-entrypoint-initdb.d/init-db.sql" + ); + + @Override + public @NonNull Map getProperties() { + return Map.of("spring.datasource.url", postgres.getJdbcUrl(), + "spring.datasource.username", postgres.getUsername(), + "spring.datasource.password", postgres.getPassword()); + } + + @Inject + ProductRepository productRepository; + + @Test + //@Sql("/sql/seed-data.sql") + void shouldGetAllProducts() { + List products = productRepository.findAll(); + assertEquals(2, products.size()); + } + + @Test + //@Sql("/sql/seed-data.sql") + void shouldNotCreateAProductWithDuplicateCode() { + Product product = new Product(3L, "p101", "Test Product"); + productRepository.createProductIfNotExists(product); + Optional optionalProduct = productRepository.findById(product.getId()); + assertThat(optionalProduct).isEmpty(); + } + +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/java/example/micronaut/ProductRepositoryWithJdbcUrlTest.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/java/example/micronaut/ProductRepositoryWithJdbcUrlTest.java new file mode 100644 index 0000000000..ca6dfc8955 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/java/example/micronaut/ProductRepositoryWithJdbcUrlTest.java @@ -0,0 +1,25 @@ +package example.micronaut; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +@MicronautTest +@Property(name = "spec.name", value = "jdbc:tc:postgresql:15.2-alpine:///db?TC_INITSCRIPT=sql/init-db.sql") +class ProductRepositoryWithJdbcUrlTest { + + @Inject + ProductRepository productRepository; + + @Test + //@Sql("classpath:/sql/seed-data.sql") + void shouldGetAllProducts() { + List products = productRepository.findAll(); + assertEquals(2, products.size()); + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/application-test.properties b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/application-test.properties new file mode 100644 index 0000000000..40fbd6d555 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/application-test.properties @@ -0,0 +1,2 @@ +#Wed Aug 02 08:23:28 CEST 2023 +jpa.default.properties.hibernate.hbm2ddl.auto=create-drop diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/logback-test.xml b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..198bd335d5 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + + + diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/sql/init-db.sql b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/sql/init-db.sql new file mode 100644 index 0000000000..8602e27158 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/sql/init-db.sql @@ -0,0 +1,8 @@ +create table products +( + id int not null, + code varchar(255) not null, + name varchar(255) not null, + primary key (id), + unique (code) +); diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/sql/seed-data.sql b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/sql/seed-data.sql new file mode 100644 index 0000000000..65fcc81c22 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/micronautframework/java/src/test/resources/sql/seed-data.sql @@ -0,0 +1,2 @@ +insert into products(id, code, name) values(1, 'p101', 'Apple MacBook Pro'); +insert into products(id, code, name) values(2, 'p102', 'Sony TV'); diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing.adoc b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing.adoc new file mode 100644 index 0000000000..2d11e2c7c8 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing.adoc @@ -0,0 +1,27 @@ +common:header-top.adoc[] + +== Sample Project + +You can link:@sourceDir@.zip[download a sample application] with the code examples shown in this article. + +== Introduction + +Spring Boot and Micronaut applications contain a simple application class which starts the application for you. + +== Spring Boot Application Class + +source:Application[app=springboot] + +=== Micronaut Framework Application Class + +source:Application[app=micronautframework] + +Except for the `@SpringBootApplication` annotation, both classes are almost identical. :-] + +== Next steps + +Read more about https://micronaut-projects.github.io/micronaut-spring/latest/guide/[Micronaut Spring]. + +common:helpWithMicronaut.adoc[] + + diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/main/java/example/micronaut/JdbcProductRepository.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/main/java/example/micronaut/JdbcProductRepository.java new file mode 100644 index 0000000000..3e6e823a8c --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/main/java/example/micronaut/JdbcProductRepository.java @@ -0,0 +1,27 @@ +package example.micronaut; + +import java.util.List; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +@Repository +public class JdbcProductRepository { + + private final JdbcTemplate jdbcTemplate; + + public JdbcProductRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List getAllProducts() { + return jdbcTemplate.query( + "select id, code, name from products", + (rs, rowNum) -> { + long id = rs.getLong("id"); + String code = rs.getString("code"); + String name = rs.getString("name"); + return new Product(id, code, name); + } + ); + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/main/java/example/micronaut/Product.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/main/java/example/micronaut/Product.java new file mode 100644 index 0000000000..5567da88e8 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/main/java/example/micronaut/Product.java @@ -0,0 +1,51 @@ +package example.micronaut; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "products") +public class Product { + + @Id + private Long id; + + @Column(nullable = false, unique = true) + private String code; + + @Column(nullable = false) + private String name; + + public Product() {} + + public Product(Long id, String code, String name) { + this.id = id; + this.code = code; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/main/java/example/micronaut/ProductRepository.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/main/java/example/micronaut/ProductRepository.java new file mode 100644 index 0000000000..7944b4ace0 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/main/java/example/micronaut/ProductRepository.java @@ -0,0 +1,19 @@ +package example.micronaut; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +interface ProductRepository extends JpaRepository { + @Modifying + @Query( + value = """ + insert into products(id, code, name) + values(:#{#p.id}, :#{#p.code}, :#{#p.name}) + ON CONFLICT DO NOTHING + """, + nativeQuery = true + ) + void createProductIfNotExists(@Param("p") Product product); +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/java/example/micronaut/JdbcProductRepositoryTest.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/java/example/micronaut/JdbcProductRepositoryTest.java new file mode 100644 index 0000000000..3d1ce6f826 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/java/example/micronaut/JdbcProductRepositoryTest.java @@ -0,0 +1,38 @@ +package example.micronaut; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.jdbc.Sql; +@JdbcTest +@TestPropertySource( + properties = { + "spring.test.database.replace=none", + "spring.datasource.url=jdbc:tc:postgresql:15.2-alpine:///db?TC_INITSCRIPT=sql/init-db.sql", + } +) +class JdbcProductRepositoryTest { + + @Autowired + private JdbcTemplate jdbcTemplate; + + private JdbcProductRepository productRepository; + + @BeforeEach + void setUp() { + productRepository = new JdbcProductRepository(jdbcTemplate); + } + + @Test + @Sql("/sql/seed-data.sql") + void shouldGetAllProducts() { + List products = productRepository.getAllProducts(); + assertEquals(2, products.size()); + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/java/example/micronaut/ProductRepositoryTest.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/java/example/micronaut/ProductRepositoryTest.java new file mode 100644 index 0000000000..330884cb3c --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/java/example/micronaut/ProductRepositoryTest.java @@ -0,0 +1,59 @@ +package example.micronaut; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.jdbc.Sql; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.MountableFile; + +@DataJpaTest +@TestPropertySource(properties = { "spring.test.database.replace=none" }) +@Testcontainers +class ProductRepositoryTest { + + @Container + static PostgreSQLContainer postgres = new PostgreSQLContainer<>( + "postgres:15.2-alpine" + ) + .withCopyFileToContainer( + MountableFile.forClasspathResource("sql/init-db.sql"), + "/docker-entrypoint-initdb.d/init-db.sql" + ); + + @DynamicPropertySource + 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); + } + + @Autowired + ProductRepository productRepository; + + @Test + @Sql("/sql/seed-data.sql") + void shouldGetAllProducts() { + List products = productRepository.findAll(); + assertEquals(2, products.size()); + } + + @Test + @Sql("/sql/seed-data.sql") + void shouldNotCreateAProductWithDuplicateCode() { + Product product = new Product(3L, "p101", "Test Product"); + productRepository.createProductIfNotExists(product); + Optional optionalProduct = productRepository.findById(product.getId()); + assertThat(optionalProduct).isEmpty(); + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/java/example/micronaut/ProductRepositoryWithJdbcUrlTest.java b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/java/example/micronaut/ProductRepositoryWithJdbcUrlTest.java new file mode 100644 index 0000000000..f500fc2227 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/java/example/micronaut/ProductRepositoryWithJdbcUrlTest.java @@ -0,0 +1,30 @@ +package example.micronaut; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.jdbc.Sql; + +@DataJpaTest +@TestPropertySource( + properties = { + "spring.test.database.replace=none", + "spring.datasource.url=jdbc:tc:postgresql:15.2-alpine:///db?TC_INITSCRIPT=sql/init-db.sql", + } +) +class ProductRepositoryWithJdbcUrlTest { + + @Autowired + ProductRepository productRepository; + + @Test + @Sql("classpath:/sql/seed-data.sql") + void shouldGetAllProducts() { + List products = productRepository.findAll(); + assertEquals(2, products.size()); + } +} diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/resources/logback-test.xml b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..198bd335d5 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + + + diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/resources/sql/init-db.sql b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/resources/sql/init-db.sql new file mode 100644 index 0000000000..8602e27158 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/resources/sql/init-db.sql @@ -0,0 +1,8 @@ +create table products +( + id int not null, + code varchar(255) not null, + name varchar(255) not null, + primary key (id), + unique (code) +); diff --git a/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/resources/sql/seed-data.sql b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/resources/sql/seed-data.sql new file mode 100644 index 0000000000..65fcc81c22 --- /dev/null +++ b/guides/spring-boot-to-micronaut-replace-h2-with-real-database-for-testing/springboot/java/src/test/resources/sql/seed-data.sql @@ -0,0 +1,2 @@ +insert into products(id, code, name) values(1, 'p101', 'Apple MacBook Pro'); +insert into products(id, code, name) values(2, 'p102', 'Sony TV');