blog: @LazyToOne, formatting, comments.
Change-Id: I44655fd7b43822f7c1a73af22402684acb49d333
diff --git a/blog/pom.xml b/blog/pom.xml
index 4d7be41..832ff43 100644
--- a/blog/pom.xml
+++ b/blog/pom.xml
@@ -73,6 +73,12 @@
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.jetbrains</groupId>
+ <artifactId>annotations</artifactId>
+ <version>RELEASE</version>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
<build>
@@ -94,11 +100,6 @@
</plugin>
<plugin>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>${compiler-plugin.version}</version>
- </plugin>
-
- <plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
@@ -108,9 +109,11 @@
</systemPropertyVariables>
</configuration>
</plugin>
+
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
+ <version>${compiler-plugin.version}</version>
<configuration>
<source>15</source>
<target>15</target>
diff --git a/blog/src/main/java/eu/mulk/demos/blog/Author.java b/blog/src/main/java/eu/mulk/demos/blog/Author.java
index 53c21c4..d544d2e 100644
--- a/blog/src/main/java/eu/mulk/demos/blog/Author.java
+++ b/blog/src/main/java/eu/mulk/demos/blog/Author.java
@@ -2,12 +2,20 @@
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.OneToOne;
+import org.hibernate.annotations.LazyToOne;
+import org.hibernate.annotations.LazyToOneOption;
@Entity
public class Author extends PanacheEntity {
public String name;
+ @OneToOne(fetch = FetchType.LAZY, mappedBy = "author")
+ @LazyToOne(LazyToOneOption.NO_PROXY)
+ public BasicCredentials basicCredentials;
+
public static Author create(String name) {
var a = new Author();
a.name = name;
diff --git a/blog/src/main/java/eu/mulk/demos/blog/BasicCredentials.java b/blog/src/main/java/eu/mulk/demos/blog/BasicCredentials.java
new file mode 100644
index 0000000..01471c6
--- /dev/null
+++ b/blog/src/main/java/eu/mulk/demos/blog/BasicCredentials.java
@@ -0,0 +1,28 @@
+package eu.mulk.demos.blog;
+
+import io.quarkus.hibernate.orm.panache.PanacheEntity;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.MapsId;
+import javax.persistence.OneToOne;
+
+@Entity
+public class BasicCredentials extends PanacheEntity {
+
+ @OneToOne(fetch = FetchType.LAZY)
+ @MapsId
+ public Author author;
+
+ public String username;
+
+ public String password;
+
+ public static BasicCredentials create(Author author, String username, String password) {
+ var bc = new BasicCredentials();
+ bc.author = author;
+ bc.id = author.id;
+ bc.username = username;
+ bc.password = password;
+ return bc;
+ }
+}
diff --git a/blog/src/main/java/eu/mulk/demos/blog/DemoDataLoader.java b/blog/src/main/java/eu/mulk/demos/blog/DemoDataLoader.java
index 3ee745a..cbaed9a 100644
--- a/blog/src/main/java/eu/mulk/demos/blog/DemoDataLoader.java
+++ b/blog/src/main/java/eu/mulk/demos/blog/DemoDataLoader.java
@@ -13,6 +13,7 @@
@ApplicationScoped
public class DemoDataLoader {
+ static final int AUTHOR_COUNT = 3;
static final int POST_COUNT = 10;
static final int COMMENT_COUNT = 3;
static final int CATEGORY_COUNT = 2;
@@ -28,25 +29,32 @@
}
// Authors
- var mb = Author.create("Matthias Benkard");
- em.persist(mb);
+ var authors =
+ nat(AUTHOR_COUNT)
+ .map(x -> Author.create("Author #%d".formatted(x)))
+ .collect(toList());
+ authors.forEach(em::persist);
// Posts
var posts =
- nat(POST_COUNT).map(x -> Post.create(mb, "Post #%d".formatted(x))).collect(toList());
+ nat(POST_COUNT)
+ .map(x -> Post.create(authors.get(x % AUTHOR_COUNT), "Post #%d".formatted(x)))
+ .collect(toList());
posts.forEach(em::persist);
// Comments
for (var post : posts) {
post.comments =
nat(COMMENT_COUNT)
- .map(x -> Comment.create(post, "Anonymous Coward", "First post")).collect(toList());
+ .map(x -> Comment.create(post, "Anonymous Coward", "First post"))
+ .collect(toList());
post.comments.forEach(em::persist);
}
// Categories
var categories =
- nat(CATEGORY_COUNT).map(x -> Category.create("Category #%d".formatted(x)))
+ nat(CATEGORY_COUNT)
+ .map(x -> Category.create("Category #%d".formatted(x)))
.collect(toList());
categories.forEach(em::persist);
for (var post : posts) {
diff --git a/blog/src/main/java/eu/mulk/demos/blog/PostResource.java b/blog/src/main/java/eu/mulk/demos/blog/PostResource.java
index 44410cf..532e873 100644
--- a/blog/src/main/java/eu/mulk/demos/blog/PostResource.java
+++ b/blog/src/main/java/eu/mulk/demos/blog/PostResource.java
@@ -1,43 +1,138 @@
package eu.mulk.demos.blog;
import java.util.List;
+import java.util.Set;
import javax.transaction.Transactional;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
+import org.hibernate.annotations.LazyToOne;
+import org.hibernate.annotations.LazyToOneOption;
+import org.jboss.logging.Logger;
@Path("/posts")
public class PostResource {
+ static final Logger log = Logger.getLogger(PostResource.class);
+
+ /**
+ * Fetches all posts with no extra information.
+ *
+ * Simple. No surprises.
+ */
@GET
@Produces(MediaType.TEXT_PLAIN)
@Transactional
public List<Post> getAll() {
+ clearLog();
+
return Post.findAll().list();
}
+ /**
+ * Fetches all posts with comments included.
+ *
+ * Lazy fetching. Simple. No surprises.
+ */
@GET
@Produces(MediaType.TEXT_PLAIN)
@Transactional
@Path("/q1")
public List<Post> getAllWithComments() {
- return Post.find("""
- SELECT p FROM Post p
- LEFT JOIN FETCH p.comments
- """).list();
+ clearLog();
+
+ return Post.find(
+ """
+ SELECT p FROM Post p
+ LEFT JOIN FETCH p.comments
+ """)
+ .list();
}
+ /**
+ * Fetches all posts with author info included.
+ *
+ * <strong>Oops!</strong>
+ *
+ * {@link LazyToOne} with {@link LazyToOneOption#NO_PROXY} is needed to make this efficient.
+ */
@GET
@Produces(MediaType.TEXT_PLAIN)
@Transactional
@Path("/q2")
- public List<Post> getAllWithCommentsAndCategories() {
- return Post.find("""
- SELECT p FROM Post p
- LEFT JOIN FETCH p.comments
- LEFT JOIN FETCH p.categories
- """).list();
+ public List<Post> getAllWithAuthors() {
+ clearLog();
+
+ return Post.find(
+ """
+ SELECT p FROM Post p
+ LEFT JOIN FETCH p.author
+ """)
+ .list();
}
+ /**
+ * Fetches all posts with comments and category info included.
+ *
+ * <strong>Oops!</strong> Crashes.
+ *
+ * Either use {@link Set} and get bad performance or do it as in {@link
+ * #getAllWithCommentsAndCategories2()}.
+ */
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ @Transactional
+ @Path("/q3")
+ public List<Post> getAllWithCommentsAndCategories() {
+ clearLog();
+
+ return Post.find(
+ """
+ SELECT p FROM Post p
+ LEFT JOIN FETCH p.comments
+ LEFT JOIN FETCH p.categories
+ """)
+ .list();
+ }
+
+ /**
+ * Fetches all posts with comments and category info included.
+ *
+ * 2 queries, but hey, no cartesian explosion! Works really well.
+ */
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ @Transactional
+ @Path("/q4")
+ public List<Post> getAllWithCommentsAndCategories2() {
+ clearLog();
+
+ List<Post> posts = Post.find(
+ """
+ SELECT p FROM Post p
+ LEFT JOIN FETCH p.comments
+ """)
+ .list();
+
+ posts = Post.find(
+ """
+ SELECT DISTINCT p FROM Post p
+ LEFT JOIN FETCH p.categories
+ WHERE p IN (?1)
+ """,
+ posts)
+ .list();
+
+ return posts;
+ }
+
+ private static void clearLog() {
+ log.infof("""
+
+ -----------------------------------------------------
+ -------------------- NEW REQUEST --------------------
+ -----------------------------------------------------
+ """);
+ }
}