From c5a5ca1f57fc4d360c111ddad62f8d4c389b5d16 Mon Sep 17 00:00:00 2001 From: Jonas Hinterdorfer Date: Mon, 1 Dec 2025 12:02:19 +0100 Subject: [PATCH] refactor: update FlowerEntity and persistence layer, add repository pattern and tests --- .idea/compiler.xml | 8 +++ pom.xml | 19 +++++++ .../java/dev/hinterdorfer/FlowerEntity.java | 37 +++++++++++++- .../dev/hinterdorfer/FlowerPersistance.java | 10 ++-- .../dev/hinterdorfer/FlowerRepository.java | 33 +++++++++++++ .../dev/hinterdorfer/IndoorFlowerEntity.java | 18 +++++++ .../dev/hinterdorfer/OutdoorFlowerEntity.java | 17 +++++++ src/main/resources/application.properties | 3 +- .../hinterdorfer/FlowerPersistanceTest.java | 49 +++++++++++++++++++ .../hinterdorfer/FlowerRepositoryTest.java | 46 +++++++++++++++++ src/test/resources/application.properties | 16 ++++++ 11 files changed, 247 insertions(+), 9 deletions(-) create mode 100644 src/main/java/dev/hinterdorfer/FlowerRepository.java create mode 100644 src/main/java/dev/hinterdorfer/IndoorFlowerEntity.java create mode 100644 src/main/java/dev/hinterdorfer/OutdoorFlowerEntity.java create mode 100644 src/test/java/dev/hinterdorfer/FlowerPersistanceTest.java create mode 100644 src/test/java/dev/hinterdorfer/FlowerRepositoryTest.java create mode 100644 src/test/resources/application.properties diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 54c67d7..8db0706 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -6,6 +6,14 @@ + + + + + + + + diff --git a/pom.xml b/pom.xml index 4a2a5f2..4bbc826 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,12 @@ io.quarkus quarkus-arc + + org.projectlombok + lombok + 1.18.26 + provided + io.quarkus quarkus-junit5 @@ -65,6 +71,12 @@ rest-assured test + + + io.quarkus + quarkus-jdbc-h2 + test + @@ -90,6 +102,13 @@ ${compiler-plugin.version} true + + + org.projectlombok + lombok + 1.18.26 + + diff --git a/src/main/java/dev/hinterdorfer/FlowerEntity.java b/src/main/java/dev/hinterdorfer/FlowerEntity.java index 6aa1fb6..e75ac38 100644 --- a/src/main/java/dev/hinterdorfer/FlowerEntity.java +++ b/src/main/java/dev/hinterdorfer/FlowerEntity.java @@ -1,11 +1,15 @@ package dev.hinterdorfer; import jakarta.persistence.*; +import org.hibernate.annotations.GenericGenerator; import java.util.UUID; @Entity @Table(name = "flowers") +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name = "flower_type") +@DiscriminatorValue("FLOWER") @NamedQueries({ @NamedQuery(name = "FlowerEntity.findByColor", query = "SELECT f FROM FlowerEntity f WHERE f.color = :color"), @NamedQuery(name = "FlowerEntity.countAll", query = "SELECT COUNT(f) FROM FlowerEntity f") @@ -13,11 +17,42 @@ import java.util.UUID; public class FlowerEntity { @Id - @GeneratedValue + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") private UUID id; private String name; @Enumerated(EnumType.STRING) private Color color; + + // JPA requires a no-arg constructor + public FlowerEntity() { + } + + // Convenience constructor for tests and usage + public FlowerEntity(String name, Color color) { + this.name = name; + this.color = color; + } + + public UUID getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } } diff --git a/src/main/java/dev/hinterdorfer/FlowerPersistance.java b/src/main/java/dev/hinterdorfer/FlowerPersistance.java index 515e705..722c4b2 100644 --- a/src/main/java/dev/hinterdorfer/FlowerPersistance.java +++ b/src/main/java/dev/hinterdorfer/FlowerPersistance.java @@ -2,24 +2,20 @@ package dev.hinterdorfer; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.persistence.EntityManager; import java.util.Collection; @ApplicationScoped public class FlowerPersistance { @Inject - private EntityManager em; + private FlowerRepository repository; public Collection find (final Color color) { - return em.createNamedQuery("FlowerEntity.findByColor", FlowerEntity.class) - .setParameter("color", color) - .getResultList(); + return repository.findByColor(color); } public long count() { - return em.createNamedQuery("FlowerEntity.countAll", Long.class) - .getSingleResult(); + return repository.countAll(); } } diff --git a/src/main/java/dev/hinterdorfer/FlowerRepository.java b/src/main/java/dev/hinterdorfer/FlowerRepository.java new file mode 100644 index 0000000..7a02db6 --- /dev/null +++ b/src/main/java/dev/hinterdorfer/FlowerRepository.java @@ -0,0 +1,33 @@ +package dev.hinterdorfer; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import java.util.Collection; + +@ApplicationScoped +public class FlowerRepository { + + @Inject + EntityManager em; + + public Collection findByColor(Color color) { + return em.createNamedQuery("FlowerEntity.findByColor", FlowerEntity.class) + .setParameter("color", color) + .getResultList(); + } + + public long countAll() { + return em.createNamedQuery("FlowerEntity.countAll", Long.class) + .getSingleResult(); + } + + public void deleteAll() { + em.createQuery("DELETE FROM FlowerEntity").executeUpdate(); + } + + public void persist(FlowerEntity flower) { + em.persist(flower); + } +} + diff --git a/src/main/java/dev/hinterdorfer/IndoorFlowerEntity.java b/src/main/java/dev/hinterdorfer/IndoorFlowerEntity.java new file mode 100644 index 0000000..7952a2c --- /dev/null +++ b/src/main/java/dev/hinterdorfer/IndoorFlowerEntity.java @@ -0,0 +1,18 @@ +package dev.hinterdorfer; + +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; + +@Entity +@DiscriminatorValue("INDOOR") +public class IndoorFlowerEntity extends FlowerEntity { + + // JPA requires a no-arg constructor + public IndoorFlowerEntity() { + super(); + } + + public IndoorFlowerEntity(String name, Color color) { + super(name, color); + } +} diff --git a/src/main/java/dev/hinterdorfer/OutdoorFlowerEntity.java b/src/main/java/dev/hinterdorfer/OutdoorFlowerEntity.java new file mode 100644 index 0000000..246fac0 --- /dev/null +++ b/src/main/java/dev/hinterdorfer/OutdoorFlowerEntity.java @@ -0,0 +1,17 @@ +package dev.hinterdorfer; + +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; + +@Entity +@DiscriminatorValue("OUTDOOR") +public class OutdoorFlowerEntity extends FlowerEntity{ + + public OutdoorFlowerEntity() { + super(); + } + + public OutdoorFlowerEntity(String name, Color color) { + super(name, color); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b59f2af..e679244 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,6 @@ quarkus.datasource.db-kind=postgresql quarkus.datasource.username=schul-user-jonas -quarkus.datasource.password=123 +quarkus.datasource.password=1234 quarkus.datasource.jdbc.url=jdbc:postgresql://pg.hinterdorfer.dev:9234/schul-user-jonas?currentSchema=namedQuery quarkus.datasource.jdbc.max-size=8 quarkus.datasource.jdbc.min-size=2 @@ -9,3 +9,4 @@ quarkus.hibernate-orm.schema-management.strategy=drop-and-create quarkus.hibernate-orm.log.sql=true quarkus.hibernate-orm.log.bind-parameters=true + diff --git a/src/test/java/dev/hinterdorfer/FlowerPersistanceTest.java b/src/test/java/dev/hinterdorfer/FlowerPersistanceTest.java new file mode 100644 index 0000000..09f9b61 --- /dev/null +++ b/src/test/java/dev/hinterdorfer/FlowerPersistanceTest.java @@ -0,0 +1,49 @@ +package dev.hinterdorfer; + +import io.quarkus.test.junit.QuarkusTest; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@QuarkusTest +public class FlowerPersistanceTest { + + @Inject + FlowerPersistance persistence; + + @Inject + EntityManager em; + + @BeforeEach + @Transactional + public void setup() { + // clean table + em.createQuery("DELETE FROM FlowerEntity").executeUpdate(); + + // insert two flowers programmatically + em.persist(new FlowerEntity("Red Flower", Color.red)); + em.persist(new FlowerEntity("Blue Flower", Color.blue)); + em.flush(); + } + + @Test + public void testFindByColor() { + Collection reds = persistence.find(Color.red); + assertEquals(1, reds.size()); + assertTrue(reds.stream().allMatch(f -> f.getColor() == Color.red)); + } + + @Test + public void testCount() { + long c = persistence.count(); + assertEquals(2L, c); + } +} + diff --git a/src/test/java/dev/hinterdorfer/FlowerRepositoryTest.java b/src/test/java/dev/hinterdorfer/FlowerRepositoryTest.java new file mode 100644 index 0000000..6373178 --- /dev/null +++ b/src/test/java/dev/hinterdorfer/FlowerRepositoryTest.java @@ -0,0 +1,46 @@ +package dev.hinterdorfer; + +import io.quarkus.test.junit.QuarkusTest; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@QuarkusTest +public class FlowerRepositoryTest { + + @Inject + FlowerRepository repository; + + @Inject + EntityManager em; + + @BeforeEach + @Transactional + public void setup() { + repository.deleteAll(); + repository.persist(new FlowerEntity("Red Flower", Color.red)); + repository.persist(new FlowerEntity("Blue Flower", Color.blue)); + em.flush(); + } + + @Test + public void testFindByColor() { + Collection reds = repository.findByColor(Color.red); + assertEquals(1, reds.size()); + assertTrue(reds.stream().allMatch(f -> f.getColor() == Color.red)); + } + + @Test + public void testCount() { + long c = repository.countAll(); + assertEquals(2L, c); + } +} + diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 0000000..5450de7 --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1,16 @@ +# Test config: use in-memory H2 and prevent main import.sql from running +quarkus.datasource.db-kind=h2 +quarkus.datasource.username=sa +quarkus.datasource.password= +quarkus.datasource.jdbc.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=PostgreSQL + +# Let Hibernate create/drop schema for tests +quarkus.hibernate-orm.database.generation=drop-and-create + +# Disable automatic load of import.sql from main resources for tests +quarkus.hibernate-orm.sql-load-script= + +# Show SQL in test logs (helpful while developing tests) +quarkus.hibernate-orm.log.sql=true +quarkus.hibernate-orm.log.bind-parameters=true +