diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/AbstractGeneratorStrategy.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/AbstractGeneratorStrategy.java index a3ab01f2c6..f6ba7d4d64 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/AbstractGeneratorStrategy.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/AbstractGeneratorStrategy.java @@ -129,6 +129,7 @@ public abstract class AbstractGeneratorStrategy implements GeneratorStrategy { switch (language) { case KOTLIN: case SCALA: + case SCALA_3: if (pkg.contains("`")) pkg = pkg.replaceAll("`([^`]+)`", "$1"); diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/GenerationUtil.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/GenerationUtil.java index 4b30f1b544..3b80a74d76 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/GenerationUtil.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/GenerationUtil.java @@ -39,12 +39,10 @@ package org.jooq.codegen; import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableSet; -import static org.jooq.codegen.Language.JAVA; -import static org.jooq.codegen.Language.KOTLIN; -import static org.jooq.codegen.Language.SCALA; import static org.jooq.codegen.GenerationUtil.ExpressionType.CONSTRUCTOR_REFERENCE; import static org.jooq.codegen.GenerationUtil.ExpressionType.EXPRESSION; -import static org.jooq.impl.DSL.name; +import static org.jooq.codegen.Language.JAVA; +import static org.jooq.codegen.Language.KOTLIN; import java.util.HashSet; import java.util.Set; @@ -53,12 +51,8 @@ import java.util.regex.Pattern; import org.jooq.Name; import org.jooq.SQLDialect; -import org.jooq.exception.SQLDialectNotSupportedException; import org.jooq.meta.DataTypeDefinition; -import org.jooq.meta.Database; import org.jooq.meta.DefaultDataTypeDefinition; -import org.jooq.meta.SchemaDefinition; -import org.jooq.util.h2.H2DataType; /** * @author Lukas Eder @@ -112,6 +106,9 @@ class GenerationUtil { "protected", "public", "return", + // [#12180] Sealed isn't a keyword in most Java contexts, but the scalac 3 compiler doesn't + // seem to implement this correctly + "sealed", "short", "static", "strictfp", @@ -423,7 +420,7 @@ class GenerationUtil { private static String convertToIdentifier0(String literal, Language language) { if (language == JAVA && JAVA_KEYWORDS.contains(literal)) return literal + "_"; - if (language == SCALA && SCALA_KEYWORDS.contains(literal)) + if (language.isScala() && SCALA_KEYWORDS.contains(literal)) return "`" + literal + "`"; if (language == KOTLIN && KOTLIN_KEYWORDS.contains(literal)) return "`" + literal + "`"; @@ -431,7 +428,7 @@ class GenerationUtil { StringBuilder sb = new StringBuilder(); if ("".equals(literal)) - if (language == SCALA) + if (language.isScala()) return "`_`"; else if (language == KOTLIN) return "`_`"; @@ -442,13 +439,13 @@ class GenerationUtil { char c = literal.charAt(i); // [#5424] Scala setters, by convention, end in "property_=", where "=" is an operator and "_" precedes it - if (language == SCALA && i == literal.length() - 1 && literal.length() >= 2 && literal.charAt(i - 1) == '_' && isScalaOperator(c)) + if (language.isScala() && i == literal.length() - 1 && literal.length() >= 2 && literal.charAt(i - 1) == '_' && isScalaOperator(c)) sb.append(c); - else if (language == SCALA && !isScalaIdentifierPart(c)) + else if (language.isScala() && !isScalaIdentifierPart(c)) sb.append(escape(c)); else if (language == JAVA && !Character.isJavaIdentifierPart(c)) sb.append(escape(c)); - else if (language == SCALA && i == 0 && !isScalaIdentifierStart(c)) + else if (language.isScala() && i == 0 && !isScalaIdentifierStart(c)) sb.append("_").append(c); else if (language == JAVA && i == 0 && !Character.isJavaIdentifierStart(c)) sb.append("_").append(c); diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/GeneratorStrategyWrapper.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/GeneratorStrategyWrapper.java index 8144c1a16f..3655bc2143 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/GeneratorStrategyWrapper.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/GeneratorStrategyWrapper.java @@ -265,7 +265,7 @@ class GeneratorStrategyWrapper extends AbstractDelegatingGeneratorStrategy { // [#5457] In Scala, we must not "override" any inherited members, even if they're private // or package private, and thus not visible - if (getTargetLanguage() == Language.SCALA) + if (getTargetLanguage().isScala()) for (Field f : clazz.getDeclaredFields()) result.add(f.getName()); } 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 183acaab45..8ab0bd9a55 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/JavaGenerator.java @@ -39,7 +39,6 @@ package org.jooq.codegen; import static java.util.Arrays.asList; -import static java.util.Collections.nCopies; import static java.util.Collections.singletonList; import static java.util.function.Function.identity; import static java.util.stream.Collectors.counting; @@ -59,7 +58,7 @@ import static org.jooq.codegen.GeneratorStrategy.Mode.POJO; import static org.jooq.codegen.GeneratorStrategy.Mode.RECORD; import static org.jooq.codegen.Language.JAVA; import static org.jooq.codegen.Language.KOTLIN; -import static org.jooq.codegen.Language.SCALA; +import static org.jooq.codegen.Language.SCALA_3; import static org.jooq.impl.DSL.name; import static org.jooq.impl.QOM.GenerationOption.STORED; import static org.jooq.impl.QOM.GenerationOption.VIRTUAL; @@ -85,7 +84,6 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -110,6 +108,7 @@ import org.jooq.Comment; import org.jooq.Condition; import org.jooq.Configuration; import org.jooq.Constants; +import org.jooq.Converter; import org.jooq.DSLContext; import org.jooq.DataType; import org.jooq.Domain; @@ -132,6 +131,7 @@ import org.jooq.PlainSQL; import org.jooq.Query; import org.jooq.QueryPart; import org.jooq.Record; +import org.jooq.Record2; import org.jooq.RecordQualifier; import org.jooq.Records; import org.jooq.Result; @@ -154,7 +154,6 @@ import org.jooq.TableOptions; // ... import org.jooq.UDT; import org.jooq.UDTField; -import org.jooq.UDTRecord; import org.jooq.UniqueKey; import org.jooq.UpdatableRecord; import org.jooq.codegen.GenerationUtil.BaseType; @@ -388,7 +387,7 @@ public class JavaGenerator extends AbstractGenerator { JavaGenerator(Language language) { super(language); - this.scalaConfigured = this.scala = (language == SCALA); + this.scalaConfigured = this.scala = (language.isScala()); this.kotlinConfigured = this.kotlin = (language == KOTLIN); this.tokenVoid = (scala || kotlin ? "Unit" : "void"); this.semicolon = (scala || kotlin ? "" : ";"); @@ -1318,12 +1317,13 @@ public class JavaGenerator extends AbstractGenerator { } if (scala) - out.print("%s.createIndex(%s.name(\"%s\"), %s, Array[%s [_] ](%s), %s)", + out.print("%s.createIndex(%s.name(\"%s\"), %s, Array[%s [%s] ](%s), %s)", Internal.class, DSL.class, escapeString(index.getOutputName()), out.ref(getStrategy().getFullJavaIdentifier(index.getTable()), 2), OrderField.class, + wildcard(), orderFields, index.isUnique() ); @@ -1450,7 +1450,7 @@ public class JavaGenerator extends AbstractGenerator { if (scala) - out.print("%s.createUniqueKey(%s, %s.name(\"%s\"), Array([[%s]]).asInstanceOf[Array[%s[%s, _] ] ], %s)", + out.print("%s.createUniqueKey(%s, %s.name(\"%s\"), Array([[%s]]).asInstanceOf[Array[%s[%s, %s] ] ], %s)", Internal.class, out.ref(getStrategy().getFullJavaIdentifier(uniqueKey.getTable()), 2), DSL.class, @@ -1458,6 +1458,7 @@ public class JavaGenerator extends AbstractGenerator { out.ref(getStrategy().getFullJavaIdentifiers(keyColumns), colRefSegments(null)), TableField.class, out.ref(getStrategy().getFullJavaClassName(uniqueKey.getTable(), Mode.RECORD)), + wildcard(), uniqueKey.enforced()); else if (kotlin) out.print("%s.createUniqueKey(%s, %s.name(\"%s\"), arrayOf([[%s]]), %s)", @@ -1550,7 +1551,7 @@ public class JavaGenerator extends AbstractGenerator { private void printCreateNonEmbeddableForeignKey(JavaWriter out, ForeignKeyDefinition foreignKey) { if (scala) - out.print("%s.createForeignKey(%s, %s.name(\"%s\"), Array([[%s]]).asInstanceOf[Array[%s[%s, _] ] ], %s, Array([[%s]]).asInstanceOf[Array[%s[%s, _] ] ], %s)", + out.print("%s.createForeignKey(%s, %s.name(\"%s\"), Array([[%s]]).asInstanceOf[Array[%s[%s, %s] ] ], %s, Array([[%s]]).asInstanceOf[Array[%s[%s, %s] ] ], %s)", Internal.class, out.ref(getStrategy().getFullJavaIdentifier(foreignKey.getKeyTable()), 2), DSL.class, @@ -1558,10 +1559,12 @@ public class JavaGenerator extends AbstractGenerator { out.ref(getStrategy().getFullJavaIdentifiers(foreignKey.getKeyColumns()), colRefSegments(null)), TableField.class, out.ref(getStrategy().getFullJavaClassName(foreignKey.getTable(), Mode.RECORD)), + wildcard(), out.ref(getStrategy().getFullJavaIdentifier(foreignKey.getReferencedKey()), 2), out.ref(getStrategy().getFullJavaIdentifiers(foreignKey.getReferencedColumns()), colRefSegments(null)), TableField.class, out.ref(getStrategy().getFullJavaClassName(foreignKey.getReferencedTable(), Mode.RECORD)), + wildcard(), foreignKey.enforced() ); else if (kotlin) @@ -2129,6 +2132,12 @@ public class JavaGenerator extends AbstractGenerator { out.println("return this;"); out.println("}"); } + + if (language == SCALA_3) { + out.println(); + out.println("override def `with`[T](field: %s[T], value: T): %s = super.`with`(field, value)", Field.class, className); + out.println("override def `with`[T, U](field: %s[T], value: U, converter: %s[? <: T, ? >: U]): %s = super.`with`(field, value, converter)", Field.class, Converter.class, className); + } } if (generateInterfaces()) @@ -2199,9 +2208,9 @@ public class JavaGenerator extends AbstractGenerator { printClassAnnotations(out, udt, Mode.RECORD_TYPE); if (scala) - out.println("%strait %s[R <: %s[R] ][[before= extends ][separator= with ][%s]] {", visibility(), className, interfaces); + out.println("%strait %s[[before= extends ][separator= with ][%s]] {", visibility(), className, interfaces); else if (kotlin) - out.println("%sinterface %s>[[before= : ][%s]] {", visibility(), className, interfaces); + out.println("%sinterface %s[[before= : ][%s]] {", visibility(), className, interfaces); else out.println("%sinterface %s[[before= extends ][%s]] {", visibility(), className, interfaces); @@ -3676,7 +3685,7 @@ public class JavaGenerator extends AbstractGenerator { out.println("klass: %s[T],", DataType.class); out.println("qualifier: %s[R],", RecordQualifier.class); out.println("comment: %s,", Comment.class); - out.println("binding: %s[_, T]", Binding.class); + out.println("binding: %s[%s, T]", Binding.class, wildcard()); out.println(")"); out.println("extends %s[R, %s, T](", classExtends, recordType); out.println("name, klass, qualifier, %s, comment, binding", udtId); @@ -4306,7 +4315,7 @@ public class JavaGenerator extends AbstractGenerator { try { if (!generateEnumsAsScalaSealedTraits()) { scala = false; - language = l == SCALA ? JAVA : l; + language = l.isScala() ? JAVA : l; getStrategy().setTargetLanguage(language); } @@ -5123,7 +5132,7 @@ public class JavaGenerator extends AbstractGenerator { printTransactionalHeader.accept(true); if (scala) { - out.println("override def fetch[Z](field: %s[Z], values: %s[_ <: Z]): %s[P] = super.fetch(field, values)", Field.class, Collection.class, List.class); + out.println("override def fetch[Z](field: %s[Z], values: %s[%s <: Z]): %s[P] = super.fetch(field, values)", Field.class, Collection.class, wildcard(), List.class); } else if (kotlin) { out.println("public override fun fetch(field: %s, values: %s): %s

= super.fetch(field, values)", Field.class, out.ref("kotlin.collections.Collection"), out.ref("kotlin.collections.List")); @@ -5137,7 +5146,7 @@ public class JavaGenerator extends AbstractGenerator { printTransactionalHeader.accept(true); if (scala) { - out.println("override def fetch[Z](field: %s[Z], values: Z*): %s[P] = super.fetch(field, values:_*)", Field.class, List.class); + out.println("override def fetch[Z](field: %s[Z], values: Z*): %s[P] = super.fetch(field, values%s)", Field.class, List.class, varargSplice()); } else if (kotlin) { out.println("public override fun fetch(field: %s, vararg values: Z): %s

= super.fetch(field, *values)", Field.class, out.ref("kotlin.collections.List")); @@ -5253,7 +5262,7 @@ public class JavaGenerator extends AbstractGenerator { printTransactionalHeader.accept(false); if (scala) { - out.println("override def %s(%ss: %s*): Unit = super.%s(%ss:_*)", name, argName, argType, name, argName); + out.println("override def %s(%ss: %s*): Unit = super.%s(%ss%s)", name, argName, argType, name, argName, varargSplice()); } else if (kotlin) { out.println("public override fun %s(vararg %ss: %s): Unit = super.%s(*%ss)", name, argName, argType, name, argName); @@ -5448,7 +5457,7 @@ public class JavaGenerator extends AbstractGenerator { String argName = name.endsWith("ById") ? "id" : "obj"; out.println("override def %s(%s: %s): Unit = super.%s(%s)", name, argName, argType, name, argName); - out.println("override def %s(%ss: %s*): Unit = super.%s(%ss:_*)", name, argName, argType, name, argName); + out.println("override def %s(%ss: %s*): Unit = super.%s(%ss%s)", name, argName, argType, name, argName, varargSplice()); out.println("override def %s(%ss: %s[%s]): Unit = super.%s(%ss)", name, argName, Collection.class, argType, name, argName); } } @@ -5525,11 +5534,11 @@ public class JavaGenerator extends AbstractGenerator { if (scala) { if (column instanceof EmbeddableDefinition) - out.println("%sdef fetchBy%s(values: %s*): %s[%s] = fetch(%s, values.map(v => new %s(v)).toArray:_*)", - visibility(), colMemberUC, colType, List.class, pType, colIdentifier, colTypeRecord); + out.println("%sdef fetchBy%s(values: %s*): %s[%s] = fetch(%s, values.map(v => new %s(v)).toArray%s)", + visibility(), colMemberUC, colType, List.class, pType, colIdentifier, colTypeRecord, varargSplice()); else - out.println("%sdef fetchBy%s(values: %s*): %s[%s] = fetch(%s, values:_*)", - visibility(), colMemberUC, colType, List.class, pType, colIdentifier); + out.println("%sdef fetchBy%s(values: %s*): %s[%s] = fetch(%s, values%s)", + visibility(), colMemberUC, colType, List.class, pType, colIdentifier, varargSplice()); } else if (kotlin) { String toTypedArray = PRIMITIVE_WRAPPERS.contains(colTypeFull) ? ".toTypedArray()" : ""; @@ -6658,8 +6667,8 @@ public class JavaGenerator extends AbstractGenerator { final String pathClassName = getStrategy().getJavaClassName(table, Mode.PATH); out.javadoc("A subtype implementing {@link %s} for simplified path-based joins.", Path.class); - out.println("%sclass %s(path: %s[_ <: %s], childPath: %s[_ <: %s, %s], parentPath: %s[_ <: %s, %s]) extends %s(path, childPath, parentPath) with %s[%s]", - visibility(), pathClassName, Table.class, Record.class, ForeignKey.class, Record.class, recordType, InverseForeignKey.class, Record.class, recordType, className, Path.class, recordType); + out.println("%sclass %s(path: %s[%s <: %s], childPath: %s[%s <: %s, %s], parentPath: %s[%s <: %s, %s]) extends %s(path, childPath, parentPath) with %s[%s]", + visibility(), pathClassName, Table.class, wildcard(), Record.class, ForeignKey.class, wildcard(), Record.class, recordType, InverseForeignKey.class, wildcard(), Record.class, recordType, className, Path.class, recordType); } out.println("}"); @@ -6672,11 +6681,11 @@ public class JavaGenerator extends AbstractGenerator { if (scala) { out.println("%sclass %s(", visibility(), className); out.println("alias: %s,", Name.class); - out.println("path: %s[_ <: %s],", Table.class, Record.class); - out.println("childPath: %s[_ <: %s, %s],", ForeignKey.class, Record.class, recordType); - out.println("parentPath: %s[_ <: %s, %s],", InverseForeignKey.class, Record.class, recordType); + out.println("path: %s[%s <: %s],", Table.class, wildcard(), Record.class); + out.println("childPath: %s[%s <: %s, %s],", ForeignKey.class, wildcard(), Record.class, recordType); + out.println("parentPath: %s[%s <: %s, %s],", InverseForeignKey.class, wildcard(), Record.class, recordType); out.println("aliased: %s[%s],", Table.class, recordType); - out.println("parameters: %s[ %s[_] ],", out.ref("scala.Array"), Field.class); + out.println("parameters: %s[ %s[%s] ],", out.ref("scala.Array"), Field.class, wildcard()); out.println("where: %s", Condition.class); out.println(")"); out.println("extends %s[%s](", classExtends, recordType); @@ -7020,8 +7029,8 @@ public class JavaGenerator extends AbstractGenerator { out.println(); if (scala) { - out.println("%sdef this(path: %s[_ <: %s], childPath: %s[_ <: %s, %s], parentPath: %s[_ <: %s, %s]) = this(%s.createPathAlias(path, childPath, parentPath), path, childPath, parentPath, %s, null, null)", - visibility(), Table.class, Record.class, ForeignKey.class, Record.class, recordType, InverseForeignKey.class, Record.class, recordType, Internal.class, tableId); + out.println("%sdef this(path: %s[%s <: %s], childPath: %s[%s <: %s, %s], parentPath: %s[%s <: %s, %s]) = this(%s.createPathAlias(path, childPath, parentPath), path, childPath, parentPath, %s, null, null)", + visibility(), Table.class, wildcard(), Record.class, ForeignKey.class, wildcard(), Record.class, recordType, InverseForeignKey.class, wildcard(), Record.class, recordType, Internal.class, tableId); } else if (kotlin) { out.println("%sconstructor(path: %s, childPath: %s?, parentPath: %s?): this(%s.createPathAlias(path, childPath, parentPath), path, childPath, parentPath, %s, null, null)", @@ -7340,8 +7349,8 @@ public class JavaGenerator extends AbstractGenerator { if (scala) { out.println(); - out.println("%soverride def getReferences: %s[ %s[%s, _] ] = %s.asList[ %s[%s, _] ]([[%s]])", - visibilityPublic(), List.class, ForeignKey.class, recordType, Arrays.class, ForeignKey.class, recordType, keyFullIds); + out.println("%soverride def getReferences: %s[ %s[%s, %s] ] = %s.asList[ %s[%s, %s] ]([[%s]])", + visibilityPublic(), List.class, ForeignKey.class, recordType, wildcard(), Arrays.class, ForeignKey.class, recordType, wildcard(), keyFullIds); } else if (kotlin) { out.println("%soverride fun getReferences(): %s<%s<%s, *>> = listOf([[%s]])", @@ -7704,7 +7713,7 @@ public class JavaGenerator extends AbstractGenerator { else out.println("new %s(alias, this)", className); - out.print("%soverride def as(alias: %s[_]): %s = ", visibilityPublic(), Table.class, className); + out.print("%soverride def as(alias: %s[%s]): %s = ", visibilityPublic(), Table.class, wildcard(), className); if (table.isTableValuedFunction()) out.println("new %s(alias.getQualifiedName(), null, null, null, this, parameters, null)", className); @@ -7793,7 +7802,7 @@ public class JavaGenerator extends AbstractGenerator { out.println("new %s(name, null)", className); out.javadoc("Rename this table"); - out.print("%soverride def rename(name: %s[_]): %s = ", visibilityPublic(), Table.class, className); + out.print("%soverride def rename(name: %s[%s]): %s = ", visibilityPublic(), Table.class, wildcard(), className); if (table.isTableValuedFunction()) out.println("new %s(name.getQualifiedName(), null, null, null, null, parameters, null)", className); @@ -7809,17 +7818,17 @@ public class JavaGenerator extends AbstractGenerator { // [#15760] super.aliased() is necessary in Scala 3 idt.accept(() -> out.println("%soverride def where(condition: %s): %s = new %s(getQualifiedName(), if (super.aliased()) this else null, condition)", visibilityPublic(), Condition.class, className, className)); - idt.accept(() -> out.println("%soverride def where(conditions: %s[_ <: %s]): %s = where(%s.and(conditions))", visibilityPublic(), Collection.class, Condition.class, className, DSL.class)); - idt.accept(() -> out.println("%soverride def where(conditions: %s*): %s = where(%s.and(conditions:_*))", visibilityPublic(), Condition.class, className, DSL.class)); + idt.accept(() -> out.println("%soverride def where(conditions: %s[%s <: %s]): %s = where(%s.and(conditions))", visibilityPublic(), Collection.class, wildcard(), Condition.class, className, DSL.class)); + idt.accept(() -> out.println("%soverride def where(conditions: %s*): %s = where(%s.and(conditions%s))", visibilityPublic(), Condition.class, className, DSL.class, varargSplice())); idt.accept(() -> out.println("%soverride def where(condition: %s[%s]): %s = where(%s.condition(condition))", visibilityPublic(), Field.class, Boolean.class, className, DSL.class)); idt.accept(() -> out.println("@%s %soverride def where(condition: %s): %s = where(%s.condition(condition))", PlainSQL.class, visibilityPublic(), SQL.class, className, DSL.class)); idt.accept(() -> out.println("@%s %soverride def where(@%s.SQL condition: %s): %s = where(%s.condition(condition))", PlainSQL.class, visibilityPublic(), Stringly.class, String.class, className, DSL.class)); - idt.accept(() -> out.println("@%s %soverride def where(@%s.SQL condition: %s, binds: AnyRef*): %s = where(%s.condition(condition, binds:_*))", PlainSQL.class, visibilityPublic(), Stringly.class, String.class, className, DSL.class)); + idt.accept(() -> out.println("@%s %soverride def where(@%s.SQL condition: %s, binds: AnyRef*): %s = where(%s.condition(condition, binds%s))", PlainSQL.class, visibilityPublic(), Stringly.class, String.class, className, DSL.class, varargSplice())); // This produces the same erasure as the previous, in scala: // (condition: String, binds: Seq) // idt.accept(() -> out.println("@%s %soverride def where(@%s.SQL condition: %s, parts: %s*): %s = where(%s.condition(condition, parts:_*))", PlainSQL.class, visibilityPublic(), Stringly.class, String.class, QueryPart.class, className, DSL.class)); - idt.accept(() -> out.println("%soverride def whereExists(select: %s[_]): %s = where(%s.exists(select))", visibilityPublic(), Select.class, className, DSL.class)); - idt.accept(() -> out.println("%soverride def whereNotExists(select: %s[_]): %s = where(%s.notExists(select))", visibilityPublic(), Select.class, className, DSL.class)); + idt.accept(() -> out.println("%soverride def whereExists(select: %s[%s]): %s = where(%s.exists(select))", visibilityPublic(), Select.class, wildcard(), className, DSL.class)); + idt.accept(() -> out.println("%soverride def whereNotExists(select: %s[%s]): %s = where(%s.notExists(select))", visibilityPublic(), Select.class, wildcard(), className, DSL.class)); } } @@ -8278,6 +8287,7 @@ public class JavaGenerator extends AbstractGenerator { case JAVA: case SCALA: + case SCALA_3: default: return "[[before=, ][new %s()]]"; } @@ -8301,6 +8311,7 @@ public class JavaGenerator extends AbstractGenerator { case JAVA: case SCALA: + case SCALA_3: default: return "[[before=.asConvertedDataType(][after=)][new %s()]]"; } @@ -9162,7 +9173,7 @@ public class JavaGenerator extends AbstractGenerator { if (out != null && !definitions.isEmpty()) { final String generic = type.getTypeParameters().length > 0 ? Stream.of(type.getTypeParameters()) - .map(x -> scala ? "_" : kotlin ? "*" : "?") + .map(x -> wildcard()) .collect(joining(", ", scala ? "[" : "<", scala ? "]" : ">")) : ""; final List references = new ArrayList<>(); @@ -10699,7 +10710,7 @@ public class JavaGenerator extends AbstractGenerator { protected String refExtendsNumberType(JavaWriter out, DataTypeDefinition type) { if (type.isGenericNumberType()) - return (scala ? "_ <: " : kotlin ? "out ": "? extends ") + out.ref(Number.class); + return (scala ? wildcard() + " <: " : kotlin ? "out ": "? extends ") + out.ref(Number.class); else return out.ref(getJavaType(type, out)); } @@ -10788,6 +10799,7 @@ public class JavaGenerator extends AbstractGenerator { switch (language) { case SCALA: + case SCALA_3: rawtype = type.replaceAll("\\[.*\\]", ""); break; @@ -10802,6 +10814,7 @@ public class JavaGenerator extends AbstractGenerator { switch (language) { case SCALA: + case SCALA_3: return "classOf[" + out.ref(type) + "]"; case KOTLIN: @@ -10821,6 +10834,7 @@ public class JavaGenerator extends AbstractGenerator { switch (language) { case SCALA: + case SCALA_3: return "new " + out.ref(rawtype) + typeParams.replace("<", "[").replace(">", "]"); case KOTLIN: @@ -10987,7 +11001,7 @@ public class JavaGenerator extends AbstractGenerator { } else if (udtMode == Mode.INTERFACE) { if (scala) - type = "java.util.List[_ <:" + getJavaType(db.getArray(schema, u).getElementType(resolver(out, udtMode)), out, udtMode) + "]"; + type = "java.util.List[" + wildcard() + " <:" + getJavaType(db.getArray(schema, u).getElementType(resolver(out, udtMode)), out, udtMode) + "]"; else type = "java.util.List"; } @@ -11063,20 +11077,32 @@ public class JavaGenerator extends AbstractGenerator { return type; } + private String varargSplice() { + switch (language) { + case SCALA: + return "_ :*"; + case SCALA_3: + default: + return "*"; + } + } + private String wildcard() { switch (language) { case KOTLIN: - return "<*>"; + return "*"; case SCALA: - return "[_]"; + return "_"; + case SCALA_3: default: - return ""; + return "?"; } } private String typeVariable(CharSequence variable) { switch (language) { case SCALA: + case SCALA_3: return "[" + variable + "]"; default: return "<" + variable + ">"; diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/Language.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/Language.java index 767a353cd8..122dcde3bd 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/Language.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/Language.java @@ -41,5 +41,41 @@ package org.jooq.codegen; * The language used by a {@link Generator}. */ public enum Language { - JAVA, SCALA, KOTLIN, XML + + /** + * The Java language + */ + JAVA, + + /** + * The Scala 2 language + */ + SCALA, + + /** + * The Scala 3 language + */ + SCALA_3, + + /** + * The Kotlin language + */ + KOTLIN, + + /** + * XML + */ + XML; + + public boolean isJava() { + return this == JAVA; + } + + public boolean isScala() { + return this == SCALA || this == SCALA_3; + } + + public boolean isKotlin() { + return this == KOTLIN; + } } \ No newline at end of file diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/Scala3Generator.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/Scala3Generator.java new file mode 100644 index 0000000000..388f23a5d4 --- /dev/null +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/Scala3Generator.java @@ -0,0 +1,56 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * Apache-2.0 license and offer limited warranties, support, maintenance, and + * commercial database integrations. + * + * For more information, please visit: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.codegen; + +import static org.jooq.codegen.Language.SCALA_3; + +import org.jooq.tools.JooqLogger; + +/** + * @author Lukas Eder + */ +public class Scala3Generator extends JavaGenerator { + + private static final JooqLogger log = JooqLogger.getLogger(Scala3Generator.class); + + public Scala3Generator() { + super(SCALA_3); + + log.warn("Scala 3 support is experimental in jOOQ. Please report any findings here, if any: https://github.com/jOOQ/jOOQ/issues/12180"); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractQualifiedRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractQualifiedRecord.java index fa13c3b013..ed7267c1a0 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractQualifiedRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractQualifiedRecord.java @@ -53,8 +53,6 @@ import org.jooq.Field; import org.jooq.QualifiedRecord; import org.jooq.RecordQualifier; import org.jooq.Row; -import org.jooq.SQLDialect; -import org.jooq.Scope; /** * @author Lukas Eder @@ -78,15 +76,17 @@ abstract class AbstractQualifiedRecord> extends Abs return qualifier; } + // [#12180] scalac 3 requires overriding this method to work around an interoperability regression @SuppressWarnings("unchecked") @Override - public final R with(Field field, T value) { + public /* non-final */ R with(Field field, T value) { return (R) super.with(field, value); } + // [#12180] scalac 3 requires overriding this method to work around an interoperability regression @SuppressWarnings("unchecked") @Override - public final R with(Field field, U value, Converter converter) { + public /* non-final */ R with(Field field, U value, Converter converter) { return (R) super.with(field, value, converter); } diff --git a/jOOQ/src/main/java/org/jooq/impl/EmbeddableRecordImpl.java b/jOOQ/src/main/java/org/jooq/impl/EmbeddableRecordImpl.java index 26790eba4b..520825309a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/EmbeddableRecordImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/EmbeddableRecordImpl.java @@ -76,15 +76,17 @@ public class EmbeddableRecordImpl> extends Abstrac super((AbstractRow) fields); } + // [#12180] scalac 3 requires overriding this method to work around an interoperability regression @SuppressWarnings("unchecked") @Override - public final R with(Field field, T value) { + public /* non-final */ R with(Field field, T value) { return (R) super.with(field, value); } + // [#12180] scalac 3 requires overriding this method to work around an interoperability regression @SuppressWarnings("unchecked") @Override - public final R with(Field field, U value, Converter converter) { + public /* non-final */ R with(Field field, U value, Converter converter) { return (R) super.with(field, value, converter); } diff --git a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java index 5ae88c87c6..757eb85264 100644 --- a/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/TableRecordImpl.java @@ -79,6 +79,7 @@ import java.util.Set; import java.util.function.Predicate; import org.jooq.Configuration; +import org.jooq.Converter; import org.jooq.DSLContext; import org.jooq.DataType; import org.jooq.Field; @@ -481,4 +482,16 @@ implements DataType t = f.getDataType(); return predicate.test(t) || t.isEmbeddable() && anyMatch(t.getRow().fields(), x -> predicate.test(x.getDataType())); } + + // [#12180] scalac 3 requires overriding this method to work around an interoperability regression + @Override + public /* non-final */ R with(Field field, T value) { + return super.with(field, value); + } + + // [#12180] scalac 3 requires overriding this method to work around an interoperability regression + @Override + public /* non-final */ R with(Field field, U value, Converter converter) { + return super.with(field, value, converter); + } } diff --git a/pom.xml b/pom.xml index 3e4b60c828..5a003cd65e 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 2.13.11 - 3.3.1 + 3.5.0 1.8.0