[jOOQ/jOOQ#644] Add support for Oracle TYPE .. UNDER type hierarchies

This includes:

- [jOOQ/jOOQ#11371] Generate UDT.getSupertype() and UDT.getSubtypes()
This commit is contained in:
Lukas Eder 2024-08-28 12:56:34 +02:00
parent fdbeea9977
commit 175380c1dc
13 changed files with 360 additions and 49 deletions

View File

@ -603,26 +603,17 @@ public class DefaultGeneratorStrategy extends AbstractGeneratorStrategy {
sb.append(subPackage);
}
// Record are yet in another subpackage
if (mode == Mode.RECORD) {
// Other subpackages
if (mode == Mode.RECORD)
sb.append(".records");
}
// POJOs too
else if (mode == Mode.POJO) {
else if (mode == Mode.RECORD_TYPE)
sb.append(".recordtypes");
else if (mode == Mode.POJO)
sb.append(".pojos");
}
// DAOs too
else if (mode == Mode.DAO) {
else if (mode == Mode.DAO)
sb.append(".daos");
}
// Interfaces too
else if (mode == Mode.INTERFACE) {
else if (mode == Mode.INTERFACE)
sb.append(".interfaces");
}
@ -679,6 +670,8 @@ public class DefaultGeneratorStrategy extends AbstractGeneratorStrategy {
result.append("Dao");
else if (mode == Mode.INTERFACE)
result.insert(0, "I");
else if (mode == Mode.RECORD_TYPE)
result.append("RecordType");
else if (mode == Mode.PATH)
result.append("Path");

View File

@ -616,6 +616,12 @@ public interface GeneratorStrategy {
*/
RECORD,
/**
* The record type mode. This is used when a {@link UDTDefinition}'s
* record type interface is being rendered.
*/
RECORD_TYPE,
/**
* The pojo mode. This is used when a {@link TableDefinition}'s pojo
* class is being rendered

View File

@ -154,6 +154,7 @@ 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;
@ -779,6 +780,7 @@ public class JavaGenerator extends AbstractGenerator {
if (generateUDTs()) {
generateUDTRecords(schema);
generateUDTRecordTypes(schema);
if (generatePojos())
generateUDTPojos(schema);
@ -1712,6 +1714,15 @@ public class JavaGenerator extends AbstractGenerator {
if (generateInterfaces())
interfaces.add(out.ref(getStrategy().getFullJavaClassName(tableUdtOrEmbeddable, Mode.INTERFACE)));
if (tableUdtOrEmbeddable instanceof UDTDefinition u) {
if (u.getSupertype() != null || !u.getSubtypes().isEmpty()) {
interfaces.add(out.ref(getStrategy().getFullJavaClassName(u, Mode.RECORD_TYPE))
+ "<"
+ className
+ ">");
}
}
if (scala) {
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.println("%sclass %s extends %s[%s](%s.%s.getDataType.getRow)[[before= with ][separator= with ][%s]] {",
@ -2169,6 +2180,104 @@ public class JavaGenerator extends AbstractGenerator {
out.println("}");
}
protected void generateUDTRecordType(UDTDefinition udt) {
JavaWriter out = newJavaWriter(udt, Mode.RECORD_TYPE);
log.info("Generating record type", out.file().getName());
generateRecordType0(udt, out);
closeJavaWriter(out);
}
private final void generateRecordType0(UDTDefinition udt, JavaWriter out) {
final String className = getStrategy().getJavaClassName(udt, Mode.RECORD_TYPE);
final List<String> interfaces = out.ref(getStrategy().getJavaClassImplements(udt, Mode.RECORD_TYPE));
interfaces.add(out.ref(UDTRecord.class) + "<R>");
if (udt.getSupertype() != null)
interfaces.add(out.ref(getStrategy().getFullJavaClassName(udt.getSupertype(), Mode.RECORD_TYPE)) + "<R>");
printPackage(out, udt, Mode.RECORD_TYPE);
generateUDTRecordTypeClassJavadoc(udt, out);
printClassAnnotations(out, udt, Mode.RECORD_TYPE);
if (scala)
out.println("%strait %s[R <: %s[R] ] extends [[%s]] {", visibility(), className, UDTRecord.class, interfaces);
else if (kotlin)
out.println("%sinterface %s<R : %s<R>> : [[%s]] {", visibility(), className, UDTRecord.class, interfaces);
else
out.println("%sinterface %s<R extends %s<R>> extends [[%s]] {", visibility(), className, UDTRecord.class, interfaces);
List<? extends TypedElementDefinition<?>> typedElements = getTypedElements(udt);
for (int i = 0; i < typedElements.size(); i++) {
TypedElementDefinition<?> column = typedElements.get(i);
if (!generateImmutableInterfaces())
generateUDTRecordTypeSetter(column, i, out);
generateUDTRecordTypeGetter(column, i, out);
}
generateUDTRecordTypeClassFooter(udt, out);
out.println("}");
}
/**
* Subclasses may override this method to provide their own record type setters.
*/
protected void generateUDTRecordTypeSetter(TypedElementDefinition<?> column, int index, JavaWriter out) {
generateUDTRecordTypeSetter0(column, index, out);
}
private final void generateUDTRecordTypeSetter0(TypedElementDefinition<?> column, @SuppressWarnings("unused") int index, JavaWriter out) {
final String className = getStrategy().getJavaClassName(column.getContainer(), Mode.RECORD_TYPE);
final String setterReturnType = generateFluentSetters() ? className : tokenVoid;
final String setter = getStrategy().getJavaSetterName(column, Mode.RECORD_TYPE);
final String typeFull = getJavaType(column.getType(resolver(out, Mode.RECORD_TYPE)), out, Mode.RECORD_TYPE);
final String type = out.ref(typeFull);
final String name = column.getQualifiedOutputName();
if (!kotlin && !printDeprecationIfUnknownType(out, typeFull))
out.javadoc("Setter for <code>%s</code>.[[before= ][%s]]", name, list(escapeEntities(comment(column))));
if (scala)
out.println("%sdef %s(value: %s): %s", visibilityPublic(), setter, type, setterReturnType);
// The property is already defined in the getter
else if (kotlin) {}
else
out.println("%s%s %s([[before=@][after= ][%s]]%s value);", visibilityPublic(), setterReturnType, setter, list(nullableOrNonnullAnnotation(out, column)), varargsIfArray(type));
}
/**
* Subclasses may override this method to provide their own record type getters.
*/
protected void generateUDTRecordTypeGetter(TypedElementDefinition<?> column, int index, JavaWriter out) {
generateUDTRecordTypeGetter0(column, index, out);
}
private final void generateUDTRecordTypeGetter0(TypedElementDefinition<?> column, @SuppressWarnings("unused") int index, JavaWriter out) {
final String member = getStrategy().getJavaMemberName(column, Mode.RECORD_TYPE);
final String getter = getStrategy().getJavaGetterName(column, Mode.RECORD_TYPE);
final String typeFull = getJavaType(column.getType(resolver(out, Mode.RECORD_TYPE)), out, Mode.RECORD_TYPE);
final String type = out.ref(typeFull);
final String name = column.getQualifiedOutputName();
if (!kotlin && !printDeprecationIfUnknownType(out, typeFull))
out.javadoc("Getter for <code>%s</code>.[[before= ][%s]]", name, list(escapeEntities(comment(column))));
printValidationAnnotation(out, column);
printNullableOrNonnullAnnotation(out, column);
if (kotlin && !generateImmutableInterfaces())
printKotlinSetterAnnotation(out, column, Mode.RECORD_TYPE);
if (scala)
out.println("%sdef %s: %s", visibilityPublic(), scalaWhitespaceSuffix(getter), type);
else if (kotlin)
out.println("%s%s %s: %s%s", visibilityPublic(), (generateImmutableInterfaces() ? "val" : "var"), member, type, kotlinNullability(out, column, Mode.RECORD_TYPE));
else
out.println("%s%s %s();", visibilityPublic(), type, getter);
}
@FunctionalInterface
private interface EmbeddableFilter {
void accept(List<Definition> result, Set<EmbeddableDefinition> duplicates, int index, EmbeddableDefinition embeddable);
@ -2584,13 +2693,13 @@ public class JavaGenerator extends AbstractGenerator {
}
private String getJavaType(Definition column, JavaWriter out) {
return getJavaType(column, out, Mode.RECORD);
return getJavaType(column, out, Mode.DEFAULT);
}
private String getJavaType(Definition column, JavaWriter out, Mode mode) {
return column instanceof EmbeddableDefinition
? getStrategy().getFullJavaClassName(column, mode)
: getJavaType(((TypedElementDefinition<?>) column).getType(resolver(out)), out);
? getStrategy().getFullJavaClassName(column, mode == Mode.DEFAULT ? Mode.RECORD : mode)
: getJavaType(((TypedElementDefinition<?>) column).getType(resolver(out)), out, mode);
}
private String getJavaTypeRef(Definition column, JavaWriter out) {
@ -2677,7 +2786,7 @@ public class JavaGenerator extends AbstractGenerator {
// [#3117] Avoid covariant setters for UDTs when generating interfaces
if (generateInterfaces() && !generateImmutableInterfaces() && (isUDT || isArray)) {
final String columnTypeFull = getJavaType(column.getType(resolver(out, Mode.RECORD)), out, Mode.RECORD);
final String columnTypeFull = getJavaType(column.getType(resolver(out, Mode.DEFAULT)), out, Mode.DEFAULT);
final String columnType = out.ref(columnTypeFull);
final String columnTypeInterface = out.ref(getJavaType(column.getType(resolver(out, Mode.INTERFACE)), out, Mode.INTERFACE));
@ -3456,6 +3565,40 @@ public class JavaGenerator extends AbstractGenerator {
}
}
if (udt.getSupertype() != null) {
final String superUdtId = out.ref(getStrategy().getFullJavaIdentifier(udt.getSupertype()), 2);
// [#644] TODO
if (scala) {
}
// [#644] TODO
else if (kotlin) {
}
else {
out.overrideInherit();
out.println("%s%s<?> getSupertype() {", visibilityPublic(), UDT.class);
out.println("return %s;", superUdtId);
out.println("}");
}
}
if (!udt.getSubtypes().isEmpty()) {
final List<String> subUdtIds = out.ref(getStrategy().getFullJavaIdentifiers(udt.getSubtypes()), 2);
// [#644] TODO
if (scala) {
}
// [#644] TODO
else if (kotlin) {
}
else {
out.overrideInherit();
out.println("%s%s<%s<?>> getSubtypes() {", visibilityPublic(), List.class, UDT.class);
out.println("return %s.asList([[%s]]);", Arrays.class, subUdtIds);
out.println("}");
}
}
generateUDTClassFooter(udt, out);
out.println("}");
closeJavaWriter(out);
@ -3708,6 +3851,41 @@ public class JavaGenerator extends AbstractGenerator {
printClassJavadoc(out, udt, "The udt <code>" + udt.getQualifiedInputName() + "</code>.");
}
/**
* Generating UDT record types
*/
protected void generateUDTRecordTypes(SchemaDefinition schema) {
log.info("Generating UDT record types");
for (UDTDefinition udt : database.getUDTs(schema)) {
try {
if (udt.getSupertype() != null || !udt.getSubtypes().isEmpty())
generateUDTRecordType(udt);
}
catch (Exception e) {
log.error("Error while generating UDT record types " + udt, e);
}
}
watch.splitInfo("UDT record types generated");
}
/**
* Subclasses may override this method to provide udt record class footer code.
*/
@SuppressWarnings("unused")
protected void generateUDTRecordTypeClassFooter(UDTDefinition udt, JavaWriter out) {}
/**
* Subclasses may override this method to provide their own Javadoc.
*/
protected void generateUDTRecordTypeClassJavadoc(UDTDefinition udt, JavaWriter out) {
if (generateCommentsOnUDTs())
printClassJavadoc(out, udt);
else
printClassJavadoc(out, udt, "The udt <code>" + udt.getQualifiedInputName() + "</code>.");
}
protected void generateUDTRoutines(SchemaDefinition schema) {
for (UDTDefinition udt : database.getUDTs(schema)) {
if (udt.getRoutines().size() > 0) {
@ -10702,7 +10880,7 @@ public class JavaGenerator extends AbstractGenerator {
}
protected String getJavaType(DataTypeDefinition type, JavaWriter out) {
return getJavaType(type, out, Mode.RECORD);
return getJavaType(type, out, Mode.DEFAULT);
}
protected String getJavaType(DataTypeDefinition type, JavaWriter out, Mode udtMode) {
@ -10731,7 +10909,7 @@ public class JavaGenerator extends AbstractGenerator {
}
protected String getType(Database db, SchemaDefinition schema, JavaWriter out, String t, int p, int s, Name u, String javaType, String defaultType) {
return getType(db, schema, out, t, p, s, u, javaType, defaultType, Mode.RECORD);
return getType(db, schema, out, t, p, s, u, javaType, defaultType, Mode.DEFAULT);
}
protected String getType(Database db, SchemaDefinition schema, JavaWriter out, String t, int p, int s, Name u, String javaType, String defaultType, Mode udtMode) {
@ -10739,7 +10917,9 @@ public class JavaGenerator extends AbstractGenerator {
}
protected String getType(Database db, SchemaDefinition schema, JavaWriter out, String t, int p, int s, Name u, String javaType, String defaultType, Mode udtMode, XMLTypeDefinition xmlType) {
UDTDefinition udt;
String type = defaultType;
Mode udtDefaultMode = udtMode == Mode.DEFAULT ? Mode.RECORD : udtMode;
// XML types
if (xmlType != null) {
@ -10762,7 +10942,7 @@ public class JavaGenerator extends AbstractGenerator {
// [#10309] TODO: The schema should be taken from baseType, if available. Might be different than the argument schema.
// When can this happen?
String baseType = getType(db, schema, out, newT, p, s, bt.u(), javaType, defaultType, udtMode);
String baseType = getType(db, schema, out, newT, p, s, bt.u(), javaType, defaultType, udtDefaultMode);
if (scala)
type = "scala.Array[" + baseType + "]";
@ -10804,14 +10984,17 @@ public class JavaGenerator extends AbstractGenerator {
}
// Check for UDTs
else if (db.getUDT(schema, u) != null) {
type = getStrategy().getFullJavaClassName(db.getUDT(schema, u), udtMode);
else if ((udt = db.getUDT(schema, u)) != null) {
if (udt.getSubtypes().isEmpty() || udtMode == Mode.RECORD || udtMode == Mode.POJO || udtMode == Mode.INTERFACE)
type = getStrategy().getFullJavaClassName(udt, udtDefaultMode);
else
type = getStrategy().getFullJavaClassName(udt, Mode.RECORD_TYPE) + "<?>";
}
// [#3942] [#7863] Dialects that support tables as UDTs
// [#5334] In MySQL, the user type is (ab)used for synthetic enum types. This can lead to accidental matches here
else if (SUPPORT_TABLE_AS_UDT.contains(db.getDialect()) && db.getTable(schema, u) != null) {
type = getStrategy().getFullJavaClassName(db.getTable(schema, u), udtMode);
type = getStrategy().getFullJavaClassName(db.getTable(schema, u), udtDefaultMode);
}
// Check for custom types

View File

@ -330,6 +330,7 @@ public abstract class AbstractDatabase implements Database {
private transient Map<SchemaDefinition, List<XMLSchemaCollectionDefinition>> xmlSchemaCollectionsBySchema;
private transient Map<SchemaDefinition, List<UDTDefinition>> udtsBySchema;
private transient Map<PackageDefinition, List<UDTDefinition>> udtsByPackage;
private transient Map<UDTDefinition, List<UDTDefinition>> subtypesByUdt;
private transient Map<SchemaDefinition, List<ArrayDefinition>> arraysBySchema;
private transient Map<SchemaDefinition, List<RoutineDefinition>> routinesBySchema;
private transient Map<SchemaDefinition, List<PackageDefinition>> packagesBySchema;
@ -3101,6 +3102,14 @@ public abstract class AbstractDatabase implements Database {
return filterPackage(getUDTs(), pkg, udtsByPackage);
}
@Override
public List<UDTDefinition> getSubtypes(UDTDefinition udt) {
if (subtypesByUdt == null)
subtypesByUdt = new LinkedHashMap<>();
return filterSupertype(getUDTs(), udt, subtypesByUdt);
}
@Override
public final Relations getRelations() {
if (relations == null) {
@ -3304,6 +3313,23 @@ public abstract class AbstractDatabase implements Database {
return result;
}
final List<UDTDefinition> filterSupertype(List<UDTDefinition> definitions, UDTDefinition supertype, Map<UDTDefinition, List<UDTDefinition>> cache) {
return cache.computeIfAbsent(supertype, u -> filterSupertype(definitions, u));
}
final List<UDTDefinition> filterSupertype(List<UDTDefinition> definitions, UDTDefinition u) {
if (u == null)
return definitions;
List<UDTDefinition> result = new ArrayList<>();
for (UDTDefinition definition : definitions)
if (definition.getSupertype() != null && definition.getSupertype().equals(u))
result.add(definition);
return result;
}
protected final <T extends TableElementDefinition> List<T> filterTable(List<T> definitions, TableDefinition table, Map<TableDefinition, List<T>> cache) {
List<T> result = cache.get(table);

View File

@ -53,6 +53,8 @@ implements
private List<RoutineDefinition> routines;
private final boolean synthetic;
private SchemaDefinition supertypeSchema;
private String supertypeName;
public AbstractUDTDefinition(SchemaDefinition schema, String name, String comment) {
this(schema, null, name, false, comment);
@ -63,9 +65,15 @@ implements
}
public AbstractUDTDefinition(SchemaDefinition schema, PackageDefinition pkg, String name, boolean synthetic, String comment) {
this(schema, pkg, name, synthetic, comment, null, null);
}
public AbstractUDTDefinition(SchemaDefinition schema, PackageDefinition pkg, String name, boolean synthetic, String comment, SchemaDefinition supertypeSchema, String supertypeName) {
super(schema, pkg, name, comment);
this.synthetic = synthetic;
this.supertypeSchema = supertypeSchema;
this.supertypeName = supertypeName;
}
@Override
@ -107,4 +115,14 @@ implements
public boolean isSynthetic() {
return synthetic;
}
@Override
public UDTDefinition getSupertype() {
return supertypeSchema == null ? null : getDatabase().getUDT(supertypeSchema, supertypeName);
}
@Override
public List<UDTDefinition> getSubtypes() {
return getDatabase().getSubtypes(this);
}
}

View File

@ -411,6 +411,11 @@ public interface Database extends AutoCloseable {
*/
List<UDTDefinition> getUDTs(PackageDefinition pkg);
/**
* Get the subtypes of a UDT, if any.
*/
List<UDTDefinition> getSubtypes(UDTDefinition udt);
/**
* The Arrays defined in this database.
*/

View File

@ -76,4 +76,14 @@ public interface UDTDefinition extends PackageDefinition {
*/
@Override
boolean isSynthetic();
/**
* The subtypes of this UDT, if any.
*/
List<UDTDefinition> getSubtypes();
/**
* The supertype of this UDT, if any.
*/
UDTDefinition getSupertype();
}

View File

@ -37,6 +37,11 @@
*/
package org.jooq;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* UDT definition.
* <p>
@ -63,4 +68,23 @@ public interface UDT<R extends UDTRecord<R>> extends RecordQualifier<R> {
* </ul>
*/
boolean isSynthetic();
/**
* Get the supertype of this {@link UDT}, or <code>null</code> if this type
* has no supertype.
*/
@Nullable
UDT<?> getSupertype();
/**
* Get the subtypes of this {@link UDT} or an empty list, if there are no
* known subtypes.
*/
@NotNull
List<UDT<?>> getSubtypes();
/**
* Check if this type is a supertype or the same type as another {@link UDT} type.
*/
boolean isAssignableFrom(UDT<?> other);
}

View File

@ -273,11 +273,11 @@ implements
* @deprecated - 3.20.0 - [#15723] - Re-generate your code.
*/
@Deprecated
protected AbstractRoutine(String name, Schema schema, DataType<T> type) {
protected AbstractRoutine(String name, Schema schema, DataType<? extends T> type) {
this(name, schema, (Package) null, type, null, null);
}
protected AbstractRoutine(String name, Schema schema, Comment comment, DataType<T> type) {
protected AbstractRoutine(String name, Schema schema, Comment comment, DataType<? extends T> type) {
this(name, schema, (Package) null, comment, type, null, null);
}
@ -321,11 +321,11 @@ implements
* @deprecated - 3.20.0 - [#15723] - Re-generate your code.
*/
@Deprecated
protected AbstractRoutine(String name, Schema schema, Package pkg, DataType<T> type) {
protected AbstractRoutine(String name, Schema schema, Package pkg, DataType<? extends T> type) {
this(name, schema, pkg, type, null, null);
}
protected AbstractRoutine(String name, Schema schema, Package pkg, Comment comment, DataType<T> type) {
protected AbstractRoutine(String name, Schema schema, Package pkg, Comment comment, DataType<? extends T> type) {
this(name, schema, pkg, comment, type, null, null);
}

View File

@ -358,7 +358,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
static final <T, U> Binding<T, U> binding(DataType<T> dataType, Converter<T, U> converter) {
static final <T, U> Binding<T, U> binding(DataType<? extends T> dataType, Converter<T, U> converter) {
Class<?> type = converter.fromType();
// Concrete types
@ -550,7 +550,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
static final <T, X, U> Binding<T, U> newBinding(final Converter<X, U> converter, final DataType<T> dataType, final Binding<T, X> binding) {
static final <T, X, U> Binding<T, U> newBinding(final Converter<X, U> converter, final DataType<? extends T> dataType, final Binding<T, X> binding) {
final Binding<T, U> theBinding;
@ -622,7 +622,9 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
try {
if (QualifiedRecord.class.isAssignableFrom(type)) {
Class<QualifiedRecord<?>> t = (Class<QualifiedRecord<?>>) type;
result.put(getMappedUDTName(scope, t), t);
// [#644] Prevent infinite recursion between fields and subtypes
if (result.putIfAbsent(getMappedUDTName(scope, t), t) == null) {
@ -635,8 +637,16 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
for (Field<?> field : getRecordQualifier(t).fields())
typeMap(field.getType(), scope, result);
RecordQualifier<?> q = getRecordQualifier(t);
for (Field<?> field : q.fields())
typeMap(field.getType(), scope, result);
// [#644] Put subtypes into the type map as well
if (q instanceof UDT<?> u) {
for (UDT<?> s : u.getSubtypes())
typeMap(s.getRecordType(), scope, result);
}
}
}
@ -647,6 +657,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
}
catch (Exception e) {
throw new MappingException("Error while collecting type map", e);
@ -1871,6 +1882,14 @@ public class DefaultBinding<T, U> implements Binding<T, U> {

View File

@ -643,7 +643,7 @@ public final class Internal {
* Factory method for parameters.
*/
@NotNull
public static final <T> Parameter<T> createParameter(String name, DataType<T> type, boolean isDefaulted, boolean isUnnamed) {
public static final <T> Parameter<T> createParameter(String name, DataType<? extends T> type, boolean isDefaulted, boolean isUnnamed) {
return createParameter(name, type, isDefaulted, isUnnamed, null, null);
}
@ -651,7 +651,7 @@ public final class Internal {
* Factory method for parameters.
*/
@NotNull
public static final <T, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, boolean isUnnamed, Converter<T, U> converter) {
public static final <T, U> Parameter<U> createParameter(String name, DataType<? extends T> type, boolean isDefaulted, boolean isUnnamed, Converter<T, U> converter) {
return createParameter(name, type, isDefaulted, isUnnamed, converter, null);
}
@ -659,7 +659,7 @@ public final class Internal {
* Factory method for parameters.
*/
@NotNull
public static final <T, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, boolean isUnnamed, Binding<T, U> binding) {
public static final <T, U> Parameter<U> createParameter(String name, DataType<? extends T> type, boolean isDefaulted, boolean isUnnamed, Binding<T, U> binding) {
return createParameter(name, type, isDefaulted, isUnnamed, null, binding);
}
@ -668,7 +668,7 @@ public final class Internal {
*/
@NotNull
@SuppressWarnings("unchecked")
public static final <T, X, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, boolean isUnnamed, Converter<X, U> converter, Binding<T, X> binding) {
public static final <T, X, U> Parameter<U> createParameter(String name, DataType<? extends T> type, boolean isDefaulted, boolean isUnnamed, Converter<X, U> converter, Binding<T, X> binding) {
final Binding<T, U> actualBinding = DefaultBinding.newBinding(converter, type, binding);
final DataType<U> actualType = converter == null && binding == null
? (DataType<U>) type

View File

@ -37,6 +37,7 @@
*/
package org.jooq.impl;
import org.jooq.ConverterContext;
import org.jooq.Record;
import org.jooq.Row;
import org.jooq.SQLDialect;

View File

@ -37,6 +37,12 @@
*/
package org.jooq.impl;
import static java.util.Collections.emptyList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.jooq.Binding;
import org.jooq.Catalog;
import org.jooq.Comment;
@ -54,6 +60,7 @@ import org.jooq.UDTField;
import org.jooq.UDTRecord;
import org.jooq.impl.QOM.UNotYetImplemented;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.ApiStatus.Internal;
/**
@ -163,6 +170,25 @@ implements
throw new UnsupportedOperationException();
}
@Override
public /* non-final */ UDT<?> getSupertype() {
return null;
}
@Override
public /* non-final */ List<UDT<?>> getSubtypes() {
return emptyList();
}
@Override
public final boolean isAssignableFrom(UDT<?> other) {
if (equals(other))
return true;
UDT<?> s = other.getSupertype();
return s != null ? isAssignableFrom(s) : false;
}
@Override
public final boolean isSQLUsable() {
return true ;
@ -209,7 +235,7 @@ implements
* instead.
*/
@Deprecated
protected static final <R extends UDTRecord<R>, T> UDTField<R, T> createField(String name, DataType<T> type, UDT<R> udt) {
protected static final <R extends UDTRecord<R>, T> UDTField<R, T> createField(String name, DataType<? extends T> type, UDT<R> udt) {
return createField(DSL.name(name), type, udt, "", null, null);
}
@ -224,7 +250,7 @@ implements
* instead.
*/
@Deprecated
protected static final <R extends UDTRecord<R>, T> UDTField<R, T> createField(String name, DataType<T> type, UDT<R> udt, String comment) {
protected static final <R extends UDTRecord<R>, T> UDTField<R, T> createField(String name, DataType<? extends T> type, UDT<R> udt, String comment) {
return createField(DSL.name(name), type, udt, comment, null, null);
}
@ -239,7 +265,7 @@ implements
* instead.
*/
@Deprecated
protected static final <R extends UDTRecord<R>, T, U> UDTField<R, U> createField(String name, DataType<T> type, UDT<R> udt, String comment, Converter<T, U> converter) {
protected static final <R extends UDTRecord<R>, T, U> UDTField<R, U> createField(String name, DataType<? extends T> type, UDT<R> udt, String comment, Converter<T, U> converter) {
return createField(DSL.name(name), type, udt, comment, converter, null);
}
@ -254,7 +280,7 @@ implements
* instead.
*/
@Deprecated
protected static final <R extends UDTRecord<R>, T, U> UDTField<R, U> createField(String name, DataType<T> type, UDT<R> udt, String comment, Binding<T, U> binding) {
protected static final <R extends UDTRecord<R>, T, U> UDTField<R, U> createField(String name, DataType<? extends T> type, UDT<R> udt, String comment, Binding<T, U> binding) {
return createField(DSL.name(name), type, udt, comment, null, binding);
}
@ -269,7 +295,7 @@ implements
* instead.
*/
@Deprecated
protected static final <R extends UDTRecord<R>, T, X, U> UDTField<R, U> createField(String name, DataType<T> type, UDT<R> udt, String comment, Converter<X, U> converter, Binding<T, X> binding) {
protected static final <R extends UDTRecord<R>, T, X, U> UDTField<R, U> createField(String name, DataType<? extends T> type, UDT<R> udt, String comment, Converter<X, U> converter, Binding<T, X> binding) {
return createField(DSL.name(name), type, udt, comment, converter, binding);
}
@ -280,7 +306,7 @@ implements
* @param name The name of the field (case-sensitive!)
* @param type The data type of the field
*/
protected static final <R extends UDTRecord<R>, T> UDTField<R, T> createField(Name name, DataType<T> type, UDT<R> udt) {
protected static final <R extends UDTRecord<R>, T> UDTField<R, T> createField(Name name, DataType<? extends T> type, UDT<R> udt) {
return createField(name, type, udt, "", null, null);
}
@ -291,7 +317,7 @@ implements
* @param name The name of the field (case-sensitive!)
* @param type The data type of the field
*/
protected static final <R extends UDTRecord<R>, T> UDTField<R, T> createField(Name name, DataType<T> type, UDT<R> udt, String comment) {
protected static final <R extends UDTRecord<R>, T> UDTField<R, T> createField(Name name, DataType<? extends T> type, UDT<R> udt, String comment) {
return createField(name, type, udt, comment, null, null);
}
@ -302,7 +328,7 @@ implements
* @param name The name of the field (case-sensitive!)
* @param type The data type of the field
*/
protected static final <R extends UDTRecord<R>, T, U> UDTField<R, U> createField(Name name, DataType<T> type, UDT<R> udt, String comment, Converter<T, U> converter) {
protected static final <R extends UDTRecord<R>, T, U> UDTField<R, U> createField(Name name, DataType<? extends T> type, UDT<R> udt, String comment, Converter<T, U> converter) {
return createField(name, type, udt, comment, converter, null);
}
@ -313,7 +339,7 @@ implements
* @param name The name of the field (case-sensitive!)
* @param type The data type of the field
*/
protected static final <R extends UDTRecord<R>, T, U> UDTField<R, U> createField(Name name, DataType<T> type, UDT<R> udt, String comment, Binding<T, U> binding) {
protected static final <R extends UDTRecord<R>, T, U> UDTField<R, U> createField(Name name, DataType<? extends T> type, UDT<R> udt, String comment, Binding<T, U> binding) {
return createField(name, type, udt, comment, null, binding);
}
@ -325,7 +351,7 @@ implements
* @param type The data type of the field
*/
@SuppressWarnings("unchecked")
protected static final <R extends UDTRecord<R>, T, X, U> UDTField<R, U> createField(Name name, DataType<T> type, UDT<R> udt, String comment, Converter<X, U> converter, Binding<T, X> binding) {
protected static final <R extends UDTRecord<R>, T, X, U> UDTField<R, U> createField(Name name, DataType<? extends T> type, UDT<R> udt, String comment, Converter<X, U> converter, Binding<T, X> binding) {
final Binding<T, U> actualBinding = DefaultBinding.newBinding(converter, type, binding);
final DataType<U> actualType = converter == null && binding == null
? (DataType<U>) type