#3536 kotlin-querybean-generator update for filterMany() changes

Brings the kotlin-querybean-generator up to date with the [java] querybean-generator in terms of how it has specific "associated beans" for ToOne and ToMany type relationships
This commit is contained in:
Rob Bygrave
2025-02-09 21:24:51 +13:00
parent 1e38ed9efc
commit b066f9c072
9 changed files with 179 additions and 249 deletions
@@ -11,6 +11,8 @@ interface Constants {
String ENTITY = "jakarta.persistence.Entity";
String EMBEDDABLE = "jakarta.persistence.Embeddable";
String CONVERTER = "jakarta.persistence.Converter";
String ONE_TO_MANY = "jakarta.persistence.OneToMany";
String MANY_TO_MANY = "jakarta.persistence.ManyToMany";
String EBEAN_COMPONENT = "io.ebean.annotation.EbeanComponent";
String DBARRAY = "io.ebean.annotation.DbArray";
@@ -18,10 +20,6 @@ interface Constants {
String DBJSONB = "io.ebean.annotation.DbJsonB";
String DBNAME = "io.ebean.annotation.DbName";
String TQASSOC = "io.ebean.typequery.TQAssoc";
String TQASSOCBEAN = "io.ebean.typequery.TQAssocBean";
String TQPROPERTY = "io.ebean.typequery.TQProperty";
String MODULEINFO = "io.ebean.config.ModuleInfo";
String METAINF_MANIFEST = "META-INF/ebean-generated-info.mf";
String METAINF_SERVICES_MODULELOADER = "META-INF/services/io.ebean.config.EntityClassRegister";
@@ -1,9 +1,8 @@
package io.ebean.querybean.generator;
class KotlinLangAdapter implements LangAdapter {
final class KotlinLangAdapter {
@Override
public void alias(Append writer, String shortName, String fullName) {
void alias(Append writer, String shortName, String fullName) {
writer.append(" companion object {").eol();
writer.append(" /**").eol();
writer.append(" * shared 'Alias' instance used to provide").eol();
@@ -20,87 +19,38 @@ class KotlinLangAdapter implements LangAdapter {
writer.append(" }").eol().eol();
}
@Override
public void assocBeanConstructor(Append writer, String shortName) {
writer.append(" constructor(name: String, root: R) : super(name, root)").eol();
writer.eol();
writer.append(" constructor(name: String, root: R, prefix: String) : super(name, root, prefix)").eol();
}
@Override
public void fetch(Append writer, String origShortName) {
writeAssocBeanFetch(writer, origShortName, "", "Eagerly fetch this association loading the specified properties.");
writeAssocBeanFetch(writer, origShortName, "Query", "Eagerly fetch this association using a 'query join' loading the specified properties.");
writeAssocBeanFetch(writer, origShortName, "Cache", "Eagerly fetch this association using L2 cache.");
writeAssocBeanFetch(writer, origShortName, "Lazy", "Use lazy loading for this association loading the specified properties.");
}
private void writeAssocBeanFetch(Append writer, String origShortName, String fetchType, String comment) {
// fun fetch(vararg properties: TQProperty<QContact,?>): R {
// return fetchProperties(*properties)
// }
writer.append(" /**").eol();
writer.append(" * ").append(comment).eol();
writer.append(" */").eol();
writer.append(" fun fetch%s(vararg properties: TQProperty<Q%s,Any>) : R {", fetchType, origShortName).eol();
writer.append(" return fetch%sProperties(*properties)", fetchType).eol();
writer.append(" }").eol();
writer.eol();
}
@Override
public void rootBeanConstructor(Append writer, String shortName, String dbName, String fullName) {
void rootBeanConstructor(Append writer, String shortName, String dbName, String fullName) {
String name = (dbName == null) ? "default" : dbName;
writer.append(" /**").eol();
writer.append(" * Construct using the %s Database.", name).eol();
writer.append(" */").eol();
writer.append(" /** Construct using the %s Database. */", name).eol();
if (dbName == null) {
writer.append(" constructor() : super(%s::class.java)", fullName).eol().eol();
} else {
writer.append(" constructor() : super(%s::class.java, io.ebean.DB.byName(\"%s\"))", fullName, dbName).eol().eol();
}
writer.append(" /**").eol();
writer.append(" * @deprecated migrate to query.usingTransaction()", name).eol();
writer.append(" */").eol();
writer.append(" @Deprecated(message=\"migrate to query.usingTransaction()\")").eol();
writer.append(" /** @deprecated migrate to query.usingTransaction() */", name).eol();
writer.append(" @Deprecated(message=\"migrate to query.usingTransaction()\")").eol();
if (dbName == null) {
writer.append(" constructor(transaction: io.ebean.Transaction) : super(%s::class.java, transaction)", fullName).eol().eol();
} else {
writer.append(" constructor(transaction: io.ebean.Transaction) : super(%s::class.java, io.ebean.DB.byName(\"%s\"), transaction)", fullName, dbName).eol().eol();
}
writer.eol();
writer.append(" /**").eol();
writer.append(" * Construct with a given Database.").eol();
writer.append(" */").eol();
writer.append(" /** Construct with a given Database. */").eol();
writer.append(" constructor(database: io.ebean.Database) : super(%s::class.java, database)", fullName).eol().eol();
writer.append(" /**").eol();
writer.append(" * Construct for Alias.").eol();
writer.append(" */").eol();
writer.append(" /** Construct for Alias. */").eol();
writer.append(" private constructor(dummy: Boolean) : super(dummy)").eol().eol();
writer.append(" /**").eol();
writer.append(" * Private constructor for FetchGroup building.").eol();
writer.append(" */").eol();
writer.append(" private constructor(fetchGroupQuery: io.ebean.Query<%s>) : super(fetchGroupQuery)", fullName).eol();
writer.append(" /** Private constructor for FetchGroup building. */").eol();
writer.append(" private constructor(fetchGroupQuery: io.ebean.Query<%s>) : super(fetchGroupQuery)", fullName).eol().eol();
writer.append(" /** Private constructor for filterMany */").eol();
writer.append(" private constructor(filter: io.ebean.ExpressionList<%s>) : super(filter)", fullName).eol().eol();
writer.eol();
writer.append(" /** Return a copy of the query. */").eol();
writer.append(" override fun copy() : Q%s {", shortName).eol();
writer.append(" return Q%s(query().copy())", shortName).eol();
writer.append(" }").eol();
writer.eol();
writer.append(" }").eol().eol();
}
@Override
public void fieldDefn(Append writer, String propertyName, String typeDefn) {
writer.append(" lateinit var %s: ", propertyName);
if (typeDefn.endsWith(",Integer>")) {
typeDefn = typeDefn.replace(",Integer>", ",Int>");
}
writer.append(typeDefn);
}
}
@@ -1,16 +0,0 @@
package io.ebean.querybean.generator;
public interface LangAdapter {
void alias(Append writer, String shortName, String beanFullName);
void rootBeanConstructor(Append writer, String shortName, String dbName, String beanFullName);
void assocBeanConstructor(Append writer, String shortName);
void fetch(Append writer, String origShortName);
void fieldDefn(Append writer, String propertyName, String typeDefn);
}
@@ -239,6 +239,10 @@ class ProcessingContext implements Constants {
return hasAnnotations(element, EMBEDDABLE);
}
private static boolean dbToMany(Element field) {
return hasAnnotations(field, ONE_TO_MANY, MANY_TO_MANY);
}
/**
* Find the DbName annotation and return name if found.
*/
@@ -261,6 +265,7 @@ class ProcessingContext implements Constants {
}
PropertyType getPropertyType(VariableElement field) {
boolean toMany = dbToMany(field);
if (dbJsonField(field)) {
return propertyTypeMap.getDbJsonType();
}
@@ -301,36 +306,30 @@ class ProcessingContext implements Constants {
if (targetEntity != null) {
final TypeElement element = elementUtils.getTypeElement(targetEntity);
if (isEntityOrEmbedded(element)) {
return createPropertyTypeAssoc(typeDef(element.asType()));
boolean embeddable = isEmbeddable(element);
return createPropertyTypeAssoc(embeddable, toMany, typeDef(element.asType()));
}
}
if (isEntityOrEmbedded(fieldType)) {
// public QAssocContact<QCustomer> contacts;
return createPropertyTypeAssoc(typeDef(typeMirror));
boolean embeddable = isEmbeddable(fieldType);
return createPropertyTypeAssoc(embeddable, toMany, typeDef(typeMirror));
}
final PropertyType result;
if (typeMirror.getKind() == TypeKind.DECLARED) {
DeclaredType declaredType = (DeclaredType) typeMirror;
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (typeArguments.size() == 1) {
TypeMirror argType = typeArguments.get(0);
Element argElement = asElement(argType);
if (isEntityOrEmbedded(argElement)) {
return createPropertyTypeAssoc(typeDef(argElement.asType()));
}
} else if (typeArguments.size() == 2) {
TypeMirror argType = typeArguments.get(1);
Element argElement = asElement(argType);
if (isEntityOrEmbedded(argElement)) {
return createPropertyTypeAssoc(typeDef(argElement.asType()));
}
}
result = createManyTypeAssoc(field, (DeclaredType) typeMirror);
} else {
result = null;
}
if (typeInstanceOf(typeMirror, "java.lang.Comparable")) {
return new PropertyTypeScalarComparable(trimAnnotations(typeMirror.toString()));
if (result != null) {
return result;
} else {
return new PropertyTypeScalar(trimAnnotations(typeMirror.toString()));
if (typeInstanceOf(typeMirror, "java.lang.Comparable")) {
return new PropertyTypeScalarComparable(trimAnnotations(typeMirror.toString()));
} else {
return new PropertyTypeScalar(trimAnnotations(typeMirror.toString()));
}
}
}
@@ -357,6 +356,25 @@ class ProcessingContext implements Constants {
.anyMatch(t -> typeInstanceOf(t, desiredInterface));
}
private PropertyType createManyTypeAssoc(VariableElement field, DeclaredType declaredType) {
boolean toMany = dbToMany(field);
List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (typeArguments.size() == 1) {
Element argElement = typeUtils.asElement(typeArguments.get(0));
if (isEntityOrEmbedded(argElement)) {
boolean embeddable = isEmbeddable(argElement);
return createPropertyTypeAssoc(embeddable, toMany, typeDef(argElement.asType()));
}
} else if (typeArguments.size() == 2) {
Element argElement = typeUtils.asElement(typeArguments.get(1));
if (isEntityOrEmbedded(argElement)) {
boolean embeddable = isEmbeddable(argElement);
return createPropertyTypeAssoc(embeddable, toMany, typeDef(argElement.asType()));
}
}
return null;
}
private String readTargetEntity(Element declaredType) {
for (AnnotationMirror annotation : declaredType.getAnnotationMirrors()) {
final Object targetEntity = readTargetEntityFromAnnotation(annotation);
@@ -386,11 +404,20 @@ class ProcessingContext implements Constants {
/**
* Create the QAssoc PropertyType.
*/
private PropertyType createPropertyTypeAssoc(String fullName) {
String[] split = Split.split(fullName);
String propertyName = "QAssoc" + split[1];
String packageName = packageAppend(split[0]);
return new PropertyTypeAssoc(propertyName, packageName);
private PropertyType createPropertyTypeAssoc(boolean embeddable, boolean toMany, String fullName) {
TypeElement typeElement = elementUtils.getTypeElement(fullName);
String type;
if (typeElement.getNestingKind().isNested()) {
type = typeElement.getEnclosingElement().toString() + "$" + typeElement.getSimpleName();
} else {
type = typeElement.getQualifiedName().toString();
}
String suffix = toMany ? "Many" : embeddable ? "": "One";
String[] split = Split.split(type);
String propertyName = "Q" + split[1] + ".Assoc" + suffix;
String importName = split[0] + ".query.Q" + split[1];
return new PropertyTypeAssoc(propertyName, importName);
}
/**
@@ -109,8 +109,7 @@ public class Processor extends AbstractProcessor implements Constants {
private void generateQueryBeans(Element element) {
try {
SimpleQueryBeanWriter beanWriter = new SimpleQueryBeanWriter((TypeElement) element, processingContext);
beanWriter.writeRootBean();
beanWriter.writeAssocBean();
beanWriter.writeBean();
} catch (Throwable e) {
processingContext.logError(element, "Error generating query beans: " + e);
}
@@ -7,25 +7,16 @@ import java.util.Set;
*/
class PropertyTypeAssoc extends PropertyType {
/**
* The package name for this associated query bean.
*/
private final String assocPackage;
private final String importName;
/**
* Construct given the associated bean type name and package.
*
* @param qAssocTypeName the associated bean type name.
* @param assocPackage the associated bean package.
*/
PropertyTypeAssoc(String qAssocTypeName, String assocPackage) {
PropertyTypeAssoc(String qAssocTypeName, String importName) {
super(qAssocTypeName);
this.assocPackage = assocPackage;
this.importName = importName;
}
@Override
void addImports(Set<String> allImports) {
allImports.add(assocPackage + "." + propertyType);
allImports.add(importName);
}
}
@@ -12,7 +12,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
@@ -74,19 +73,17 @@ class SimpleQueryBeanWriter {
private final boolean embeddable;
private final String dbName;
private final String beanFullName;
private final LangAdapter langAdapter;
private boolean writingAssocBean;
private final KotlinLangAdapter langAdapter = new KotlinLangAdapter();
private boolean writingEmbeddedBean;
private final String generatedSourcesDir;
private String destPackage;
private String origDestPackage;
private String shortName;
private final String shortInnerName;
private final String origShortName;
private Append writer;
SimpleQueryBeanWriter(TypeElement element, ProcessingContext processingContext) {
this.langAdapter = new KotlinLangAdapter();
this.generatedSourcesDir = processingContext.generatedSourcesDir();
this.element = element;
this.processingContext = processingContext;
@@ -95,7 +92,7 @@ class SimpleQueryBeanWriter {
this.destPackage = Util.packageOf(nested, beanFullName) + ".query";
String sn = Util.shortName(nested, beanFullName);
this.shortInnerName = Util.shortName(false, sn);
this.shortName = sn.replace(".", "");
this.shortName = sn.replace(".", "_"); // $ not supported with Kotlin, see kotlinInnerType()
this.origShortName = shortName;
this.isEntity = processingContext.isEntity(element);
this.embeddable = processingContext.isEmbeddable(element);
@@ -118,8 +115,8 @@ class SimpleQueryBeanWriter {
return processingContext.findDbName(element);
}
private LangAdapter lang() {
return langAdapter;
private static String kotlinInnerType(String fullType) {
return fullType.replace('$', '_');
}
private void gatherPropertyDetails() {
@@ -148,25 +145,24 @@ class SimpleQueryBeanWriter {
}
/**
* Write the type query bean (root bean).
* Write the type query bean.
*/
void writeRootBean() throws IOException {
void writeBean() throws IOException {
gatherPropertyDetails();
translateKotlinImportTypes();
if (isEmbeddable()) {
processingContext.addEntity(beanFullName, dbName);
writeEmbeddedBean();
} else if (isEntity()) {
processingContext.addEntity(beanFullName, dbName);
writer = new Append(createFileWriter());
translateKotlinImportTypes();
writePackage();
writeImports();
writeClass();
writeAlias();
writeFields();
writeFields(false);
writeConstructors();
//writeStaticAliasClass();
writeClassEnd();
writer.close();
@@ -196,139 +192,53 @@ class SimpleQueryBeanWriter {
/**
* Write the type query assoc bean.
*/
void writeAssocBean() throws IOException {
writingAssocBean = true;
origDestPackage = destPackage;
destPackage = destPackage + ".assoc";
shortName = "Assoc" + shortName;
void writeEmbeddedBean() throws IOException {
writingEmbeddedBean = true;
prepareAssocBeanImports();
writer = new Append(createFileWriter());
writePackage();
writeImports();
writeClass();
writeFields();
writeConstructors();
writeEmbeddedAssoc();
writeClassEnd();
writer.close();
}
/**
* Prepare the imports for writing assoc bean.
*/
private void prepareAssocBeanImports() {
if (embeddable) {
importTypes.add(Constants.TQASSOC);
} else {
importTypes.add(Constants.TQASSOCBEAN);
}
if (isEntity()) {
importTypes.add(Constants.TQPROPERTY);
importTypes.add(origDestPackage + ".Q" + origShortName);
//if (implementsInterface != null) {
// importTypes.add(Constants.AVAJE_LANG_NULLABLE);
// importTypes.add(Constants.JAVA_COLLECTION);
// importTypes.add(implementsInterfaceFullName);
//}
}
// remove imports for the same package
Iterator<String> importsIterator = importTypes.iterator();
String checkImportStart = destPackage + ".QAssoc";
while (importsIterator.hasNext()) {
String importType = importsIterator.next();
if (importType.startsWith(checkImportStart)) {
importsIterator.remove();
}
}
}
/**
* Write constructors.
*/
private void writeConstructors() {
if (writingAssocBean) {
writeAssocBeanFetch();
writeAssocBeanConstructor();
} else {
writeRootBeanConstructor();
}
langAdapter.rootBeanConstructor(writer, shortName, dbName, beanFullName);
writeAssocClasses();
}
/**
* Write the constructors for 'root' type query bean.
*/
private void writeRootBeanConstructor() {
lang().rootBeanConstructor(writer, shortName, dbName, beanFullName);
}
private void writeAssocBeanFetch() {
if (isEntity()) {
//if (implementsInterface != null) {
// writeAssocBeanExpression(false, "eq", "Is equal to by ID property.");
// writeAssocBeanExpression(true, "eqIfPresent", "Is equal to by ID property if the value is not null, if null no expression is added.");
// writeAssocBeanExpression(false, "in", "IN the given values.", implementsInterfaceShortName + "...", "in");
// writeAssocBeanExpression(false, "inBy", "IN the given interface values.", "Collection<" + implementsInterfaceShortName + ">", "in");
// writeAssocBeanExpression(true, "inOrEmptyBy", "IN the given interface values if the collection is not empty. No expression is added if the collection is empty..", "Collection<" + implementsInterfaceShortName + ">", "inOrEmpty");
//}
}
}
private void writeAssocBeanExpression(boolean nullable,String expression, String comment) {
writeAssocBeanExpression(nullable, expression, comment, implementsInterfaceShortName, expression);
}
private void writeAssocBeanExpression(boolean nullable, String expression, String comment, String param, String actualExpression) {
final String nullableAnnotation = nullable ? "@Nullable " : "";
String values = expression.startsWith("in") ? "values" : "value";
writer.append(" /**").eol();
writer.append(" * ").append(comment).eol();
writer.append(" */").eol();
writer.append(" fun %s(%s%s %s): R {", expression, nullableAnnotation, param, values).eol();
writer.append(" expr().%s(_name, %s);", actualExpression, values).eol();
writer.append(" return _root;").eol();
writer.append(" }").eol();
writer.eol();
}
/**
* Write constructor for 'assoc' type query bean.
*/
private void writeAssocBeanConstructor() {
lang().assocBeanConstructor(writer, shortName);
}
/**
* Write all the fields.
*/
private void writeFields() {
private void writeFields(boolean assocBeans) {
String padding = assocBeans ? " " : "";
for (PropertyMeta property : properties) {
String typeDefn = property.getTypeDefn(shortName, writingAssocBean);
lang().fieldDefn(writer, property.getName(), typeDefn);
writer.eol();
String typeDefn = kotlinTypeDefn(property.getTypeDefn(shortName, assocBeans));
writer.append("%s lateinit var %s: %s", padding, property.getName(), kotlinInnerType(typeDefn)).eol();
}
writer.eol();
}
private static String kotlinTypeDefn(String type) {
if (type.endsWith(",Integer>")) {
return type.replace(",Integer>", ",Int>");
} else {
return type;
}
}
/**
* Write the class definition.
*/
private void writeClass() {
if (writingAssocBean) {
if (writingEmbeddedBean) {
writer.append("/**").eol();
writer.append(" * Association query bean for %s.", shortName).eol();
writer.append(" * ").eol();
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();
if (embeddable) {
writer.append("class Q%s<R> : TQAssoc<%s,R> {", shortName, beanFullName).eol();
} else {
writer.append("class Q%s<R> : TQAssocBean<%s,R,Q%s> {", shortName, beanFullName, origShortName).eol();
}
writer.append("class Q%s {", shortName).eol();
} else {
writer.append("/**").eol();
writer.append(" * Query bean for %s.", shortName).eol();
@@ -344,9 +254,7 @@ class SimpleQueryBeanWriter {
}
private void writeAlias() {
if (!writingAssocBean) {
lang().alias(writer, shortName, beanFullName);
}
langAdapter.alias(writer, shortName, beanFullName);
}
private void writeClassEnd() {
@@ -358,7 +266,7 @@ class SimpleQueryBeanWriter {
*/
private void writeImports() {
for (String importType : importTypes) {
writer.append("import %s;", importType).eol();
writer.append("import %s;", kotlinInnerType(importType)).eol();
}
writer.eol();
}
@@ -379,4 +287,60 @@ class SimpleQueryBeanWriter {
return new FileWriter(absFile);
}
private void writeEmbeddedAssoc() {
writer.append(" @io.ebean.typequery.Generated(\"io.ebean.querybean.generator\") @io.ebean.typequery.TypeQueryBean(\"v1\")").eol();
writer.append(" class Assoc<R> : io.ebean.typequery.TQAssoc<%s,R> {", beanFullName).eol().eol();
writeFields(true);
writer.append(" protected constructor(name: String, root: R) : super(name, root)").eol();
writer.append(" protected constructor(name: String, root: R, prefix: String) : super(name, root, prefix)").eol();
writer.append(" }").eol().eol();
}
private void writeAssocClasses() {
writer.append(" @io.ebean.typequery.Generated(\"io.ebean.querybean.generator\") @io.ebean.typequery.TypeQueryBean(\"v1\")").eol();
writer.append(" abstract class Assoc<R> : io.ebean.typequery.TQAssocBean<%s, R, Q%s> {", beanFullName, shortName).eol();
writeFields(true);
writer.append(" protected constructor(name: String, root: R) : super(name, root)").eol();
writer.append(" protected constructor(name: String, root: R, prefix: String) : super(name, root, prefix)").eol();
writer.append(" }").eol().eol();
writer.append(" @io.ebean.typequery.Generated(\"io.ebean.querybean.generator\") @io.ebean.typequery.TypeQueryBean(\"v1\")").eol();
writer.append(" class AssocOne<R> : Assoc<R> {").eol();
writer.append(" constructor(name: String, root: R) : super(name, root)").eol();
writer.append(" constructor(name: String, root: R, prefix: String) : super(name, root, prefix)").eol();
writer.append(" }").eol().eol();
writer.append(" @io.ebean.typequery.Generated(\"io.ebean.querybean.generator\") @io.ebean.typequery.TypeQueryBean(\"v1\")").eol();
writer.append(" class AssocMany<R> : Assoc<R>, io.ebean.typequery.TQAssocMany<%s, R, Q%s> {", beanFullName, shortName).eol();
writer.append(" constructor(name: String, root: R) : super(name, root)").eol();
writer.append(" constructor(name: String, root: R, prefix: String) : super(name, root, prefix)").eol();
writer.eol();
writer.append(" override fun filterMany(apply: java.util.function.Consumer<Q%s>): R {", shortName).eol();
writer.append(" val list: io.ebean.ExpressionList<%s> = _newExpressionList<%s>()", beanFullName, beanFullName).eol();
writer.append(" apply.accept(Q%s(list))", shortName).eol();
writer.append(" return _filterMany(list)").eol();
writer.append(" }").eol().eol();
writer.append(" override fun filterMany(filter: io.ebean.ExpressionList<%s>): R {", beanFullName).eol();
writer.append(" return _filterMany(filter)").eol();
writer.append(" }").eol().eol();
writer.append(" override fun filterManyRaw(rawExpressions: String, vararg params: Any): R {").eol();
writer.append(" return _filterManyRaw(rawExpressions, *params)").eol();
writer.append(" }").eol().eol();
// Ebean 14.x only
writer.append(" @Deprecated(\"for removal, migrate to filterManyRaw()\")").eol();
writer.append(" override fun filterMany(rawExpressions: String, vararg params: Any): R {").eol();
writer.append(" return _filterMany(rawExpressions, *params)").eol();
writer.append(" }").eol().eol();
writer.append(" override fun isEmpty(): R {").eol();
writer.append(" return _isEmpty() ").eol();
writer.append(" }").eol().eol();
writer.append(" override fun isNotEmpty(): R {").eol();
writer.append(" return _isNotEmpty() ").eol();
writer.append(" }").eol().eol();
writer.append(" }").eol();
}
}
+1 -1
View File
@@ -92,7 +92,7 @@
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<!-- <artifactId>querybean-generator</artifactId>-->
<version>14.8.0</version>
<version>14.8.1</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
@@ -0,0 +1,17 @@
package org.example.domain
import jakarta.persistence.*
@Entity
@Table(name = "t_inner2")
class MyKInnerEmb {
@Id
var one: Long = 0
var two: String = "0"
var address: EmbAddre? = null
@Embeddable
data class EmbAddre(val line1: String, val line2: String)
}