From fb2f7760579cfce18ee565b4a09fb57cd715bb4a Mon Sep 17 00:00:00 2001 From: lukaseder Date: Wed, 16 Sep 2015 18:53:21 +0200 Subject: [PATCH] [#3082] Let generated POJOs reference Java array types, instead of ArrayRecords --- .../java/org/jooq/util/JavaGenerator.java | 166 +++++++++++++----- .../main/java/org/jooq/util/JavaWriter.java | 6 +- .../org/jooq/util/DataTypeDefinition.java | 5 + .../jooq/util/DefaultDataTypeDefinition.java | 5 + 4 files changed, 133 insertions(+), 49 deletions(-) diff --git a/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java b/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java index 85a318bde8..d4abf7a4dc 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java +++ b/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java @@ -866,34 +866,43 @@ public class JavaGenerator extends AbstractGenerator { final String type = out.ref(getJavaType(column.getType())); final String name = column.getQualifiedOutputName(); final boolean isUDT = column.getType().isUDT(); + final boolean isArray = column.getType().isArray(); + final boolean isUDTArray = column.getType().isArray() && database.getArray(column.getType().getSchema(), column.getType().getUserType()).getElementType().isUDT(); - out.tab(1).javadoc("Setter for %s.%s", name, defaultIfBlank(" " + comment, "")); - if (scala) { - out.tab(1).println("def %s(value : %s) : %s = {", setter, type, setterReturnType); - out.tab(2).println("setValue(%s, value)", i); - if (fluentSetters()) - out.tab(2).println("this"); - out.tab(1).println("}"); - } - else { - out.tab(1).overrideIf(generateInterfaces() && !generateImmutablePojos() && !isUDT); - out.tab(1).println("public %s %s(%s value) {", setterReturnType, setter, type); - out.tab(2).println("setValue(%s, value);", i); - if (fluentSetters()) - out.tab(2).println("return this;"); - out.tab(1).println("}"); + // We cannot have covariant setters for arrays because of type erasure + if (!(generateInterfaces() && isArray)) { + out.tab(1).javadoc("Setter for %s.%s", name, defaultIfBlank(" " + comment, "")); + + if (scala) { + out.tab(1).println("def %s(value : %s) : %s = {", setter, type, setterReturnType); + out.tab(2).println("setValue(%s, value)", i); + if (fluentSetters()) + out.tab(2).println("this"); + out.tab(1).println("}"); + } + else { + out.tab(1).overrideIf(generateInterfaces() && !generateImmutablePojos() && !isUDT); + out.tab(1).println("public %s %s(%s value) {", setterReturnType, setter, type); + out.tab(2).println("setValue(%s, value);", i); + if (fluentSetters()) + out.tab(2).println("return this;"); + out.tab(1).println("}"); + } } // [#3117] Avoid covariant setters for UDTs when generating interfaces - if (generateInterfaces() && !generateImmutablePojos() && isUDT) { - final String typeInterface = out.ref(getJavaType(column.getType(), Mode.INTERFACE)); + if (generateInterfaces() && !generateImmutablePojos() && (isUDT || isArray)) { + final String columnType = out.ref(getJavaType(column.getType(), Mode.RECORD)); + final String columnTypeInterface = out.ref(getJavaType(column.getType(), Mode.INTERFACE)); out.tab(1).javadoc("Setter for %s.%s", name, defaultIfBlank(" " + comment, "")); out.tab(1).override(); if (scala) { - out.tab(1).println("def %s(value : %s) : %s = {", setter, typeInterface, setterReturnType); + // [#3082] TODO Handle + ARRAY also for Scala + + out.tab(1).println("def %s(value : %s) : %s = {", setter, columnTypeInterface, setterReturnType); out.tab(2).println("if (value == null)"); out.tab(3).println("setValue(%s, null)", i); out.tab(2).println("else"); @@ -903,13 +912,37 @@ public class JavaGenerator extends AbstractGenerator { out.tab(1).println("}"); } else { - out.tab(1).println("public %s %s(%s value) {", setterReturnType, setter, typeInterface); + out.tab(1).println("public %s %s(%s value) {", setterReturnType, setter, columnTypeInterface); out.tab(2).println("if (value == null)"); out.tab(3).println("setValue(%s, null);", i); - out.tab(2).println("else"); - out.tab(3).println("setValue(%s, value.into(new %s()));", i, type); + + if (isUDT) { + out.tab(2).println("else"); + out.tab(3).println("setValue(%s, value.into(new %s()));", i, type); + } + else if (isArray) { + final ArrayDefinition array = database.getArray(column.getType().getSchema(), column.getType().getUserType()); + final String componentType = out.ref(getJavaType(array.getElementType(), Mode.RECORD)); + final String componentTypeInterface = out.ref(getJavaType(array.getElementType(), Mode.INTERFACE)); + + out.tab(2).println("else {"); + out.tab(3).println("%s a = new %s();", columnType, columnType); + out.println(); + out.tab(3).println("for (%s i : value)", componentTypeInterface); + + if (isUDTArray) + out.tab(4).println("a.add(i.into(new %s()));", componentType); + else + out.tab(4).println("a.add(i);", componentType); + + out.println(); + out.tab(3).println("setValue(1, a);"); + out.tab(2).println("}"); + } + if (fluentSetters()) out.tab(2).println("return this;"); + out.tab(1).println("}"); } } @@ -1274,7 +1307,7 @@ public class JavaGenerator extends AbstractGenerator { final String setterReturnType = fluentSetters() ? className : "void"; final String setter = getStrategy().getJavaSetterName(column, Mode.DEFAULT); final String getter = getStrategy().getJavaGetterName(column, Mode.DEFAULT); - final String type = out.ref(getJavaType((column).getType(), Mode.INTERFACE)); + final String type = out.ref(getJavaType(column.getType(), Mode.INTERFACE)); final String name = column.getQualifiedOutputName(); if (!generateImmutablePojos()) { @@ -2485,11 +2518,13 @@ public class JavaGenerator extends AbstractGenerator { for (TypedElementDefinition column : getTypedElements(tableOrUDT)) { final String columnType = out.ref(getJavaType(column.getType(), Mode.POJO)); + final String columnTypeInterface = out.ref(getJavaType(column.getType(), Mode.INTERFACE)); final String columnSetterReturnType = fluentSetters() ? className : (scala ? "Unit" : "void"); final String columnSetter = getStrategy().getJavaSetterName(column, Mode.POJO); final String columnGetter = getStrategy().getJavaGetterName(column, Mode.POJO); final String columnMember = getStrategy().getJavaMemberName(column, Mode.POJO); final boolean isUDT = column.getType().isUDT(); + final boolean isUDTArray = column.getType().isArray() && database.getArray(column.getType().getSchema(), column.getType().getUserType()).getElementType().isUDT(); // Getter out.println(); @@ -2513,38 +2548,44 @@ public class JavaGenerator extends AbstractGenerator { // Setter if (!generateImmutablePojos()) { - out.println(); - - if (scala) { - out.tab(1).println("def %s(%s : %s) : %s = {", columnSetter, columnMember, columnType, columnSetterReturnType); - out.tab(2).println("this.%s = %s", columnMember, columnMember); - if (fluentSetters()) - out.tab(2).println("this"); - out.tab(1).println("}"); - } - else { - out.tab(1).overrideIf(generateInterfaces() && !isUDT); - out.tab(1).println("public %s %s(%s %s) {", columnSetterReturnType, columnSetter, columnType, columnMember); - out.tab(2).println("this.%s = %s;", columnMember, columnMember); - if (fluentSetters()) - out.tab(2).println("return this;"); - out.tab(1).println("}"); - } - - // [#3117] To avoid covariant setters on POJOs, we need to generate two setter overloads - if (generateInterfaces() && isUDT) { - final String columnTypeInterface = out.ref(getJavaType(column.getType(), Mode.INTERFACE)); + // We cannot have covariant setters for arrays because of type erasure + if (!(generateInterfaces() && isUDTArray)) { out.println(); if (scala) { + out.tab(1).println("def %s(%s : %s) : %s = {", columnSetter, columnMember, columnType, columnSetterReturnType); + out.tab(2).println("this.%s = %s", columnMember, columnMember); + if (fluentSetters()) + out.tab(2).println("this"); + out.tab(1).println("}"); + } + else { + out.tab(1).overrideIf(generateInterfaces() && !isUDT); + out.tab(1).println("public %s %s(%s %s) {", columnSetterReturnType, columnSetter, columnType, columnMember); + out.tab(2).println("this.%s = %s;", columnMember, columnMember); + if (fluentSetters()) + out.tab(2).println("return this;"); + out.tab(1).println("}"); + } + } + + // [#3117] To avoid covariant setters on POJOs, we need to generate two setter overloads + if (generateInterfaces() && (isUDT || isUDTArray)) { + out.println(); + + if (scala) { + // [#3082] TODO Handle + ARRAY also for Scala + out.tab(1).println("def %s(%s : %s) : %s = {", columnSetter, columnMember, columnTypeInterface, columnSetterReturnType); out.tab(2).println("if (%s == null)", columnMember); out.tab(3).println("this.%s = null", columnMember); out.tab(2).println("else"); out.tab(3).println("this.%s = %s.into(new %s)", columnMember, columnMember, columnType); + if (fluentSetters()) out.tab(2).println("this"); + out.tab(1).println("}"); } else { @@ -2552,10 +2593,27 @@ public class JavaGenerator extends AbstractGenerator { out.tab(1).println("public %s %s(%s %s) {", columnSetterReturnType, columnSetter, columnTypeInterface, columnMember); out.tab(2).println("if (%s == null)", columnMember); out.tab(3).println("this.%s = null;", columnMember); - out.tab(2).println("else"); - out.tab(3).println("this.%s = %s.into(new %s());", columnMember, columnMember, columnType); + + if (isUDT) { + out.tab(2).println("else"); + out.tab(3).println("this.%s = %s.into(new %s());", columnMember, columnMember, columnType); + } + else if (isUDTArray) { + final ArrayDefinition array = database.getArray(column.getType().getSchema(), column.getType().getUserType()); + final String componentType = out.ref(getJavaType(array.getElementType(), Mode.POJO)); + final String componentTypeInterface = out.ref(getJavaType(array.getElementType(), Mode.INTERFACE)); + + out.tab(2).println("else {"); + out.tab(3).println("this.%s = new %s();", columnMember, ArrayList.class); + out.println(); + out.tab(3).println("for (%s i : %s)", componentTypeInterface, columnMember); + out.tab(4).println("this.%s.add(i.into(new %s()));", columnMember, componentType); + out.tab(2).println("}"); + } + if (fluentSetters()) out.tab(2).println("return this;"); + out.tab(1).println("}"); } } @@ -4432,7 +4490,23 @@ public class JavaGenerator extends AbstractGenerator { // Check for Oracle-style VARRAY types else if (db.getArray(schema, u) != null) { - type = getStrategy().getFullJavaClassName(db.getArray(schema, u), Mode.RECORD); + boolean udtArray = db.getArray(schema, u).getElementType().isUDT(); + + if (udtMode == Mode.POJO || (udtMode == Mode.INTERFACE && !udtArray)) { + if (scala) + type = "java.util.List[" + getJavaType(db.getArray(schema, u).getElementType(), udtMode) + "]"; + else + type = "java.util.List<" + getJavaType(db.getArray(schema, u).getElementType(), udtMode) + ">"; + } + else if (udtMode == Mode.INTERFACE) { + if (scala) + type = "java.util.List[_ <:" + getJavaType(db.getArray(schema, u).getElementType(), udtMode) + "]"; + else + type = "java.util.List"; + } + else { + type = getStrategy().getFullJavaClassName(db.getArray(schema, u), Mode.RECORD); + } } // Check for ENUM types diff --git a/jOOQ-codegen/src/main/java/org/jooq/util/JavaWriter.java b/jOOQ-codegen/src/main/java/org/jooq/util/JavaWriter.java index 301314d4f5..d267e480c9 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/util/JavaWriter.java +++ b/jOOQ-codegen/src/main/java/org/jooq/util/JavaWriter.java @@ -33,8 +33,8 @@ public class JavaWriter extends GeneratorWriter { private final String className; private final boolean isJava; private final boolean isScala; - private final Pattern REF_PATTERN = Pattern - .compile("((?:[\\p{L}_$][\\p{L}\\p{N}_$]*\\.)*[\\p{L}_$][\\p{L}\\p{N}_$]*)((?:<.*>|\\[.*\\])*)"); ; + private final Pattern REF_PATTERN = Pattern.compile("((?:[\\p{L}_$][\\p{L}\\p{N}_$]*\\.)*[\\p{L}_$][\\p{L}\\p{N}_$]*)((?:<.*>|\\[.*\\])*)"); + private final Pattern PLAIN_GENERIC_TYPE_PATTERN = Pattern.compile("[<\\[]((?:[\\p{L}_$][\\p{L}\\p{N}_$]*\\.)*[\\p{L}_$][\\p{L}\\p{N}_$]*)[>\\]]"); public JavaWriter(File file, String fullyQualifiedTypes) { super(file); @@ -194,7 +194,7 @@ public class JavaWriter extends GeneratorWriter { // Consider importing generic type arguments, recursively c = remainder - + (generic.startsWith("<") || generic.startsWith("[") + + (PLAIN_GENERIC_TYPE_PATTERN.matcher(generic).matches() ? generic.substring(0, 1) + ref(generic.substring(1, generic.length() - 1)) + generic.substring(generic.length() - 1) : generic); } diff --git a/jOOQ-meta/src/main/java/org/jooq/util/DataTypeDefinition.java b/jOOQ-meta/src/main/java/org/jooq/util/DataTypeDefinition.java index caf76212ea..92a2251760 100644 --- a/jOOQ-meta/src/main/java/org/jooq/util/DataTypeDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/util/DataTypeDefinition.java @@ -100,6 +100,11 @@ public interface DataTypeDefinition { */ boolean isUDT(); + /** + * Whether this data type represents an array. + */ + boolean isArray(); + /** * Whether this data type is a NUMBER type without precision and scale. */ diff --git a/jOOQ-meta/src/main/java/org/jooq/util/DefaultDataTypeDefinition.java b/jOOQ-meta/src/main/java/org/jooq/util/DefaultDataTypeDefinition.java index b53888e33c..a50cd48871 100644 --- a/jOOQ-meta/src/main/java/org/jooq/util/DefaultDataTypeDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/util/DefaultDataTypeDefinition.java @@ -140,6 +140,11 @@ public class DefaultDataTypeDefinition implements DataTypeDefinition { return getDatabase().getUDT(schema, udtName) != null; } + @Override + public final boolean isArray() { + return getDatabase().getArray(schema, udtName) != null; + } + @Override public final String getType() { return typeName;