/*
* 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
*
* http://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
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.codegen;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.tools.StringUtils.defaultIfNull;
import static org.jooq.tools.StringUtils.defaultString;
import static org.jooq.tools.StringUtils.isBlank;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import javax.sql.DataSource;
import org.jooq.Constants;
import org.jooq.DSLContext;
import org.jooq.Log.Level;
import org.jooq.impl.DSL;
import org.jooq.meta.CatalogVersionProvider;
import org.jooq.meta.Database;
import org.jooq.meta.Databases;
import org.jooq.meta.Definition;
import org.jooq.meta.SchemaVersionProvider;
import org.jooq.meta.jaxb.CatalogMappingType;
import org.jooq.meta.jaxb.Configuration;
import org.jooq.meta.jaxb.Generate;
import org.jooq.meta.jaxb.Jdbc;
import org.jooq.meta.jaxb.Logging;
import org.jooq.meta.jaxb.Matchers;
import org.jooq.meta.jaxb.OnError;
import org.jooq.meta.jaxb.Property;
import org.jooq.meta.jaxb.SchemaMappingType;
import org.jooq.meta.jaxb.Strategy;
import org.jooq.meta.jaxb.Target;
// ...
import org.jooq.tools.JooqLogger;
import org.jooq.tools.StringUtils;
import org.jooq.tools.jdbc.JDBCUtils;
import org.jooq.util.jaxb.tools.MiniJAXB;
The GenerationTool takes care of generating Java code from a database schema.
It takes its configuration parameters from an XML file passed in either as a JAXB-annotated Configuration
object, or from the file system when passed as an argument to main(String[])
.
See http://www.jooq.org/xsd/ for the
latest XSD specification.
Author: Lukas Eder
/**
* The GenerationTool takes care of generating Java code from a database schema.
* <p>
* It takes its configuration parameters from an XML file passed in either as a
* JAXB-annotated {@link Configuration} object, or from the file system when
* passed as an argument to {@link #main(String[])}.
* <p>
* See <a href="http://www.jooq.org/xsd/">http://www.jooq.org/xsd/</a> for the
* latest XSD specification.
*
* @author Lukas Eder
*/
public class GenerationTool {
public static final String DEFAULT_TARGET_ENCODING = "UTF-8";
public static final String DEFAULT_TARGET_DIRECTORY = "target/generated-sources/jooq";
public static final String DEFAULT_TARGET_PACKAGENAME = "org.jooq.generated";
private static final JooqLogger log = JooqLogger.getLogger(GenerationTool.class);
private static final JooqLogger unusedLogger = JooqLogger.getLogger(Unused.class);
private static class Unused {}
private ClassLoader loader;
private DataSource dataSource;
private Connection connection;
private DSLContext ctx;
private Boolean autoCommit;
private boolean close;
The class loader to use with this generation tool.
If set, all classes are loaded with this class loader
/**
* The class loader to use with this generation tool.
* <p>
* If set, all classes are loaded with this class loader
*/
public void setClassLoader(ClassLoader loader) {
this.loader = loader;
}
The JDBC connection to use with this generation tool.
If set, the configuration XML's <jdbc/>
configuration is
ignored, and this connection is used for meta data inspection, instead.
/**
* The JDBC connection to use with this generation tool.
* <p>
* If set, the configuration XML's <code><jdbc/></code> configuration is
* ignored, and this connection is used for meta data inspection, instead.
*/
public void setConnection(Connection connection) {
this.connection = connection;
this.ctx = DSL.using(connection);
}
The JDBC data source to use with this generation tool.
If set, the configuration XML's <jdbc/>
configuration is
ignored, and this connection is used for meta data inspection, instead.
/**
* The JDBC data source to use with this generation tool.
* <p>
* If set, the configuration XML's <code><jdbc/></code> configuration is
* ignored, and this connection is used for meta data inspection, instead.
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public static void main(String[] args) throws Exception {
String[] files;
if (args.length > 0) {
files = args;
}
else {
String property = System.getProperty("jooq.codegen.configurationFile");
if (property != null) {
files = new String[] { property };
}
else {
log.error("Usage : GenerationTool <configuration-file>");
System.exit(-1);
return;
}
}
for (String file : files) {
InputStream in = GenerationTool.class.getResourceAsStream(file);
try {
// [#2932] Retry loading the file, if it wasn't found. This may be helpful
// to some users who were unaware that this file is loaded from the classpath
if (in == null && !file.startsWith("/"))
in = GenerationTool.class.getResourceAsStream("/" + file);
// [#3668] Also check the local file system for configuration files
if (in == null && new File(file).exists())
in = new FileInputStream(new File(file));
if (in == null) {
log.error("Cannot find " + file + " on classpath, or in directory " + new File(".").getCanonicalPath());
log.error("-----------");
log.error("Please be sure it is located");
log.error(" - on the classpath and qualified as a classpath location.");
log.error(" - in the local directory or at a global path in the file system.");
System.exit(-1);
return;
}
// [#10463] Make sure logging threshold is set, in this special case
Configuration configuration = load(in);
setGlobalLoggingThreshold(configuration);
log.info("Initialising properties", file);
generate(configuration);
}
catch (Exception e) {
log.error("Error in file: " + file + ". Error : " + e.getMessage(), e);
System.exit(-1);
return;
}
finally {
if (in != null)
in.close();
}
}
}
Deprecated: - Use generate(Configuration)
instead
/**
* @deprecated - Use {@link #generate(Configuration)} instead
*/
@Deprecated
public static void main(Configuration configuration) throws Exception {
new GenerationTool().run(configuration);
}
public static void generate(String xml) throws Exception {
new GenerationTool().run(load(new ByteArrayInputStream(xml.getBytes(DEFAULT_TARGET_ENCODING))));
}
public static void generate(Configuration configuration) throws Exception {
new GenerationTool().run(configuration);
}
public void run(Configuration configuration) throws Exception {
try {
run0(configuration);
}
catch (Exception e) {
OnError onError = configuration.getOnError();
if (onError == null) {
onError = OnError.FAIL;
}
switch (onError) {
case SILENT:
break;
case LOG:
log.warn("Code generation failed", e);
break;
case FAIL:
throw e;
}
}
}
@SuppressWarnings({ "unchecked", "unused" })
private void run0(Configuration configuration) throws Exception {
if (configuration.getLogging() != null) {
setGlobalLoggingThreshold(configuration);
}
else {
String property = System.getProperty("jooq.codegen.logging");
if (property != null) {
try {
Logging.valueOf(property);
}
catch (IllegalArgumentException e) {
log.error("Unsupported property", "Unsupported value for system property jooq.codegen.logging: " + property + ". Supported values include: " + Arrays.asList(Logging.values()));
}
}
}
if (Boolean.getBoolean("jooq.codegen.skip")) {
log.info("Skipping jOOQ code generation");
return;
}
if (log.isDebugEnabled())
log.debug("Input configuration", "" + configuration);
// [#9727] The Maven plugin will have set the basedir to Maven's ${basedir}.
// Standalone code generation should use the JVM's working dir as basedir, by default.
if (configuration.getBasedir() == null)
configuration.setBasedir(new File(".").getAbsolutePath());
Jdbc j = configuration.getJdbc();
org.jooq.meta.jaxb.Generator g = configuration.getGenerator();
if (g == null)
throw new GeneratorException("The <generator/> tag is mandatory. For details, see " + Constants.NS_CODEGEN);
// [#3669] Optional Database element
if (g.getDatabase() == null)
g.setDatabase(new org.jooq.meta.jaxb.Database());
org.jooq.meta.jaxb.Database d = g.getDatabase();
String databaseName = trim(d.getName());
// [#1394] The <generate/> element and some others should be optional
if (g.getGenerate() == null)
g.setGenerate(new Generate());
if (g.getStrategy() == null)
g.setStrategy(new Strategy());
if (g.getTarget() == null)
g.setTarget(new Target());
// [#9744] The <locale/> is also needed in GenerationTool:
Locale locale = Locale.getDefault();
if (!StringUtils.isBlank(g.getTarget().getLocale()))
if (true)
locale = Locale.forLanguageTag(g.getTarget().getLocale());
else
log.info("Locale support", "Locale support has been added for the Java 8+ distributions only");
Database database = null;
try {
// Initialise connection
// ---------------------
if (connection == null) {
close = true;
if (dataSource != null) {
setConnection(dataSource.getConnection());
}
else {
String url = System.getProperty("jooq.codegen.jdbc.url");
if (url != null) {
j = defaultIfNull(j, new Jdbc());
if (j.getDriver() == null)
j.setDriver(System.getProperty("jooq.codegen.jdbc.driver"));
if (j.getUrl() == null)
j.setUrl(url);
if (j.getUser() == null)
j.setUser(System.getProperty("jooq.codegen.jdbc.user"));
if (j.getUsername() == null)
j.setUsername(System.getProperty("jooq.codegen.jdbc.username"));
if (j.getPassword() == null)
j.setPassword(System.getProperty("jooq.codegen.jdbc.password"));
if (j.isAutoCommit() == null) {
String a = System.getProperty("jooq.codegen.jdbc.autoCommit");
if (a != null)
j.setAutoCommit(Boolean.valueOf(a));
}
}
if (j != null) {
try {
Class<? extends Driver> driver = (Class<? extends Driver>) loadClass(driverClass(j));
Properties properties = properties(j.getProperties());
if (!properties.containsKey("user"))
properties.put("user", defaultString(defaultString(j.getUser(), j.getUsername())));
if (!properties.containsKey("password"))
properties.put("password", defaultString(j.getPassword()));
setConnection(driver.newInstance().connect(defaultString(j.getUrl()), properties));
}
catch (Exception e) {
if (databaseName != null)
if (databaseName.contains("DDLDatabase") || databaseName.contains("XMLDatabase") || databaseName.contains("JPADatabase"))
log.warn("Error while connecting to database. Note that file based database implementations do not need a <jdbc/> configuration in the code generator.", e);
throw e;
}
}
}
}
j = defaultIfNull(j, new Jdbc());
if (connection != null && j.isAutoCommit() != null) {
autoCommit = connection.getAutoCommit();
connection.setAutoCommit(j.isAutoCommit());
}
// Initialise generator
// --------------------
Class<Generator> generatorClass = (Class<Generator>) (!isBlank(g.getName())
? loadClass(trim(g.getName()))
: JavaGenerator.class);
Generator generator = generatorClass.newInstance();
GeneratorStrategy strategy;
Matchers matchers = g.getStrategy().getMatchers();
if (matchers != null) {
strategy = new MatcherStrategy(matchers);
if (g.getStrategy().getName() != null) {
// [#7416] Depending on who is unmarshalling the Configuration (Maven / JAXB),
// the XSD's default value might apply, which we can safely ignore.
if (!DefaultGeneratorStrategy.class.getName().equals(g.getStrategy().getName()))
log.warn("WARNING: Matchers take precedence over custom strategy. Strategy ignored: " +
g.getStrategy().getName());
g.getStrategy().setName(null);
}
}
else {
Class<GeneratorStrategy> strategyClass = (Class<GeneratorStrategy>) (!isBlank(g.getStrategy().getName())
? loadClass(trim(g.getStrategy().getName()))
: DefaultGeneratorStrategy.class);
strategy = strategyClass.newInstance();
}
generator.setStrategy(strategy);
Class<? extends Database> databaseClass = !isBlank(databaseName)
? (Class<? extends Database>) loadClass(databaseName)
: connection != null
? databaseClass(connection)
: databaseClass(j);
database = databaseClass.newInstance();
database.setBasedir(configuration.getBasedir());
database.setProperties(properties(d.getProperties()));
database.setOnError(configuration.getOnError());
List<CatalogMappingType> catalogs = d.getCatalogs();
List<SchemaMappingType> schemata = d.getSchemata();
boolean catalogsEmpty = catalogs.isEmpty();
boolean schemataEmpty = schemata.isEmpty();
// For convenience, the catalog configuration can be set also directly in the <database/> element
if (catalogsEmpty) {
if (isBlank(d.getInputCatalog()) && !isBlank(d.getOutputCatalog()))
log.warn("WARNING: /configuration/generator/database/outputCatalog must be paired with /configuration/generator/database/inputCatalog");
CatalogMappingType catalog = new CatalogMappingType();
catalog.setInputCatalog(trim(d.getInputCatalog()));
catalog.setOutputCatalog(trim(d.getOutputCatalog()));
catalog.setOutputCatalogToDefault(d.isOutputCatalogToDefault());
catalogs.add(catalog);
if (!isBlank(catalog.getInputCatalog()))
catalogsEmpty = false;
// For convenience and backwards-compatibility, the schema configuration can be set also directly
// in the <database/> element
if (schemataEmpty) {
if (isBlank(d.getInputSchema()) && !isBlank(d.getOutputSchema()))
log.warn("WARNING: /configuration/generator/database/outputSchema must be paired with /configuration/generator/database/inputSchema");
SchemaMappingType schema = new SchemaMappingType();
schema.setInputSchema(trim(d.getInputSchema()));
schema.setOutputSchema(trim(d.getOutputSchema()));
schema.setOutputSchemaToDefault(d.isOutputSchemaToDefault());
catalog.getSchemata().add(schema);
if (!isBlank(schema.getInputSchema()))
schemataEmpty = false;
}
else {
catalog.getSchemata().addAll(schemata);
if (!isBlank(d.getInputSchema()))
log.warn("WARNING: Cannot combine configuration properties /configuration/generator/database/inputSchema and /configuration/generator/database/schemata");
if (!isBlank(d.getOutputSchema()))
log.warn("WARNING: Cannot combine configuration properties /configuration/generator/database/outputSchema and /configuration/generator/database/schemata");
}
}
else {
if (!isBlank(d.getInputCatalog()))
log.warn("WARNING: Cannot combine configuration properties /configuration/generator/database/inputCatalog and /configuration/generator/database/catalogs");
if (!isBlank(d.getOutputCatalog()))
log.warn("WARNING: Cannot combine configuration properties /configuration/generator/database/outputCatalog and /configuration/generator/database/catalogs");
if (!isBlank(d.getInputSchema()))
log.warn("WARNING: Cannot combine configuration properties /configuration/generator/database/inputSchema and /configuration/generator/database/catalogs");
if (!isBlank(d.getOutputSchema()))
log.warn("WARNING: Cannot combine configuration properties /configuration/generator/database/outputSchema and /configuration/generator/database/catalogs");
if (!schemataEmpty)
log.warn("WARNING: Cannot combine configuration properties /configuration/generator/database/catalogs and /configuration/generator/database/schemata");
}
for (CatalogMappingType catalog : catalogs) {
if ("".equals(catalog.getOutputCatalog()))
log.warn("WARNING: Empty <outputCatalog/> should not be used to model default outputCatalogs. Use <outputCatalogToDefault>true</outputCatalogToDefault>, instead. See also: https://github.com/jOOQ/jOOQ/issues/3018");
// [#3018] If users want the output catalog to be "" then, ignore the actual <outputCatalog/> configuration
if (TRUE.equals(catalog.isOutputCatalogToDefault()))
catalog.setOutputCatalog("");
else if (catalog.getOutputCatalog() == null)
catalog.setOutputCatalog(trim(catalog.getInputCatalog()));
for (SchemaMappingType schema : catalog.getSchemata()) {
if (catalogsEmpty && schemataEmpty && isBlank(schema.getInputSchema())) {
if (!isBlank(j.getSchema()))
log.warn("WARNING: The configuration property jdbc.Schema is deprecated and will be removed in the future. Use /configuration/generator/database/inputSchema instead");
schema.setInputSchema(trim(j.getSchema()));
}
// [#3018] Prior to <outputSchemaToDefault/>, empty <outputSchema/> elements meant that
// the outputSchema should be the default schema. This is a bit too clever, and doesn't
// work when Maven parses the XML configurations.
if ("".equals(schema.getOutputSchema()))
log.warn("WARNING: Empty <outputSchema/> should not be used to model default outputSchemas. Use <outputSchemaToDefault>true</outputSchemaToDefault>, instead. See also: https://github.com/jOOQ/jOOQ/issues/3018");
// [#3018] If users want the output schema to be "" then, ignore the actual <outputSchema/> configuration
if (TRUE.equals(schema.isOutputSchemaToDefault()))
schema.setOutputSchema("");
else if (schema.getOutputSchema() == null)
schema.setOutputSchema(trim(schema.getInputSchema()));
}
}
if (catalogsEmpty)
log.info("No <inputCatalog/> was provided. Generating ALL available catalogs instead.");
if (catalogsEmpty && schemataEmpty)
log.info("No <inputSchema/> was provided. Generating ALL available schemata instead.");
database.setConnection(connection);
database.setConfiguredCatalogs(catalogs);
database.setConfiguredSchemata(schemata);
database.setIncludes(new String[] { defaultString(d.getIncludes()) });
database.setExcludes(new String[] { defaultString(d.getExcludes()) });
database.setIncludeExcludeColumns(TRUE.equals(d.isIncludeExcludeColumns()));
database.setIncludeForeignKeys(!FALSE.equals(d.isIncludeForeignKeys()));
database.setIncludePackages(!FALSE.equals(d.isIncludePackages()));
database.setIncludePackageRoutines(!FALSE.equals(d.isIncludePackageRoutines()));
database.setIncludePackageUDTs(!FALSE.equals(d.isIncludePackageUDTs()));
database.setIncludePackageConstants(!FALSE.equals(d.isIncludePackageConstants()));
database.setIncludeIndexes(!FALSE.equals(d.isIncludeIndexes()));
database.setIncludeCheckConstraints(!FALSE.equals(d.isIncludeCheckConstraints()));
database.setIncludeSystemIndexes(TRUE.equals(d.isIncludeSystemIndexes()));
database.setIncludeSystemCheckConstraints(TRUE.equals(d.isIncludeSystemCheckConstraints()));
database.setIncludeInvisibleColumns(!FALSE.equals(d.isIncludeInvisibleColumns()));
database.setIncludePrimaryKeys(!FALSE.equals(d.isIncludePrimaryKeys()));
database.setIncludeRoutines(!FALSE.equals(d.isIncludeRoutines()));
database.setIncludeDomains(!FALSE.equals(d.isIncludeDomains()));
database.setIncludeSequences(!FALSE.equals(d.isIncludeSequences()));
database.setIncludeTables(!FALSE.equals(d.isIncludeTables()));
database.setIncludeEmbeddables(!FALSE.equals(d.isIncludeEmbeddables()));
database.setIncludeTriggerRoutines(TRUE.equals(d.isIncludeTriggerRoutines()));
database.setIncludeUDTs(!FALSE.equals(d.isIncludeUDTs()));
database.setIncludeUniqueKeys(!FALSE.equals(d.isIncludeUniqueKeys()));
database.setForceIntegerTypesOnZeroScaleDecimals(!FALSE.equals(d.isForceIntegerTypesOnZeroScaleDecimals()));
database.setRecordVersionFields(new String[] { defaultString(d.getRecordVersionFields()) });
database.setRecordTimestampFields(new String[] { defaultString(d.getRecordTimestampFields()) });
database.setSyntheticPrimaryKeys(new String[] { defaultString(d.getSyntheticPrimaryKeys()) });
database.setOverridePrimaryKeys(new String[] { defaultString(d.getOverridePrimaryKeys()) });
database.setSyntheticIdentities(new String[] { defaultString(d.getSyntheticIdentities()) });
database.setConfiguredCustomTypes(d.getCustomTypes());
database.setConfiguredEnumTypes(d.getEnumTypes());
database.setConfiguredForcedTypes(d.getForcedTypes());
database.setConfiguredEmbeddables(d.getEmbeddables());
database.setConfiguredSyntheticObjects(d.getSyntheticObjects());
database.setEmbeddablePrimaryKeys(d.getEmbeddablePrimaryKeys());
database.setEmbeddableUniqueKeys(d.getEmbeddableUniqueKeys());
database.setEmbeddableDomains(d.getEmbeddableDomains());
database.setLogSlowQueriesAfterSeconds(defaultIfNull(d.getLogSlowQueriesAfterSeconds(), 5));
database.setLogSlowResultsAfterSeconds(defaultIfNull(d.getLogSlowResultsAfterSeconds(), 5));
if (d.getRegexFlags() != null) {
database.setRegexFlags(d.getRegexFlags());
if (strategy instanceof MatcherStrategy) {
((MatcherStrategy) strategy).getPatterns().setRegexFlags(d.getRegexFlags());
}
}
database.setRegexMatchesPartialQualification(!FALSE.equals(d.isRegexMatchesPartialQualification()));
database.setSqlMatchesPartialQualification(!FALSE.equals(d.isSqlMatchesPartialQualification()));
SchemaVersionProvider svp = null;
CatalogVersionProvider cvp = null;
if (!isBlank(d.getSchemaVersionProvider())) {
try {
svp = (SchemaVersionProvider) Class.forName(d.getSchemaVersionProvider()).newInstance();
log.info("Using custom schema version provider : " + svp);
}
catch (Exception ignore) {
if (d.getSchemaVersionProvider().toLowerCase(locale).startsWith("select")) {
svp = new SQLSchemaVersionProvider(connection, d.getSchemaVersionProvider());
log.info("Using SQL schema version provider : " + d.getSchemaVersionProvider());
}
else {
svp = new ConstantSchemaVersionProvider(d.getSchemaVersionProvider());
}
}
}
if (!isBlank(d.getCatalogVersionProvider())) {
try {
cvp = (CatalogVersionProvider) Class.forName(d.getCatalogVersionProvider()).newInstance();
log.info("Using custom catalog version provider : " + cvp);
}
catch (Exception ignore) {
if (d.getCatalogVersionProvider().toLowerCase(locale).startsWith("select")) {
cvp = new SQLCatalogVersionProvider(connection, d.getCatalogVersionProvider());
log.info("Using SQL catalog version provider : " + d.getCatalogVersionProvider());
}
else {
cvp = new ConstantCatalogVersionProvider(d.getCatalogVersionProvider());
}
}
}
if (svp == null)
svp = new ConstantSchemaVersionProvider(null);
if (cvp == null)
cvp = new ConstantCatalogVersionProvider(null);
database.setSchemaVersionProvider(svp);
database.setCatalogVersionProvider(cvp);
if (!isBlank(d.getOrderProvider())) {
Class<?> orderProvider = Class.forName(d.getOrderProvider());
if (Comparator.class.isAssignableFrom(orderProvider))
database.setOrderProvider((Comparator<Definition>) orderProvider.newInstance());
else
log.warn("Order provider must be of type java.util.Comparator: " + orderProvider);
}
if (d.getEnumTypes().size() > 0)
log.warn("DEPRECATED", "The configuration property /configuration/generator/database/enumTypes is experimental and deprecated and will be removed in the future.");
if (Boolean.TRUE.equals(d.isDateAsTimestamp()))
log.warn("DEPRECATED", "The configuration property /configuration/generator/database/dateAsTimestamp is deprecated as it is superseded by custom bindings and converters. It will thus be removed in the future.");
if (d.isDateAsTimestamp() != null)
database.setDateAsTimestamp(d.isDateAsTimestamp());
if (g.getGenerate().isJavaTimeTypes() != null)
database.setJavaTimeTypes(g.getGenerate().isJavaTimeTypes());
if (d.isUnsignedTypes() != null)
database.setSupportsUnsignedTypes(d.isUnsignedTypes());
if (d.isIntegerDisplayWidths() != null)
database.setIntegerDisplayWidths(d.isIntegerDisplayWidths());
if (d.isIgnoreProcedureReturnValues() != null)
database.setIgnoreProcedureReturnValues(d.isIgnoreProcedureReturnValues());
if (Boolean.TRUE.equals(d.isIgnoreProcedureReturnValues()))
log.warn("DEPRECATED", "The <ignoreProcedureReturnValues/> flag is deprecated and used for backwards-compatibility only. It will be removed in the future.");
if (isBlank(g.getTarget().getPackageName()))
g.getTarget().setPackageName(DEFAULT_TARGET_PACKAGENAME);
if (isBlank(g.getTarget().getDirectory()))
g.getTarget().setDirectory(DEFAULT_TARGET_DIRECTORY);
if (isBlank(g.getTarget().getEncoding()))
g.getTarget().setEncoding(DEFAULT_TARGET_ENCODING);
// [#2887] [#9727] Patch relative paths to take plugin execution basedir into account
if (!new File(g.getTarget().getDirectory()).isAbsolute())
g.getTarget().setDirectory(new File(configuration.getBasedir(), g.getTarget().getDirectory()).getCanonicalPath());
generator.setTargetPackage(g.getTarget().getPackageName());
generator.setTargetDirectory(g.getTarget().getDirectory());
generator.setTargetEncoding(g.getTarget().getEncoding());
if (g.getTarget().isClean() != null)
generator.setTargetClean(g.getTarget().isClean());
generator.setTargetLocale(locale);
if (g.getGenerate().isIndexes() != null)
generator.setGenerateIndexes(g.getGenerate().isIndexes());
if (g.getGenerate().isRelations() != null)
generator.setGenerateRelations(g.getGenerate().isRelations());
if (g.getGenerate().isImplicitJoinPathsToOne() != null)
generator.setGenerateImplicitJoinPathsToOne(g.getGenerate().isImplicitJoinPathsToOne());
if (g.getGenerate().isDeprecated() != null)
generator.setGenerateDeprecated(g.getGenerate().isDeprecated());
if (g.getGenerate().isDeprecationOnUnknownTypes() != null)
generator.setGenerateDeprecationOnUnknownTypes(g.getGenerate().isDeprecationOnUnknownTypes());
if (g.getGenerate().isInstanceFields() != null)
generator.setGenerateInstanceFields(g.getGenerate().isInstanceFields());
if (g.getGenerate().isGeneratedAnnotation() != null)
generator.setGenerateGeneratedAnnotation(g.getGenerate().isGeneratedAnnotation());
if (g.getGenerate().getGeneratedAnnotationType() != null)
generator.setGenerateGeneratedAnnotationType(g.getGenerate().getGeneratedAnnotationType());
if (g.getGenerate().isGeneratedAnnotationDate() != null)
generator.setGenerateGeneratedAnnotationDate(g.getGenerate().isGeneratedAnnotationDate());
if (g.getGenerate().isNonnullAnnotation() != null)
generator.setGenerateNonnullAnnotation(g.getGenerate().isNonnullAnnotation());
if (g.getGenerate().getNonnullAnnotationType() != null)
generator.setGeneratedNonnullAnnotationType(g.getGenerate().getNonnullAnnotationType());
if (g.getGenerate().isNullableAnnotation() != null)
generator.setGenerateNullableAnnotation(g.getGenerate().isNullableAnnotation());
if (g.getGenerate().getNullableAnnotationType() != null)
generator.setGeneratedNullableAnnotationType(g.getGenerate().getNullableAnnotationType());
if (g.getGenerate().isConstructorPropertiesAnnotation() != null)
generator.setGenerateConstructorPropertiesAnnotation(g.getGenerate().isConstructorPropertiesAnnotation());
if (g.getGenerate().isConstructorPropertiesAnnotationOnPojos() != null)
generator.setGenerateConstructorPropertiesAnnotationOnPojos(g.getGenerate().isConstructorPropertiesAnnotationOnPojos());
if (g.getGenerate().isConstructorPropertiesAnnotationOnRecords() != null)
generator.setGenerateConstructorPropertiesAnnotationOnRecords(g.getGenerate().isConstructorPropertiesAnnotationOnRecords());
if (g.getGenerate().isRoutines() != null)
generator.setGenerateRoutines(g.getGenerate().isRoutines());
if (g.getGenerate().isSequences() != null)
generator.setGenerateSequences(g.getGenerate().isSequences());
if (g.getGenerate().isSequenceFlags() != null)
generator.setGenerateSequenceFlags(g.getGenerate().isSequenceFlags());
if (g.getGenerate().isUdts() != null)
generator.setGenerateUDTs(g.getGenerate().isUdts());
if (g.getGenerate().isTables() != null)
generator.setGenerateTables(g.getGenerate().isTables());
if (g.getGenerate().isEmbeddables() != null)
generator.setGenerateEmbeddables(g.getGenerate().isEmbeddables());
if (g.getGenerate().isRecords() != null)
generator.setGenerateRecords(g.getGenerate().isRecords());
if (g.getGenerate().isRecordsImplementingRecordN() != null)
generator.setGenerateRecordsImplementingRecordN(g.getGenerate().isRecordsImplementingRecordN());
if (g.getGenerate().isPojos() != null)
generator.setGeneratePojos(g.getGenerate().isPojos());
if (g.getGenerate().isPojosAsJavaRecordClasses() != null)
generator.setGeneratePojosAsJavaRecordClasses(g.getGenerate().isPojosAsJavaRecordClasses());
if (g.getGenerate().isPojosAsScalaCaseClasses() != null)
generator.setGeneratePojosAsScalaCaseClasses(g.getGenerate().isPojosAsScalaCaseClasses());
if (g.getGenerate().isPojosAsKotlinDataClasses() != null)
generator.setGeneratePojosAsKotlinDataClasses(g.getGenerate().isPojosAsKotlinDataClasses());
if (g.getGenerate().isImmutablePojos() != null)
generator.setGenerateImmutablePojos(g.getGenerate().isImmutablePojos());
if (g.getGenerate().isSerializablePojos() != null)
generator.setGenerateSerializablePojos(g.getGenerate().isSerializablePojos());
if (g.getGenerate().isInterfaces() != null)
generator.setGenerateInterfaces(g.getGenerate().isInterfaces());
if (g.getGenerate().isImmutableInterfaces() != null)
generator.setGenerateImmutableInterfaces(g.getGenerate().isImmutableInterfaces());
if (g.getGenerate().isSerializableInterfaces() != null)
generator.setGenerateSerializableInterfaces(g.getGenerate().isSerializableInterfaces());
if (g.getGenerate().isDaos() != null)
generator.setGenerateDaos(g.getGenerate().isDaos());
if (g.getGenerate().isJpaAnnotations() != null)
generator.setGenerateJPAAnnotations(g.getGenerate().isJpaAnnotations());
if (g.getGenerate().getJpaVersion() != null)
generator.setGenerateJPAVersion(g.getGenerate().getJpaVersion());
if (g.getGenerate().isValidationAnnotations() != null)
generator.setGenerateValidationAnnotations(g.getGenerate().isValidationAnnotations());
if (g.getGenerate().isSpringAnnotations() != null)
generator.setGenerateSpringAnnotations(g.getGenerate().isSpringAnnotations());
if (g.getGenerate().getGeneratedSerialVersionUID() != null)
generator.setGenerateGeneratedSerialVersionUID(g.getGenerate().getGeneratedSerialVersionUID());
if (g.getGenerate().getMaxMembersPerInitialiser() != null)
generator.setMaxMembersPerInitialiser(g.getGenerate().getMaxMembersPerInitialiser());
if (g.getGenerate().isQueues() != null)
generator.setGenerateQueues(g.getGenerate().isQueues());
if (g.getGenerate().isLinks() != null)
generator.setGenerateLinks(g.getGenerate().isLinks());
if (g.getGenerate().isKeys() != null)
generator.setGenerateKeys(g.getGenerate().isKeys());
if (g.getGenerate().isGlobalObjectReferences() != null)
generator.setGenerateGlobalObjectReferences(g.getGenerate().isGlobalObjectReferences());
if (g.getGenerate().isGlobalCatalogReferences() != null)
generator.setGenerateGlobalCatalogReferences(g.getGenerate().isGlobalCatalogReferences());
if (g.getGenerate().isGlobalDomainReferences() != null)
generator.setGenerateGlobalDomainReferences(g.getGenerate().isGlobalDomainReferences());
if (g.getGenerate().isGlobalSchemaReferences() != null)
generator.setGenerateGlobalSchemaReferences(g.getGenerate().isGlobalSchemaReferences());
if (g.getGenerate().isGlobalRoutineReferences() != null)
generator.setGenerateGlobalRoutineReferences(g.getGenerate().isGlobalRoutineReferences());
if (g.getGenerate().isGlobalSequenceReferences() != null)
generator.setGenerateGlobalSequenceReferences(g.getGenerate().isGlobalSequenceReferences());
if (g.getGenerate().isGlobalTableReferences() != null)
generator.setGenerateGlobalTableReferences(g.getGenerate().isGlobalTableReferences());
if (g.getGenerate().isGlobalUDTReferences() != null)
generator.setGenerateGlobalUDTReferences(g.getGenerate().isGlobalUDTReferences());
if (g.getGenerate().isGlobalQueueReferences() != null)
generator.setGenerateGlobalQueueReferences(g.getGenerate().isGlobalQueueReferences());
if (g.getGenerate().isGlobalLinkReferences() != null)
generator.setGenerateGlobalLinkReferences(g.getGenerate().isGlobalLinkReferences());
if (g.getGenerate().isGlobalKeyReferences() != null)
generator.setGenerateGlobalKeyReferences(g.getGenerate().isGlobalKeyReferences());
if (g.getGenerate().isGlobalIndexReferences() != null)
generator.setGenerateGlobalIndexReferences(g.getGenerate().isGlobalIndexReferences());
if (g.getGenerate().isJavadoc() != null)
generator.setGenerateJavadoc(g.getGenerate().isJavadoc());
if (g.getGenerate().isComments() != null)
generator.setGenerateComments(g.getGenerate().isComments());
if (g.getGenerate().isCommentsOnAttributes() != null)
generator.setGenerateCommentsOnAttributes(g.getGenerate().isCommentsOnAttributes());
if (g.getGenerate().isCommentsOnCatalogs() != null)
generator.setGenerateCommentsOnCatalogs(g.getGenerate().isCommentsOnCatalogs());
if (g.getGenerate().isCommentsOnColumns() != null)
generator.setGenerateCommentsOnColumns(g.getGenerate().isCommentsOnColumns());
if (g.getGenerate().isCommentsOnKeys() != null)
generator.setGenerateCommentsOnKeys(g.getGenerate().isCommentsOnKeys());
if (g.getGenerate().isCommentsOnLinks() != null)
generator.setGenerateCommentsOnLinks(g.getGenerate().isCommentsOnLinks());
if (g.getGenerate().isCommentsOnPackages() != null)
generator.setGenerateCommentsOnPackages(g.getGenerate().isCommentsOnPackages());
if (g.getGenerate().isCommentsOnParameters() != null)
generator.setGenerateCommentsOnParameters(g.getGenerate().isCommentsOnParameters());
if (g.getGenerate().isCommentsOnQueues() != null)
generator.setGenerateCommentsOnQueues(g.getGenerate().isCommentsOnQueues());
if (g.getGenerate().isCommentsOnRoutines() != null)
generator.setGenerateCommentsOnRoutines(g.getGenerate().isCommentsOnRoutines());
if (g.getGenerate().isCommentsOnSchemas() != null)
generator.setGenerateCommentsOnSchemas(g.getGenerate().isCommentsOnSchemas());
if (g.getGenerate().isCommentsOnSequences() != null)
generator.setGenerateCommentsOnSequences(g.getGenerate().isCommentsOnSequences());
if (g.getGenerate().isCommentsOnTables() != null)
generator.setGenerateCommentsOnTables(g.getGenerate().isCommentsOnTables());
if (g.getGenerate().isCommentsOnEmbeddables() != null)
generator.setGenerateCommentsOnEmbeddables(g.getGenerate().isCommentsOnEmbeddables());
if (g.getGenerate().isCommentsOnUDTs() != null)
generator.setGenerateCommentsOnUDTs(g.getGenerate().isCommentsOnUDTs());
if (g.getGenerate().isSources() != null)
generator.setGenerateSources(g.getGenerate().isSources());
if (g.getGenerate().isSourcesOnViews() != null)
generator.setGenerateSourcesOnViews(g.getGenerate().isSourcesOnViews());
if (g.getGenerate().isFluentSetters() != null)
generator.setGenerateFluentSetters(g.getGenerate().isFluentSetters());
if (g.getGenerate().isJavaBeansGettersAndSetters() != null)
generator.setGenerateJavaBeansGettersAndSetters(g.getGenerate().isJavaBeansGettersAndSetters());
if (g.getGenerate().isVarargSetters() != null)
generator.setGenerateVarargsSetters(g.getGenerate().isVarargSetters());
if (g.getGenerate().isPojosEqualsAndHashCode() != null)
generator.setGeneratePojosEqualsAndHashCode(g.getGenerate().isPojosEqualsAndHashCode());
if (g.getGenerate().isPojosToString() != null)
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)
generator.setGenerateEmptySchemas(g.getGenerate().isEmptySchemas());
if (g.getGenerate().getNewline() != null)
generator.setGenerateNewline(g.getGenerate().getNewline());
if (g.getGenerate().getIndentation() != null)
generator.setGenerateIndentation(g.getGenerate().getIndentation());
if (!isBlank(d.getSchemaVersionProvider()))
generator.setUseSchemaVersionProvider(true);
if (!isBlank(d.getCatalogVersionProvider()))
generator.setUseCatalogVersionProvider(true);
if (d.isTableValuedFunctions() != null)
generator.setGenerateTableValuedFunctions(d.isTableValuedFunctions());
else {
generator.setGenerateTableValuedFunctions(true);
}
// Generator properties that should in fact be strategy properties
strategy.setInstanceFields(generator.generateInstanceFields());
strategy.setJavaBeansGettersAndSetters(generator.generateJavaBeansGettersAndSetters());
generator.generate(database);
logUnused("forced type", "forced types", database.getUnusedForcedTypes());
logUnused("embeddable", "embeddables", database.getUnusedEmbeddables());
logUnused("synthetic identity", "synthetic identities", database.getUnusedSyntheticIdentities());
logUnused("synthetic primary key", "synthetic primary keys", database.getUnusedSyntheticPrimaryKeys());
logUnused("synthetic unique key", "synthetic unique keys", database.getUnusedSyntheticUniqueKeys());
logUnused("synthetic foreign key", "synthetic foreign keys", database.getUnusedSyntheticForeignKeys());
}
finally {
if (database != null)
try {
database.close();
}
catch (Exception e) {
log.error("Error while closing database", e);
}
// Close connection only if it was created by the GenerationTool
if (connection != null) {
if (close) {
// [#11105] In case of misconfiguration, the ctx reference could be null as a side effect
if (ctx != null && ctx.family() == HSQLDB && dataSource == null)
ctx.execute("shutdown");
connection.close();
}
else if (autoCommit != null) {
connection.setAutoCommit(autoCommit);
}
}
}
}
private void logUnused(String objectType, String objectTypes, List<?> list) {
if (!list.isEmpty() && Boolean.parseBoolean(System.getProperty("jooq.codegen.logunused", "true"))) {
unusedLogger.warn(
"Unused " + objectTypes,
"There are unused " + objectTypes + ", which have not been used by this generation run.\n"
+ "This can be because of misconfigurations, such as, for example:\n"
+ "- case sensitive regular expressions\n"
+ "- regular expressions depending on whitespace (Pattern.COMMENTS is turned on!)\n"
+ "- missing or inadequate object qualification\n"
+ "- the object to which the configuration was applied in the past has been dropped\n"
+ "Try turning on DEBUG logging (-X in Maven, and <logging/> in jOOQ) to get additional info about the schema"
);
for (Object o : list)
unusedLogger.warn("Unused " + objectType, o);
}
}
private static void setGlobalLoggingThreshold(Configuration configuration) {
if (configuration.getLogging() != null) {
switch (configuration.getLogging()) {
case TRACE:
JooqLogger.globalThreshold(Level.TRACE);
break;
case DEBUG:
JooqLogger.globalThreshold(Level.DEBUG);
break;
case INFO:
JooqLogger.globalThreshold(Level.INFO);
break;
case WARN:
JooqLogger.globalThreshold(Level.WARN);
break;
case ERROR:
JooqLogger.globalThreshold(Level.ERROR);
break;
case FATAL:
JooqLogger.globalThreshold(Level.FATAL);
break;
}
}
}
private Properties properties(List<Property> properties) {
Properties result = new Properties();
for (Property p : properties)
result.put(p.getKey(), p.getValue());
return result;
}
private String driverClass(Jdbc j) {
String result = j.getDriver();
if (result == null) {
result = JDBCUtils.driver(j.getUrl());
log.info("Database", "Inferring driver " + result + " from URL " + j.getUrl());
}
return result;
}
private Class<? extends Database> databaseClass(Jdbc j) {
return databaseClass(j.getUrl());
}
private Class<? extends Database> databaseClass(Connection c) {
try {
return databaseClass(c.getMetaData().getURL());
}
catch (SQLException e) {
throw new GeneratorException("Error when reading URL from JDBC connection", e);
}
}
private Class<? extends Database> databaseClass(String url) {
if (isBlank(url))
throw new GeneratorException("No JDBC URL configured.");
Class<? extends Database> result = Databases.databaseClass(JDBCUtils.dialect(url));
log.info("Database", "Inferring database " + result.getName() + " from URL " + url);
return result;
}
private Class<?> loadClass(String className) throws ClassNotFoundException {
try {
// [#2283] If no explicit class loader was provided try loading the class
// with "default" techniques
if (loader == null) {
return loadClass0(className);
}
// Prefer the explicit class loader if available
else {
return loader.loadClass(className);
}
}
catch (ClassNotFoundException e) {
String message = null;
// [#7556] [#8781]
if (className.startsWith("org.jooq.util.")) {
String alternative = null;
alternativeLoop:
for (String pkg : new String[] { "org.jooq.meta", "org.jooq.meta.extensions", "org.jooq.codegen", "org.jooq.codegen.maven" }) {
try {
alternative = loadClass0(className.replace("org.jooq.util", pkg)).getName();
break alternativeLoop;
}
catch (ClassNotFoundException ignore) {}
}
log.warn("Type not found", message =
"Your configured " + className + " type was not found.\n"
+ (alternative != null ? ("Did you mean " + alternative + "?\n") : "")
+ "Do note that in jOOQ 3.11, jOOQ-meta and jOOQ-codegen packages have been renamed. New package names are:\n"
+ "- org.jooq.meta\n"
+ "- org.jooq.meta.extensions\n"
+ "- org.jooq.codegen\n"
+ "- org.jooq.codegen.maven\n"
+ "See https://github.com/jOOQ/jOOQ/issues/7419 for details");
}
else if (className.equals("org.jooq.meta.extensions.liquibase.LiquibaseDatabase")) {
log.warn("Type not found", message =
"Your configured database type was not found: " + className + ".\n"
+ "- Please make sure the jooq-meta-extensions-liquibase dependency is on your classpath.\n"
+ "- In jOOQ 3.14, the dependency name has changed, see https://github.com/jOOQ/jOOQ/issues/10331");
}
else if (className.equals("org.jooq.meta.extensions.jpa.JPADatabase")) {
log.warn("Type not found", message =
"Your configured database type was not found: " + className + ".\n"
+ "- Please make sure the jooq-meta-extensions-hibernate dependency is on your classpath.\n"
+ "- In jOOQ 3.14, the dependency name has changed, see https://github.com/jOOQ/jOOQ/issues/10331");
}
// [#2801] [#4620]
else if (className.startsWith("org.jooq.meta.") && className.endsWith("Database")) {
log.warn("Type not found", message =
"Your configured database type was not found: " + className + ". This can have several reasons:\n"
+ "- You want to use a commercial jOOQ Edition, but you pulled the Open Source Edition from Maven Central.\n"
+ "- You have mis-typed your class name.");
}
if (message == null)
throw e;
else
throw new ClassNotFoundException(message, e);
}
}
private Class<?> loadClass0(String className) throws ClassNotFoundException {
try {
return Class.forName(className);
}
catch (ClassNotFoundException e) {
return Thread.currentThread().getContextClassLoader().loadClass(className);
}
}
private static String trim(String string) {
return (string == null ? null : string.trim());
}
Copy bytes from a large (over 2GB) InputStream
to an
OutputStream
.
This method buffers the input internally, so there is no need to use a
BufferedInputStream
.
Params: - input – the
InputStream
to read from - output – the
OutputStream
to write to
Throws: - NullPointerException – if the input or output is null
- IOException – if an I/O error occurs
Returns: the number of bytes copied Since: Commons IO 1.3
/**
* Copy bytes from a large (over 2GB) <code>InputStream</code> to an
* <code>OutputStream</code>.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
*
* @param input the <code>InputStream</code> to read from
* @param output the <code>OutputStream</code> to write to
* @return the number of bytes copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since Commons IO 1.3
*/
public static long copyLarge(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[1024 * 4];
long count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
Load a jOOQ codegen configuration file from an input stream
/**
* Load a jOOQ codegen configuration file from an input stream
*/
public static Configuration load(InputStream in) throws IOException {
// [#1149] If there is no namespace defined, add the default one
ByteArrayOutputStream out = new ByteArrayOutputStream();
copyLarge(in, out);
String xml = out.toString();
// TODO [#1201] Add better error handling here
xml = xml.replaceAll(
"<(\\w+:)?configuration xmlns(:\\w+)?=\"http://www.jooq.org/xsd/jooq-codegen-\\d+\\.\\d+\\.\\d+.xsd\">",
"<$1configuration xmlns$2=\"" + Constants.NS_CODEGEN + "\">");
return MiniJAXB.unmarshal(xml, Configuration.class);
}
}