diff --git a/ebean-querybean/src/test/java/org/example/domain/MyInner.java b/ebean-querybean/src/test/java/org/example/domain/MyInner.java
new file mode 100644
index 000000000..e37dadaba
--- /dev/null
+++ b/ebean-querybean/src/test/java/org/example/domain/MyInner.java
@@ -0,0 +1,69 @@
+package org.example.domain;
+
+import javax.persistence.Embeddable;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import java.util.Objects;
+
+@Entity
+@IdClass(MyInner.ID.class)
+public class MyInner {
+
+ @Embeddable
+ public static class ID {
+ final long id;
+ final String one;
+
+ public ID(long id, String one) {
+ this.id = id;
+ this.one = one;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ID id1 = (ID) o;
+ return id == id1.id && one.equals(id1.one);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, one);
+ }
+ }
+
+ @Id
+ long id;
+ @Id
+ String one;
+ String description;
+
+ public long id() {
+ return id;
+ }
+
+ public MyInner id(long id) {
+ this.id = id;
+ return this;
+ }
+
+ public String one() {
+ return one;
+ }
+
+ public MyInner one(String beanOne) {
+ this.one = beanOne;
+ return this;
+ }
+
+ public String description() {
+ return description;
+ }
+
+ public MyInner description(String description) {
+ this.description = description;
+ return this;
+ }
+}
diff --git a/ebean-querybean/src/test/java/org/querytest/MyInnerTest.java b/ebean-querybean/src/test/java/org/querytest/MyInnerTest.java
new file mode 100644
index 000000000..c08d56d94
--- /dev/null
+++ b/ebean-querybean/src/test/java/org/querytest/MyInnerTest.java
@@ -0,0 +1,30 @@
+package org.querytest;
+
+import io.ebean.DB;
+import org.example.domain.MyInner;
+import org.example.domain.query.QMyInner;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class MyInnerTest {
+
+ @Test
+ void insert_and_find() {
+
+ MyInner myInner = new MyInner()
+ .id(42).one("one").description("foo");
+
+ DB.save(myInner);
+
+ MyInner found = DB.find(MyInner.class, new MyInner.ID(42, "one"));
+ assertThat(found).isNotNull();
+
+ MyInner found2 = new QMyInner()
+ .id.eq(42)
+ .one.eq("one")
+ .findOne();
+
+ assertThat(found2).isNotNull();
+ }
+}
diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml
index 70d5ec330..c57f81b61 100644
--- a/kotlin-querybean-generator/pom.xml
+++ b/kotlin-querybean-generator/pom.xml
@@ -12,7 +12,7 @@
kotlin-querybean-generator
- 1.6.0
+ 1.6.20
@@ -61,6 +61,13 @@
test
+
+ io.ebean
+ ebean-platform-h2
+ 13.6.2-SNAPSHOT
+ test
+
+
io.ebean
ebean-ddl-generator
@@ -106,7 +113,7 @@
io.ebean
kotlin-querybean-generator
- 12.13.0
+ 13.6.2-SNAPSHOT
@@ -155,8 +162,8 @@
- 1.8
- 1.8
+ 11
+ 11
-proc:none
diff --git a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java
index ee21711d2..ef3ee6204 100644
--- a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java
+++ b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java
@@ -63,13 +63,9 @@ class SimpleQueryBeanWriter {
);
private final Set importTypes = new TreeSet<>();
-
private final List properties = new ArrayList<>();
-
private final TypeElement element;
-
private final ProcessingContext processingContext;
-
private final boolean isEntity;
private final boolean embeddable;
private final String dbName;
@@ -80,10 +76,9 @@ class SimpleQueryBeanWriter {
private String destPackage;
private String origDestPackage;
-
private String shortName;
- private String origShortName;
-
+ private final String shortInnerName;
+ private final String origShortName;
private Append writer;
SimpleQueryBeanWriter(TypeElement element, ProcessingContext processingContext) {
@@ -92,8 +87,12 @@ class SimpleQueryBeanWriter {
this.element = element;
this.processingContext = processingContext;
this.beanFullName = element.getQualifiedName().toString();
- this.destPackage = derivePackage(beanFullName) + ".query";
- this.shortName = deriveShortName(beanFullName);
+ boolean nested = element.getNestingKind().isNested();
+ this.destPackage = Util.packageOf(nested, beanFullName) + ".query";
+ String sn = Util.shortName(nested, beanFullName);
+ this.shortInnerName = Util.shortName(false, sn);
+ this.shortName = sn.replace(".", "");
+ this.origShortName = shortName;
this.isEntity = processingContext.isEntity(element);
this.embeddable = processingContext.isEmbeddable(element);
this.dbName = findDbName();
@@ -129,10 +128,7 @@ class SimpleQueryBeanWriter {
*
*/
private void addClassProperties() {
-
- List fields = processingContext.allFields(element);
-
- for (VariableElement field : fields) {
+ for (VariableElement field : processingContext.allFields(element)) {
PropertyType type = processingContext.getPropertyType(field);
if (type != null) {
type.addImports(importTypes);
@@ -145,9 +141,7 @@ class SimpleQueryBeanWriter {
* Write the type query bean (root bean).
*/
void writeRootBean() throws IOException {
-
gatherPropertyDetails();
-
if (isEmbeddable()) {
processingContext.addEntity(beanFullName, dbName);
} else if (isEntity()) {
@@ -193,15 +187,12 @@ class SimpleQueryBeanWriter {
* Write the type query assoc bean.
*/
void writeAssocBean() throws IOException {
-
writingAssocBean = true;
origDestPackage = destPackage;
destPackage = destPackage + ".assoc";
- origShortName = shortName;
shortName = "Assoc" + shortName;
prepareAssocBeanImports();
-
writer = new Append(createFileWriter());
writePackage();
@@ -279,7 +270,6 @@ class SimpleQueryBeanWriter {
* Write all the fields.
*/
private void writeFields() {
-
for (PropertyMeta property : properties) {
String typeDefn = property.getTypeDefn(shortName, writingAssocBean);
lang().fieldDefn(writer, property.getName(), typeDefn);
@@ -292,7 +282,6 @@ class SimpleQueryBeanWriter {
* Write the class definition.
*/
private void writeClass() {
-
if (writingAssocBean) {
writer.append("/**").eol();
writer.append(" * Association query bean for %s.", shortName).eol();
@@ -301,7 +290,7 @@ class SimpleQueryBeanWriter {
writer.append(" */").eol();
writer.append(Constants.AT_GENERATED).eol();
writer.append(Constants.AT_TYPEQUERYBEAN).eol();
- lang().beginAssocClass(writer, shortName, origShortName);
+ lang().beginAssocClass(writer, shortName, shortInnerName);
} else {
writer.append("/**").eol();
@@ -331,7 +320,6 @@ class SimpleQueryBeanWriter {
* Write all the imports.
*/
private void writeImports() {
-
for (String importType : importTypes) {
writer.append("import %s;", importType).eol();
}
@@ -343,9 +331,7 @@ class SimpleQueryBeanWriter {
}
private Writer createFileWriter() throws IOException {
-
String relPath = destPackage.replace('.', '/');
-
File absDir = new File(generatedSourcesDir, relPath);
if (!absDir.exists() && !absDir.mkdirs()) {
processingContext.logNote("failed to create directories for:" + absDir.getAbsolutePath());
@@ -356,19 +342,4 @@ class SimpleQueryBeanWriter {
return new FileWriter(absFile);
}
- private String derivePackage(String name) {
- int pos = name.lastIndexOf('.');
- if (pos == -1) {
- return "";
- }
- return name.substring(0, pos);
- }
-
- private String deriveShortName(String name) {
- int pos = name.lastIndexOf('.');
- if (pos == -1) {
- return name;
- }
- return name.substring(pos + 1);
- }
}
diff --git a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/Util.java b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/Util.java
new file mode 100644
index 000000000..022348788
--- /dev/null
+++ b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/Util.java
@@ -0,0 +1,46 @@
+package io.ebean.querybean.generator;
+
+class Util {
+
+ static String packageOf(boolean nested, String originName) {
+ return nested ? nestedPackageOf(originName) : packageOf(originName);
+ }
+
+ private static String nestedPackageOf(String cls) {
+ int pos = cls.lastIndexOf('.');
+ if (pos < 0) {
+ return "";
+ }
+ pos = cls.lastIndexOf('.', pos - 1);
+ return (pos == -1) ? "" : cls.substring(0, pos);
+ }
+
+ private static String packageOf(String cls) {
+ int pos = cls.lastIndexOf('.');
+ return (pos == -1) ? "" : cls.substring(0, pos);
+ }
+
+ static String shortName(boolean nested, String fullType) {
+ return nested ? nestedShortName(fullType): shortName(fullType);
+ }
+
+ private static String nestedShortName(String fullType) {
+ int pos = fullType.lastIndexOf('.');
+ if (pos < 0) {
+ return fullType;
+ } else {
+ pos = fullType.lastIndexOf('.', pos - 1);
+ return pos < 0 ? fullType : fullType.substring(pos + 1);
+ }
+ }
+
+ private static String shortName(String fullType) {
+ int p = fullType.lastIndexOf('.');
+ if (p == -1) {
+ return fullType;
+ } else {
+ return fullType.substring(p + 1);
+ }
+ }
+
+}
diff --git a/kotlin-querybean-generator/src/test/kotlin/io/ebean/querybean/generator/UtilTest.kt b/kotlin-querybean-generator/src/test/kotlin/io/ebean/querybean/generator/UtilTest.kt
new file mode 100644
index 000000000..7965a398c
--- /dev/null
+++ b/kotlin-querybean-generator/src/test/kotlin/io/ebean/querybean/generator/UtilTest.kt
@@ -0,0 +1,20 @@
+package io.ebean.querybean.generator
+
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.Test
+
+internal class UtilTest {
+
+ @Test
+ fun packageOf() {
+ Assertions.assertEquals(Util.packageOf(true, "com.example.Foo.Bar"), "com.example")
+ Assertions.assertEquals(Util.packageOf(false, "com.example.other.foo.Bar"), "com.example.other.foo")
+ }
+
+ @Test
+ fun shortName() {
+ Assertions.assertEquals(Util.shortName(true, "com.example.Foo.Bar"), "Foo.Bar")
+ Assertions.assertEquals(Util.shortName(false, "com.example.foo.Bar"), "Bar")
+ Assertions.assertEquals(Util.shortName(false, "Bar"), "Bar")
+ }
+}
diff --git a/kotlin-querybean-generator/src/test/kotlin/org/example/domain/MyKotInner.kt b/kotlin-querybean-generator/src/test/kotlin/org/example/domain/MyKotInner.kt
new file mode 100644
index 000000000..b96fd987c
--- /dev/null
+++ b/kotlin-querybean-generator/src/test/kotlin/org/example/domain/MyKotInner.kt
@@ -0,0 +1,20 @@
+package org.example.domain
+
+import javax.persistence.*
+
+@Entity
+@Table(name = "t_inner")
+@IdClass(MyKotInner.Mid::class)
+class MyKotInner {
+
+ @Id
+ var one: String = "0"
+ @Id
+ var two: String = "0"
+
+ var description: String? = null
+
+ @Embeddable
+ data class Mid(val one: String, val two: String)
+
+}
diff --git a/kotlin-querybean-generator/src/test/kotlin/org/example/otherpackage/InnerTest.kt b/kotlin-querybean-generator/src/test/kotlin/org/example/otherpackage/InnerTest.kt
new file mode 100644
index 000000000..caa3bb0a0
--- /dev/null
+++ b/kotlin-querybean-generator/src/test/kotlin/org/example/otherpackage/InnerTest.kt
@@ -0,0 +1,23 @@
+package org.example.otherpackage
+
+import io.ebean.DB
+import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat
+import org.example.domain.MyKotInner
+import org.junit.jupiter.api.Test
+
+class InnerTest {
+
+ @Test
+ fun split_normal() {
+ val my = MyKotInner()
+ my.one = "a"
+ my.two = "b"
+ my.description = "desc"
+ DB.save(my)
+
+ val myId = MyKotInner.Mid("a", "b")
+
+ val found = DB.find(MyKotInner::class.java, myId)
+ assertThat(found).isNotNull
+ }
+}
diff --git a/kotlin-querybean-generator/src/test/resources/META-INF/ebean-version.mf b/kotlin-querybean-generator/src/test/resources/META-INF/ebean-version.mf
new file mode 100644
index 000000000..d95d9c73c
--- /dev/null
+++ b/kotlin-querybean-generator/src/test/resources/META-INF/ebean-version.mf
@@ -0,0 +1 @@
+ebean-version: 141
diff --git a/kotlin-querybean-generator/src/test/resources/application-test.properties b/kotlin-querybean-generator/src/test/resources/application-test.properties
new file mode 100644
index 000000000..180ec19fc
--- /dev/null
+++ b/kotlin-querybean-generator/src/test/resources/application-test.properties
@@ -0,0 +1,9 @@
+ebean.ddl.generate=true
+ebean.ddl.run=true
+#datasource.default=h2
+
+datasource.db.username=sa
+datasource.db.password=
+datasource.db.url=jdbc:h2:mem:testKotlin
+
+
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 3d55fd1ad..f8e965f04 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
@@ -18,13 +18,9 @@ import java.util.TreeSet;
class SimpleQueryBeanWriter {
private final Set importTypes = new TreeSet<>();
-
private final List properties = new ArrayList<>();
-
private final TypeElement element;
-
private final ProcessingContext processingContext;
-
private final String dbName;
private final String beanFullName;
private final boolean isEntity;
@@ -33,17 +29,21 @@ class SimpleQueryBeanWriter {
private String destPackage;
private String origDestPackage;
-
private String shortName;
- private String origShortName;
+ private final String shortInnerName;
+ private final String origShortName;
private Append writer;
SimpleQueryBeanWriter(TypeElement element, ProcessingContext processingContext) {
this.element = element;
this.processingContext = processingContext;
this.beanFullName = element.getQualifiedName().toString();
- this.destPackage = derivePackage(beanFullName) + ".query";
- this.shortName = deriveShortName(beanFullName);
+ boolean nested = element.getNestingKind().isNested();
+ this.destPackage = Util.packageOf(nested, beanFullName) + ".query";
+ String sn = Util.shortName(nested, beanFullName);
+ this.shortInnerName = Util.shortName(false, sn);
+ this.shortName = sn.replace('.', '$');
+ this.origShortName = shortName;
this.isEntity = processingContext.isEntity(element);
this.embeddable = processingContext.isEmbeddable(element);
this.dbName = findDbName();
@@ -125,7 +125,6 @@ class SimpleQueryBeanWriter {
writingAssocBean = true;
origDestPackage = destPackage;
destPackage = destPackage + ".assoc";
- origShortName = shortName;
shortName = "Assoc" + shortName;
prepareAssocBeanImports();
@@ -318,7 +317,7 @@ class SimpleQueryBeanWriter {
writer.append(" */").eol();
writer.append(Constants.AT_GENERATED).eol();
writer.append(Constants.AT_TYPEQUERYBEAN).eol();
- writer.append("public class Q%s extends TQAssocBean<%s,R> {", shortName, origShortName).eol();
+ writer.append("public class Q%s extends TQAssocBean<%s,R> {", shortName, shortInnerName).eol();
} else {
writer.append("/**").eol();
@@ -388,19 +387,4 @@ class SimpleQueryBeanWriter {
return jfo.openWriter();
}
- private String derivePackage(String name) {
- int pos = name.lastIndexOf('.');
- if (pos == -1) {
- return "";
- }
- return name.substring(0, pos);
- }
-
- private String deriveShortName(String name) {
- int pos = name.lastIndexOf('.');
- if (pos == -1) {
- return name;
- }
- return name.substring(pos + 1);
- }
}
diff --git a/querybean-generator/src/main/java/io/ebean/querybean/generator/Util.java b/querybean-generator/src/main/java/io/ebean/querybean/generator/Util.java
new file mode 100644
index 000000000..022348788
--- /dev/null
+++ b/querybean-generator/src/main/java/io/ebean/querybean/generator/Util.java
@@ -0,0 +1,46 @@
+package io.ebean.querybean.generator;
+
+class Util {
+
+ static String packageOf(boolean nested, String originName) {
+ return nested ? nestedPackageOf(originName) : packageOf(originName);
+ }
+
+ private static String nestedPackageOf(String cls) {
+ int pos = cls.lastIndexOf('.');
+ if (pos < 0) {
+ return "";
+ }
+ pos = cls.lastIndexOf('.', pos - 1);
+ return (pos == -1) ? "" : cls.substring(0, pos);
+ }
+
+ private static String packageOf(String cls) {
+ int pos = cls.lastIndexOf('.');
+ return (pos == -1) ? "" : cls.substring(0, pos);
+ }
+
+ static String shortName(boolean nested, String fullType) {
+ return nested ? nestedShortName(fullType): shortName(fullType);
+ }
+
+ private static String nestedShortName(String fullType) {
+ int pos = fullType.lastIndexOf('.');
+ if (pos < 0) {
+ return fullType;
+ } else {
+ pos = fullType.lastIndexOf('.', pos - 1);
+ return pos < 0 ? fullType : fullType.substring(pos + 1);
+ }
+ }
+
+ private static String shortName(String fullType) {
+ int p = fullType.lastIndexOf('.');
+ if (p == -1) {
+ return fullType;
+ } else {
+ return fullType.substring(p + 1);
+ }
+ }
+
+}
diff --git a/querybean-generator/src/test/java/io/ebean/querybean/generator/UtilTest.java b/querybean-generator/src/test/java/io/ebean/querybean/generator/UtilTest.java
new file mode 100644
index 000000000..cccab2ed8
--- /dev/null
+++ b/querybean-generator/src/test/java/io/ebean/querybean/generator/UtilTest.java
@@ -0,0 +1,22 @@
+package io.ebean.querybean.generator;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class UtilTest {
+
+ @Test
+ void packageOf() {
+ assertEquals(Util.packageOf(true, "com.example.Foo.Bar"), "com.example");
+ assertEquals(Util.packageOf(false, "com.example.other.foo.Bar"), "com.example.other.foo");
+ }
+
+ @Test
+ void shortName() {
+ assertEquals(Util.shortName(true, "com.example.Foo.Bar"), "Foo.Bar");
+ assertEquals(Util.shortName(false, "com.example.foo.Bar"), "Bar");
+ assertEquals(Util.shortName(false, "Bar"), "Bar");
+ }
+
+}