From bd0c184e0f6ac40ab560755d734c8a5da7d68d8a Mon Sep 17 00:00:00 2001 From: lukaseder Date: Tue, 20 Dec 2016 17:03:32 +0100 Subject: [PATCH] [#4429] Add to code generator configuration to generate Java 8 java.time types instead of java.sql types --- .../java/org/jooq/util/AbstractGenerator.java | 11 +++ .../java/org/jooq/util/GenerationTool.java | 11 +++ .../main/java/org/jooq/util/Generator.java | 16 ++++ .../java/org/jooq/util/JavaGenerator.java | 75 +++++++++++++++---- .../main/resources/xsd/jooq-codegen-3.9.0.xsd | 8 ++ 5 files changed, 105 insertions(+), 16 deletions(-) diff --git a/jOOQ-codegen/src/main/java/org/jooq/util/AbstractGenerator.java b/jOOQ-codegen/src/main/java/org/jooq/util/AbstractGenerator.java index a11ec58c0c..e5e0b014f2 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/util/AbstractGenerator.java +++ b/jOOQ-codegen/src/main/java/org/jooq/util/AbstractGenerator.java @@ -93,6 +93,7 @@ abstract class AbstractGenerator implements Generator { boolean generateGlobalLinkReferences = true; boolean fluentSetters = false; String generateFullyQualifiedTypes = ""; + boolean generateJavaTimeTypes = false; boolean generateTableValuedFunctions = false; boolean generateEmptyCatalogs = false; boolean generateEmptySchemas = false; @@ -541,6 +542,16 @@ abstract class AbstractGenerator implements Generator { this.generateFullyQualifiedTypes = generateFullyQualifiedTypes; } + @Override + public boolean generateJavaTimeTypes() { + return generateJavaTimeTypes; + } + + @Override + public void setGenerateJavaTimeTypes(boolean generateJavaTimeTypes) { + this.generateJavaTimeTypes = generateJavaTimeTypes; + } + @Override public boolean generateEmptyCatalogs() { return generateEmptyCatalogs; diff --git a/jOOQ-codegen/src/main/java/org/jooq/util/GenerationTool.java b/jOOQ-codegen/src/main/java/org/jooq/util/GenerationTool.java index f9e612cd88..9566607805 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/util/GenerationTool.java +++ b/jOOQ-codegen/src/main/java/org/jooq/util/GenerationTool.java @@ -562,6 +562,8 @@ public class GenerationTool { generator.setGeneratePojosToString(g.getGenerate().isPojosToString()); if (g.getGenerate().getFullyQualifiedTypes() != null) generator.setGenerateFullyQualifiedTypes(g.getGenerate().getFullyQualifiedTypes()); + if (g.getGenerate().isJavaTimeTypes() != null) + generator.setGenerateJavaTimeTypes(g.getGenerate().isJavaTimeTypes()); if (g.getGenerate().isEmptyCatalogs() != null) generator.setGenerateEmptyCatalogs(g.getGenerate().isEmptyCatalogs()); if (g.getGenerate().isEmptySchemas() != null) @@ -592,6 +594,15 @@ public class GenerationTool { strategy.setInstanceFields(generator.generateInstanceFields()); + if (true) + ; + else + + if (g.getGenerate().isJavaTimeTypes() != null) { + log.warn("INVALID CONFIG", "The java.time API cannot be used in the Java 6 distribution of jOOQ 3.9+"); + generator.setGenerateJavaTimeTypes(false); + } + generator.generate(database); } finally { diff --git a/jOOQ-codegen/src/main/java/org/jooq/util/Generator.java b/jOOQ-codegen/src/main/java/org/jooq/util/Generator.java index 382f5d25ec..0b73ba7f8f 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/util/Generator.java +++ b/jOOQ-codegen/src/main/java/org/jooq/util/Generator.java @@ -429,6 +429,22 @@ public interface Generator { */ void setGenerateFullyQualifiedTypes(String generateFullyQualifiedTypes); + /** + * A flag indicating whether Java 8's java.time types should be used by the + * source code generator, rather than JDBC's java.sql types. + *

+ * This flag is ignored in the commercial Java 6 distribution of jOOQ 3.9+ + */ + boolean generateJavaTimeTypes(); + + /** + * A flag indicating whether Java 8's java.time types should be used by the + * source code generator, rather than JDBC's java.sql types. + *

+ * This flag is ignored in the commercial Java 6 distribution of jOOQ 3.9+ + */ + void setGenerateJavaTimeTypes(boolean generateJavaTimeTypes); + /** * Whether empty catalogs should still be generated. */ 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 99de387f8f..e612276f63 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java +++ b/jOOQ-codegen/src/main/java/org/jooq/util/JavaGenerator.java @@ -54,13 +54,18 @@ import static org.jooq.util.GenerationUtil.convertToIdentifier; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.lang.reflect.Modifier; import java.lang.reflect.TypeVariable; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -140,57 +145,78 @@ import org.jooq.util.postgres.PostgresDatabase; */ public class JavaGenerator extends AbstractGenerator { - private static final JooqLogger log = JooqLogger.getLogger(JavaGenerator.class); + private static final JooqLogger log = JooqLogger.getLogger(JavaGenerator.class); /** * The Javadoc to be used for private constructors */ - private static final String NO_FURTHER_INSTANCES_ALLOWED = "No further instances allowed"; + private static final String NO_FURTHER_INSTANCES_ALLOWED = "No further instances allowed"; /** * [#1459] Prevent large static initialisers by splitting nested classes */ - private static final int INITIALISER_SIZE = 500; + private static final int INITIALISER_SIZE = 500; + + /** + * [#4429] A map providing access to SQLDataType member literals + */ + private static final Map, String> SQLDATATYPE_LITERAL_LOOKUP; /** * An overall stop watch to measure the speed of source code generation */ - private final StopWatch watch = new StopWatch(); + private final StopWatch watch = new StopWatch(); /** * The underlying database of this generator */ - private Database database; + private Database database; /** * The code generation date, if needed. */ - private String isoDate; + private String isoDate; /** * The cached schema version numbers. */ - private Map schemaVersions; + private Map schemaVersions; /** * The cached catalog version numbers. */ - private Map catalogVersions; + private Map catalogVersions; /** * All files modified by this generator. */ - private Set files = new LinkedHashSet(); + private Set files = new LinkedHashSet(); /** * These directories were not modified by this generator, but flagged as not * for removal (e.g. because of {@link #schemaVersions} or * {@link #catalogVersions}). */ - private Set directoriesNotForRemoval = new LinkedHashSet(); + private Set directoriesNotForRemoval = new LinkedHashSet(); - private final boolean scala; - private final String tokenVoid; + private final boolean scala; + private final String tokenVoid; + + static { + SQLDATATYPE_LITERAL_LOOKUP = new IdentityHashMap, String>(); + + try { + for (java.lang.reflect.Field f : SQLDataType.class.getFields()) { + if (Modifier.isPublic(f.getModifiers()) && + Modifier.isStatic(f.getModifiers()) && + Modifier.isFinal(f.getModifiers())) + SQLDATATYPE_LITERAL_LOOKUP.put((DataType) f.get(SQLDataType.class), f.getName()); + } + } + catch (Exception e) { + log.warn(e); + } + } public JavaGenerator() { this(JAVA); @@ -5233,7 +5259,7 @@ public class JavaGenerator extends AbstractGenerator { // Try finding a basic standard SQL type according to the current dialect else { try { - Class clazz = DefaultDataType.getType(db.getDialect(), t, p, s); + Class clazz = mapJavaTimeTypes(DefaultDataType.getDataType(db.getDialect(), t, p, s)).getType(); if (scala && clazz == byte[].class) type = "scala.Array[scala.Byte]"; else @@ -5306,7 +5332,7 @@ public class JavaGenerator extends AbstractGenerator { DataType dataType = null; try { - dataType = DefaultDataType.getDataType(db.getDialect(), t, p, s).nullable(n); + dataType = mapJavaTimeTypes(DefaultDataType.getDataType(db.getDialect(), t, p, s)).nullable(n); if (d != null) dataType = dataType.defaultValue((Field) DSL.field(d, dataType)); @@ -5320,10 +5346,11 @@ public class JavaGenerator extends AbstractGenerator { // specific DataType t, then reference that one. if (dataType != null && dataType.getSQLDataType() != null) { DataType sqlDataType = dataType.getSQLDataType(); + String literal = SQLDATATYPE_LITERAL_LOOKUP.get(sqlDataType); String sqlDataTypeRef = SQLDataType.class.getCanonicalName() + '.' - + DefaultDataType.normalise(sqlDataType.getTypeName()); + + literal; sb.append(sqlDataTypeRef); @@ -5387,7 +5414,7 @@ public class JavaGenerator extends AbstractGenerator { sb.append(typeName); if (!type1.equals(type2)) { - Class clazz = DefaultDataType.getType(db.getDialect(), t, p, s); + Class clazz = mapJavaTimeTypes(DefaultDataType.getDataType(db.getDialect(), t, p, s)).getType(); sb.append(".asNumberDataType("); sb.append(classOf(clazz.getCanonicalName())); @@ -5420,6 +5447,22 @@ public class JavaGenerator extends AbstractGenerator { return sb.toString(); } + private DataType mapJavaTimeTypes(DataType dataType) { + DataType result = dataType; + + // [#4429] [#5713] This logic should be implemented in Configuration + if (dataType.isDateTime() && generateJavaTimeTypes) { + if (dataType.getType() == Date.class) + result = SQLDataType.LOCALDATE; + else if (dataType.getType() == Time.class) + result = SQLDataType.LOCALTIME; + else if (dataType.getType() == Timestamp.class) + result = SQLDataType.LOCALDATETIME; + } + + return result; + } + protected boolean match(DataTypeDefinition type1, DataTypeDefinition type2) { return getJavaType(type1).equals(getJavaType(type2)); } diff --git a/jOOQ-meta/src/main/resources/xsd/jooq-codegen-3.9.0.xsd b/jOOQ-meta/src/main/resources/xsd/jooq-codegen-3.9.0.xsd index b2219428ef..7c0392a5fa 100644 --- a/jOOQ-meta/src/main/resources/xsd/jooq-codegen-3.9.0.xsd +++ b/jOOQ-meta/src/main/resources/xsd/jooq-codegen-3.9.0.xsd @@ -978,6 +978,14 @@ be generated. --> + + +