/*
 * 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>&lt;jdbc/&gt;</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>&lt;jdbc/&gt;</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:
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); } }