@Transactional annotation (if
+ * {@link #generateSpringAnnotations()} is set).
+ */
+ boolean generateSpringDao();
+
+ /**
+ * Whether a Spring specific {@link DAOImpl} subclass should be generated,
+ * which may contain Spring specific stuff, such as the
+ * @Transactional annotation (if
+ * {@link #generateSpringAnnotations()} is set).
+ */
+ void setGenerateSpringDao(boolean generateSpringDao);
+
/**
* Whether kotlin mutable properties should be annotated with
* set:JvmName as a workaround for problems occurring when
diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java
index 7c8418f0dc..21498e0c0c 100644
--- a/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java
+++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java
@@ -87,6 +87,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -129,6 +130,7 @@ import org.jooq.TableOptions;
import org.jooq.UDT;
import org.jooq.UDTField;
import org.jooq.UniqueKey;
+import org.jooq.UpdatableRecord;
import org.jooq.codegen.GeneratorStrategy.Mode;
import org.jooq.codegen.GeneratorWriter.CloseResult;
import org.jooq.exception.SQLDialectNotSupportedException;
@@ -571,6 +573,9 @@ public class JavaGenerator extends AbstractGenerator {
generateCatalog(catalog);
+ if (generateSpringDao() && catalog.getSchemata().stream().anyMatch(s -> !s.getTables().isEmpty()))
+ generateSpringDao(catalog);
+
log.info("Generating schemata", "Total: " + catalog.getSchemata().size());
for (SchemaDefinition schema : catalog.getSchemata()) {
try {
@@ -4150,6 +4155,280 @@ public class JavaGenerator extends AbstractGenerator {
watch.splitInfo("Table DAOs generated");
}
+ protected void generateSpringDao(CatalogDefinition catalog) {
+ // [#10756] Optionally, this class could be implemented in a new jooq-spring-extensions module
+ JavaWriter out = newJavaWriter(new File(getStrategy().getFile(catalog).getParentFile(), "AbstractSpringDAOImpl.java"));
+ log.info("Generating AbstractSpringDAOImpl", out.file().getName());
+ generateSpringDao(catalog, out);
+ closeJavaWriter(out);
+ }
+
+ protected void generateSpringDao(CatalogDefinition catalog, JavaWriter out) {
+ printPackage(out, catalog);
+
+ printClassJavadoc(out, "Spring specific {@" + out.ref(DAOImpl.class) + "} override.");
+ printClassAnnotations(out, catalog, Mode.DEFAULT);
+
+ String transactional = generateSpringAnnotations()
+ ? out.ref("org.springframework.transaction.annotation.Transactional")
+ : null;
+ String className = "AbstractSpringDAOImpl";
+
+ if (scala) {
+ if (generateSpringAnnotations())
+ out.println("@%s(readOnly = true)", transactional);
+
+ out.println("%sabstract class %s[R <: %s[R], P, T](table: %s[R], klass: java.lang.Class[P], configuration: %s) extends %s[R, P, T](table, klass, configuration) {",
+ visibility(), className, UpdatableRecord.class, Table.class, Configuration.class, DAOImpl.class);
+
+ out.println();
+ out.println("%sdef this(table: %s[R], klass: java.lang.Class[P]) = this(table, klass, null)", visibility(), Table.class);
+ }
+ else if (kotlin) {
+ if (generateSpringAnnotations())
+ out.println("@%s(readOnly = true)", transactional);
+
+ out.println("%sabstract class %s, configuration: %s?) : %s ) : this(table, type, null)", visibility(), Table.class, Class.class);
+ }
+ else {
+ if (generateSpringAnnotations())
+ out.println("@%s(readOnly = true)", transactional);
+
+ out.println("%sabstract class %s type) {", className, Table.class, Class.class);
+ out.println("super(table, type);");
+ out.println("}");
+ out.println();
+ out.println("protected %s(%s type, %s configuration) {", className, Table.class, Class.class, Configuration.class);
+ out.println("super(table, type, configuration);");
+ out.println("}");
+ }
+
+ Consumer = super.fetch(field, values)", Field.class, out.ref("kotlin.collections.Collection"), out.ref("kotlin.collections.List"));
+ }
+ else {
+ out.override();
+ out.println("public fetch(%s = super.fetch(field, *values)", Field.class, out.ref("kotlin.collections.List"));
+ }
+ else {
+ out.override();
+ out.println("public fetch(%s = super.fetchOptional(field, value)", Field.class, Optional.class);
+ }
+ else {
+ out.override();
+ out.println("public fetchOptional(%s = super.fetchRange(field, lowerInclusive, upperInclusive)", Field.class, out.ref("kotlin.collections.List"));
+ }
+ else {
+ out.override();
+ out.println("public fetchRange(%s = super.findAll()", out.ref("kotlin.collections.List"));
+ }
+ else {
+ out.override();
+ out.println("public %s findAll() {", List.class);
+ out.println("return super.findAll();");
+ out.println("}");
+ }
+
+ printTransactionalHeader.accept(true);
+ if (scala) {
+ out.println("override def findById(id: T): P = super.findById(id)");
+ }
+ else if (kotlin) {
+ out.println("public override fun findById(id: T): P? = super.findById(id)");
+ }
+ else {
+ out.override();
+ out.println("public P findById(T id) {");
+ out.println("return super.findById(id);");
+ out.println("}");
+ }
+
+ printTransactionalHeader.accept(true);
+ if (scala) {
+ out.println("override def findOptionalById(id: T): %s[P] = super.findOptionalById(id)", Optional.class);
+ }
+ else if (kotlin) {
+ out.println("public override fun findOptionalById(id: T): %s = super.findOptionalById(id)", Optional.class);
+ }
+ else {
+ out.override();
+ out.println("public %s findOptionalById(T id) {", Optional.class);
+ out.println("return super.findOptionalById(id);");
+ out.println("}");
+ }
+
+ for (String name : asList("insert", "update", "merge", "delete", "deleteById")) {
+ String argType = name.endsWith("ById") ? "T" : "P";
+ String argName = name.endsWith("ById") ? "id" : "obj";
+
+ printTransactionalHeader.accept(false);
+ if (scala) {
+ out.println("override def %s(%s: %s): Unit = super.%s(%s)", name, argName, argType, name, argName);
+ }
+ else if (kotlin) {
+ out.println("public override fun %s(%s: %s): Unit = super.%s(%s)", name, argName, argType, name, argName);
+ }
+ else {
+ out.override();
+ out.println("public void %s(%s<%s> %ss) {", name, Collection.class, argType, argName);
+ out.println("super.%s(%ss);", name, argName);
+ out.println("}");
+ }
+
+ printTransactionalHeader.accept(false);
+ if (scala) {
+ out.println("override def %s(%ss: %s*): Unit = super.%s(%ss:_*)", name, argName, argType, name, argName);
+ }
+ else if (kotlin) {
+ out.println("public override fun %s(vararg %ss: %s): Unit = super.%s(*%ss)", name, argName, argType, name, argName);
+ }
+ else {
+ out.override();
+ out.println("public void %s(%s %s) {", name, argType, argName);
+ out.println("super.%s(%s);", name, argName);
+ out.println("}");
+ }
+
+ printTransactionalHeader.accept(false);
+ if (scala) {
+ out.println("override def %s(%ss: %s[%s]): Unit = super.%s(%ss)", name, argName, Collection.class, argType, name, argName);
+ }
+ else if (kotlin) {
+ out.println("public override fun %s(%ss: %s<%s>): Unit = super.%s(%ss)", name, argName, out.ref("kotlin.collections.Collection"), argType, name, argName);
+ }
+ else {
+ out.override();
+ out.println("public void %s(%s... %ss) {", name, argType, argName);
+ out.println("super.%s(%ss);", name, argName);
+ out.println("}");
+ }
+ }
+
+ generateSpringDaoClassFooter(catalog, out);
+ out.println("}");
+ }
+
+ /**
+ * Subclasses may override this method to provide table references class footer code.
+ */
+ @SuppressWarnings("unused")
+ protected void generateSpringDaoClassFooter(CatalogDefinition catalog, JavaWriter out) {}
+
protected void generateDao(TableDefinition table) {
JavaWriter out = newJavaWriter(getFile(table, Mode.DAO));
log.info("Generating DAO", out.file().getName());
@@ -4167,7 +4446,9 @@ public class JavaGenerator extends AbstractGenerator {
final String className = getStrategy().getJavaClassName(table, Mode.DAO);
final ListsetX() setters instead of setIsX() in byte code for mutable properties called isX.
*
@@ -2756,6 +2782,11 @@ public class Generate implements Serializable, XMLAppendable
return this;
}
+ public Generate withSpringDao(Boolean value) {
+ setSpringDao(value);
+ return this;
+ }
+
public Generate withKotlinSetterJvmNameAnnotationsOnIsPrefix(Boolean value) {
setKotlinSetterJvmNameAnnotationsOnIsPrefix(value);
return this;
@@ -3070,6 +3101,7 @@ public class Generate implements Serializable, XMLAppendable
builder.append("jpaVersion", jpaVersion);
builder.append("validationAnnotations", validationAnnotations);
builder.append("springAnnotations", springAnnotations);
+ builder.append("springDao", springDao);
builder.append("kotlinSetterJvmNameAnnotationsOnIsPrefix", kotlinSetterJvmNameAnnotationsOnIsPrefix);
builder.append("globalObjectReferences", globalObjectReferences);
builder.append("globalCatalogReferences", globalCatalogReferences);
@@ -3579,6 +3611,15 @@ public class Generate implements Serializable, XMLAppendable
return false;
}
}
+ if (springDao == null) {
+ if (other.springDao!= null) {
+ return false;
+ }
+ } else {
+ if (!springDao.equals(other.springDao)) {
+ return false;
+ }
+ }
if (kotlinSetterJvmNameAnnotationsOnIsPrefix == null) {
if (other.kotlinSetterJvmNameAnnotationsOnIsPrefix!= null) {
return false;
@@ -4058,6 +4099,7 @@ public class Generate implements Serializable, XMLAppendable
result = ((prime*result)+((jpaVersion == null)? 0 :jpaVersion.hashCode()));
result = ((prime*result)+((validationAnnotations == null)? 0 :validationAnnotations.hashCode()));
result = ((prime*result)+((springAnnotations == null)? 0 :springAnnotations.hashCode()));
+ result = ((prime*result)+((springDao == null)? 0 :springDao.hashCode()));
result = ((prime*result)+((kotlinSetterJvmNameAnnotationsOnIsPrefix == null)? 0 :kotlinSetterJvmNameAnnotationsOnIsPrefix.hashCode()));
result = ((prime*result)+((globalObjectReferences == null)? 0 :globalObjectReferences.hashCode()));
result = ((prime*result)+((globalCatalogReferences == null)? 0 :globalCatalogReferences.hashCode()));
diff --git a/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.17.0.xsd b/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.17.0.xsd
index f5601c517a..62f981161f 100644
--- a/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.17.0.xsd
+++ b/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.17.0.xsd
@@ -1793,6 +1793,10 @@ jOOQ version used for source code.]]>setIsX() in byte code for mutable properties called isX.]]>