Skip to content

Commit

Permalink
Merge pull request #3554 from ebean-orm/feature/3536-kotlin-querybean…
Browse files Browse the repository at this point in the history
…-generator

#3536 kotlin-querybean-generator update for filterMany() changes
  • Loading branch information
rbygrave authored Feb 9, 2025
2 parents 2d48dd2 + b066f9c commit 11632c3
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 247 deletions.
55 changes: 55 additions & 0 deletions ebean-querybean/src/test/java/org/example/domain/MyInnerEmb.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.example.domain;

import jakarta.persistence.Embeddable;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class MyInnerEmb {

@Embeddable
public static class EmbAddr {
final long streetNum;
final String line1;

public EmbAddr(long streetNum, String line1) {
this.streetNum = streetNum;
this.line1 = line1;
}
}

@Id
long id;
String one;

@Embedded
EmbAddr address;

public long id() {
return id;
}

public MyInnerEmb id(long id) {
this.id = id;
return this;
}

public String one() {
return one;
}

public MyInnerEmb one(String beanOne) {
this.one = beanOne;
return this;
}

public EmbAddr address() {
return address;
}

public MyInnerEmb setAddress(EmbAddr address) {
this.address = address;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,15 @@ 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";
String DBJSON = "io.ebean.annotation.DbJson";
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";
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -20,87 +19,38 @@ public void alias(Append writer, String shortName, String fullName) {
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();
}

@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);
writer.append(" }").eol().eol();
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ boolean isEmbeddable(Element element) {
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.
*/
Expand All @@ -261,6 +265,7 @@ private static boolean dbArrayField(Element field) {
}

PropertyType getPropertyType(VariableElement field) {
boolean toMany = dbToMany(field);
if (dbJsonField(field)) {
return propertyTypeMap.getDbJsonType();
}
Expand Down Expand Up @@ -301,36 +306,30 @@ PropertyType getPropertyType(VariableElement field) {
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()));
}
}
}

Expand All @@ -357,6 +356,25 @@ private boolean typeInstanceOf(final TypeMirror typeMirror, final CharSequence d
.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);
Expand Down Expand Up @@ -386,11 +404,20 @@ private String langShortType(String shortName) {
/**
* 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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ private void writeModuleInfoBean() {
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,16 @@
*/
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);
}

}
Loading

0 comments on commit 11632c3

Please sign in to comment.