mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-23 01:07:49 +00:00
Merge pull request #2986 from ebean-orm/feature/querybeans-assoc-supportInterfaceUse
[querybeans] Add support for using interface types with querybean expressions eq() in() etc WHEN entity beans implement an interface
This commit is contained in:
@@ -31,4 +31,7 @@ interface Constants {
|
||||
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";
|
||||
|
||||
String AVAJE_LANG_NULLABLE = "io.avaje.lang.Nullable";
|
||||
String JAVA_COLLECTION = "java.util.Collection";
|
||||
}
|
||||
|
||||
+1
-1
@@ -334,7 +334,7 @@ class ProcessingContext implements Constants {
|
||||
}
|
||||
}
|
||||
|
||||
private Element asElement(TypeMirror argType) {
|
||||
Element asElement(TypeMirror argType) {
|
||||
if (argType.getKind() == TypeKind.WILDCARD) {
|
||||
argType = ((WildcardType) argType).getExtendsBound();
|
||||
}
|
||||
|
||||
+50
@@ -3,6 +3,7 @@ package io.ebean.querybean.generator;
|
||||
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
@@ -65,6 +66,9 @@ class SimpleQueryBeanWriter {
|
||||
private final Set<String> importTypes = new TreeSet<>();
|
||||
private final List<PropertyMeta> properties = new ArrayList<>();
|
||||
private final TypeElement element;
|
||||
private final TypeElement implementsInterface;
|
||||
private String implementsInterfaceFullName;
|
||||
private String implementsInterfaceShortName;
|
||||
private final ProcessingContext processingContext;
|
||||
private final boolean isEntity;
|
||||
private final boolean embeddable;
|
||||
@@ -96,6 +100,18 @@ class SimpleQueryBeanWriter {
|
||||
this.isEntity = processingContext.isEntity(element);
|
||||
this.embeddable = processingContext.isEmbeddable(element);
|
||||
this.dbName = findDbName();
|
||||
this.implementsInterface = initInterface(element);
|
||||
}
|
||||
|
||||
private TypeElement initInterface(TypeElement element) {
|
||||
for (TypeMirror anInterface : element.getInterfaces()) {
|
||||
TypeElement e = (TypeElement)processingContext.asElement(anInterface);
|
||||
String name = e.getQualifiedName().toString();
|
||||
if (!name.startsWith("java") && !name.startsWith("io.ebean")) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String findDbName() {
|
||||
@@ -115,6 +131,11 @@ class SimpleQueryBeanWriter {
|
||||
importTypes.add(Constants.FETCHGROUP);
|
||||
importTypes.add(Constants.QUERY);
|
||||
importTypes.add(Constants.TRANSACTION);
|
||||
if (implementsInterface != null) {
|
||||
implementsInterfaceFullName = implementsInterface.getQualifiedName().toString();
|
||||
boolean nested = implementsInterface.getNestingKind().isNested();
|
||||
implementsInterfaceShortName = Util.shortName(nested, implementsInterfaceFullName);
|
||||
}
|
||||
if (dbName != null) {
|
||||
importTypes.add(Constants.DB);
|
||||
}
|
||||
@@ -219,6 +240,11 @@ class SimpleQueryBeanWriter {
|
||||
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
|
||||
@@ -255,9 +281,33 @@ class SimpleQueryBeanWriter {
|
||||
private void writeAssocBeanFetch() {
|
||||
if (isEntity()) {
|
||||
lang().fetch(writer, origShortName);
|
||||
//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.
|
||||
*/
|
||||
|
||||
@@ -33,4 +33,6 @@ interface Constants {
|
||||
String METAINF_MANIFEST = "META-INF/ebean-generated-info.mf";
|
||||
String METAINF_SERVICES_MODULELOADER = "META-INF/services/io.ebean.config.EntityClassRegister";
|
||||
|
||||
String AVAJE_LANG_NULLABLE = "io.avaje.lang.Nullable";
|
||||
String JAVA_COLLECTION = "java.util.Collection";
|
||||
}
|
||||
|
||||
@@ -541,4 +541,8 @@ class ProcessingContext implements Constants {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Element asElement(TypeMirror mirror) {
|
||||
return typeUtils.asElement(mirror);
|
||||
}
|
||||
}
|
||||
|
||||
+51
-1
@@ -3,6 +3,7 @@ package io.ebean.querybean.generator;
|
||||
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.tools.JavaFileObject;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
@@ -20,6 +21,9 @@ class SimpleQueryBeanWriter {
|
||||
private final Set<String> importTypes = new TreeSet<>();
|
||||
private final List<PropertyMeta> properties = new ArrayList<>();
|
||||
private final TypeElement element;
|
||||
private final TypeElement implementsInterface;
|
||||
private String implementsInterfaceFullName;
|
||||
private String implementsInterfaceShortName;
|
||||
private final ProcessingContext processingContext;
|
||||
private final String dbName;
|
||||
private final String beanFullName;
|
||||
@@ -47,6 +51,18 @@ class SimpleQueryBeanWriter {
|
||||
this.isEntity = processingContext.isEntity(element);
|
||||
this.embeddable = processingContext.isEmbeddable(element);
|
||||
this.dbName = findDbName();
|
||||
this.implementsInterface = initInterface(element);
|
||||
}
|
||||
|
||||
private TypeElement initInterface(TypeElement element) {
|
||||
for (TypeMirror anInterface : element.getInterfaces()) {
|
||||
TypeElement e = (TypeElement)processingContext.asElement(anInterface);
|
||||
String name = e.getQualifiedName().toString();
|
||||
if (!name.startsWith("java") && !name.startsWith("io.ebean")) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String findDbName() {
|
||||
@@ -70,7 +86,11 @@ class SimpleQueryBeanWriter {
|
||||
importTypes.add(Constants.FETCHGROUP);
|
||||
importTypes.add(Constants.QUERY);
|
||||
importTypes.add(Constants.TRANSACTION);
|
||||
|
||||
if (implementsInterface != null) {
|
||||
implementsInterfaceFullName = implementsInterface.getQualifiedName().toString();
|
||||
boolean nested = implementsInterface.getNestingKind().isNested();
|
||||
implementsInterfaceShortName = Util.shortName(nested, implementsInterfaceFullName);
|
||||
}
|
||||
if (dbName != null) {
|
||||
importTypes.add(Constants.DB);
|
||||
}
|
||||
@@ -154,6 +174,11 @@ class SimpleQueryBeanWriter {
|
||||
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
|
||||
@@ -267,9 +292,34 @@ class SimpleQueryBeanWriter {
|
||||
writeAssocBeanFetch("Query", "Eagerly fetch this association using a 'query join' loading the specified properties.");
|
||||
writeAssocBeanFetch("Cache", "Eagerly fetch this association using L2 cache.");
|
||||
writeAssocBeanFetch("Lazy", "Use lazy loading for this association loading the specified properties.");
|
||||
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<? extends " + 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<? extends " + 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";
|
||||
String castVarargs = expression.equals("in") ? "(Object[])" : "";
|
||||
writer.append(" /**").eol();
|
||||
writer.append(" * ").append(comment).eol();
|
||||
writer.append(" */").eol();
|
||||
writer.append(" public final R %s(%s%s %s) {", expression, nullableAnnotation, param, values).eol();
|
||||
writer.append(" expr().%s(_name, %s%s);", actualExpression, castVarargs, values).eol();
|
||||
writer.append(" return _root;").eol();
|
||||
writer.append(" }").eol();
|
||||
writer.eol();
|
||||
}
|
||||
|
||||
private void writeAssocBeanFetch(String fetchType, String comment) {
|
||||
writer.append(" /**").eol();
|
||||
writer.append(" * ").append(comment).eol();
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>13.13.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
@@ -81,6 +87,24 @@
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<!-- <execution>-->
|
||||
<!-- <id>test-kapt</id>-->
|
||||
<!-- <goals>-->
|
||||
<!-- <goal>test-kapt</goal>-->
|
||||
<!-- </goals>-->
|
||||
<!-- <configuration>-->
|
||||
<!-- <sourceDirs>-->
|
||||
<!-- <sourceDir>src/test/kotlin</sourceDir>-->
|
||||
<!-- </sourceDirs>-->
|
||||
<!-- <annotationProcessorPaths>-->
|
||||
<!-- <annotationProcessorPath>-->
|
||||
<!-- <groupId>io.ebean</groupId>-->
|
||||
<!-- <artifactId>kotlin-querybean-generator</artifactId>-->
|
||||
<!-- <version>13.13.2</version>-->
|
||||
<!-- </annotationProcessorPath>-->
|
||||
<!-- </annotationProcessorPaths>-->
|
||||
<!-- </configuration>-->
|
||||
<!-- </execution>-->
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.example.api
|
||||
|
||||
interface ICustomer {
|
||||
|
||||
}
|
||||
@@ -3,11 +3,12 @@ package org.example.order
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.Id
|
||||
import javax.persistence.Version
|
||||
import org.example.api.ICustomer
|
||||
|
||||
@Entity
|
||||
class Customer(
|
||||
name: String,
|
||||
) {
|
||||
) : ICustomer {
|
||||
@Id
|
||||
var id: Int = 0
|
||||
val name: String = name
|
||||
|
||||
Reference in New Issue
Block a user