From f03892a4bdd0a01c63ee0610f78f0200cf4ac1ea Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 11 Sep 2023 23:01:44 +1200 Subject: [PATCH] #3216 - Fix querybean generation for @Embedded beans (fix for 13.22.0 change) Version 13.22.0 added a change to query bean generation that has an issue for embedded beans. This fixes that issue. --- .../test/java/org/example/domain/CaoBean.java | 40 ++++++++++++ .../test/java/org/example/domain/CaoKey.java | 42 ++++++++++++ .../java/org/querytest/QueryCaoBeanTest.java | 44 +++++++++++++ .../ebean/querybean/generator/Constants.java | 1 + .../generator/SimpleQueryBeanWriter.java | 64 +++++++++++-------- 5 files changed, 163 insertions(+), 28 deletions(-) create mode 100644 ebean-querybean/src/test/java/org/example/domain/CaoBean.java create mode 100644 ebean-querybean/src/test/java/org/example/domain/CaoKey.java create mode 100644 ebean-querybean/src/test/java/org/querytest/QueryCaoBeanTest.java diff --git a/ebean-querybean/src/test/java/org/example/domain/CaoBean.java b/ebean-querybean/src/test/java/org/example/domain/CaoBean.java new file mode 100644 index 000000000..23ca4eb73 --- /dev/null +++ b/ebean-querybean/src/test/java/org/example/domain/CaoBean.java @@ -0,0 +1,40 @@ +package org.example.domain; + +import javax.persistence.*; + +@Entity +public class CaoBean { + + @Id + private CaoKey key; + + private String description; + + @Version + private long version; + + public CaoKey getKey() { + return key; + } + + public void setKey(CaoKey key) { + this.key = key; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + +} diff --git a/ebean-querybean/src/test/java/org/example/domain/CaoKey.java b/ebean-querybean/src/test/java/org/example/domain/CaoKey.java new file mode 100644 index 000000000..5b25b5337 --- /dev/null +++ b/ebean-querybean/src/test/java/org/example/domain/CaoKey.java @@ -0,0 +1,42 @@ +package org.example.domain; + +import javax.persistence.Embeddable; + +@Embeddable +public class CaoKey { + + private final int customer; + private final int type; + + public CaoKey(int customer, int type) { + this.customer = customer; + this.type = type; + } + + public int customer() { + return customer; + } + + public int type() { + return type; + } + + @Override + public int hashCode() { + int hc = 31 * 7 + customer; + hc = 31 * hc + type; + return hc; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof CaoKey) { + CaoKey k = (CaoKey) o; + return k.customer == customer && k.type == type; + } + return false; + } +} diff --git a/ebean-querybean/src/test/java/org/querytest/QueryCaoBeanTest.java b/ebean-querybean/src/test/java/org/querytest/QueryCaoBeanTest.java new file mode 100644 index 000000000..ddcb608eb --- /dev/null +++ b/ebean-querybean/src/test/java/org/querytest/QueryCaoBeanTest.java @@ -0,0 +1,44 @@ +package org.querytest; + +import io.ebean.DB; +import org.example.domain.CaoBean; +import org.example.domain.CaoKey; +import org.example.domain.query.QCaoBean; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class QueryCaoBeanTest { + + @Test + void withEmbeddedId() { + insertTestData(); + + List list = new QCaoBean() + .key.type.eq(3) + .findList(); + + assertThat(list).hasSize(2); + for (CaoBean caoBean : list) { + assertThat(caoBean.getKey().type()).isEqualTo(3); + } + } + + private static void insertTestData() { + var key = new CaoKey(42, 3); + var bean = new CaoBean(); + bean.setKey(key); + bean.setDescription("hi"); + + DB.save(bean); + + var key2 = new CaoKey(43, 3); + var bean2 = new CaoBean(); + bean2.setKey(key2); + bean2.setDescription("hi2"); + + DB.save(bean2); + } +} diff --git a/querybean-generator/src/main/java/io/ebean/querybean/generator/Constants.java b/querybean-generator/src/main/java/io/ebean/querybean/generator/Constants.java index bf506d4e0..5b152eb4a 100644 --- a/querybean-generator/src/main/java/io/ebean/querybean/generator/Constants.java +++ b/querybean-generator/src/main/java/io/ebean/querybean/generator/Constants.java @@ -22,6 +22,7 @@ interface Constants { String TQROOTBEAN = "io.ebean.typequery.TQRootBean"; String TQASSOCBEAN = "io.ebean.typequery.TQAssocBean"; + String TQASSOC = "io.ebean.typequery.TQAssoc"; String TYPEQUERYBEAN = "io.ebean.typequery.TypeQueryBean"; String DATABASE = "io.ebean.Database"; String DB = "io.ebean.DB"; diff --git a/querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java b/querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java index 8ad6f9783..e5de04a56 100644 --- a/querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java +++ b/querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java @@ -77,16 +77,21 @@ class SimpleQueryBeanWriter { private void gatherPropertyDetails() { importTypes.add(Constants.GENERATED); importTypes.add(beanFullName); - importTypes.add(Constants.TQASSOCBEAN); - importTypes.add(Constants.TQROOTBEAN); importTypes.add(Constants.TYPEQUERYBEAN); - importTypes.add(Constants.DATABASE); - importTypes.add(Constants.FETCHGROUP); - importTypes.add(Constants.QUERY); - importTypes.add(Constants.TRANSACTION); - importTypes.add(Constants.CONSUMER); - importTypes.add(Constants.EXPR); - importTypes.add(Constants.EXPRESSIONLIST); + if (embeddable) { + importTypes.add(Constants.TQASSOC); + } else { + importTypes.add(Constants.TQASSOCBEAN); + importTypes.add(Constants.TQROOTBEAN); + importTypes.add(Constants.DATABASE); + importTypes.add(Constants.FETCHGROUP); + importTypes.add(Constants.QUERY); + importTypes.add(Constants.TRANSACTION); + importTypes.add(Constants.CONSUMER); + importTypes.add(Constants.EXPR); + importTypes.add(Constants.EXPRESSIONLIST); + } + if (implementsInterface != null) { implementsInterfaceFullName = implementsInterface.getQualifiedName().toString(); boolean nested = implementsInterface.getNestingKind().isNested(); @@ -122,24 +127,20 @@ class SimpleQueryBeanWriter { */ void writeRootBean() throws IOException { gatherPropertyDetails(); - if (isEmbeddable()) { - processingContext.addEntity(beanFullName, dbName); - } else if (isEntity()) { - processingContext.addEntity(beanFullName, dbName); - writer = new Append(createFileWriter()); - - writePackage(); - writeImports(); - writeClass(); + processingContext.addEntity(beanFullName, dbName); + writer = new Append(createFileWriter()); + writePackage(); + writeImports(); + writeClass(); + if (isEntity()) { writeAlias(); writeFields(); writeConstructors(); writeStaticAliasClass(); - writeAssocClass(); - writeClassEnd(); - - writer.close(); } + writeAssocClass(); + writeClassEnd(); + writer.close(); } /** @@ -237,8 +238,12 @@ class SimpleQueryBeanWriter { writer.append(" * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.").eol(); writer.append(" */").eol(); writer.append(Constants.AT_GENERATED).eol(); - writer.append(Constants.AT_TYPEQUERYBEAN).eol(); - writer.append("public final class Q%s extends TQRootBean<%1$s,Q%1$s> {", shortName).eol(); + if (embeddable) { + writer.append("public final class Q%s {", shortName).eol(); + } else { + writer.append(Constants.AT_TYPEQUERYBEAN).eol(); + writer.append("public final class Q%s extends TQRootBean<%1$s,Q%1$s> {", shortName).eol(); + } writer.eol(); } @@ -276,9 +281,9 @@ class SimpleQueryBeanWriter { writer.append(" ").append(Constants.AT_GENERATED).eol(); writer.append(" ").append(Constants.AT_TYPEQUERYBEAN).eol(); if (embeddable) { - writer.append(" public static final class Assoc extends TQAssoc<%s,R> {", shortName, shortInnerName).eol(); + writer.append(" public static final class Assoc extends TQAssoc<%s,R> {", shortInnerName).eol(); } else { - writer.append(" public static final class Assoc extends TQAssocBean<%s,R,Q%s> {", shortName, shortInnerName, origShortName).eol(); + writer.append(" public static final class Assoc extends TQAssocBean<%s,R,Q%s> {", shortName, shortInnerName).eol(); } for (PropertyMeta property : properties) { writer.append(" "); @@ -287,12 +292,15 @@ class SimpleQueryBeanWriter { } writer.eol(); writeAssocBeanConstructor(); - writeAssocFilterMany(); - writeAssocBeanFetch(); + if (!embeddable) { + writeAssocFilterMany(); + writeAssocBeanFetch(); + } writer.append(" }").eol(); } private void writeAssocFilterMany() { + writer.eol(); writer.append(" public final R filterMany(Consumer apply) {", shortName).eol(); writer.append(" final ExpressionList list = Expr.factory().expressionList();", shortName).eol(); writer.append(" final var qb = new Q%s(list);", shortName).eol();