[#4846] Add SPI to allow for injecting meta data ordering
This commit is contained in:
parent
47c2549909
commit
100b2dee35
@ -52,6 +52,7 @@ import java.io.StringWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
@ -478,6 +479,15 @@ public class GenerationTool {
|
||||
database.setSchemaVersionProvider(svp);
|
||||
database.setCatalogVersionProvider(cvp);
|
||||
|
||||
if (!StringUtils.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()))
|
||||
|
||||
@ -15710,6 +15710,94 @@ configuration {
|
||||
</html></content>
|
||||
</section>
|
||||
|
||||
<section id="codegen-config-order-provider">
|
||||
<title>Custom ordering of generated code</title>
|
||||
<content><html>
|
||||
<p>
|
||||
By default, the jOOQ code generator maintains the following ordering of objects:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Catalogs, schemas, tables, user-defined types, packages, routines, sequences, constraints are ordered alphabetically</li>
|
||||
<li>Table columns, user-defined type attributes, routine parameters are ordered in their order of definition</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Sometimes, it may be desireable to override this default ordering to a custom ordering. In particular, the default ordering may be case-sensitive, when case-insensitive ordering is really more desireable at times. Users may define an order provider by specifying a fully qualified class on the code generator's class path, which must implement <reference class="java.util.Comparator" title="java.util.Comparator<org.jooq.util.Definition>"/> as follows:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>XML configuration (standalone and Maven)</strong>
|
||||
</p>
|
||||
|
||||
</html><xml><![CDATA[<configuration>
|
||||
<generator>
|
||||
<database>
|
||||
<orderProvider>com.example.CaseInsensitiveOrderProvider</orderProvider>
|
||||
</database>
|
||||
</generator>
|
||||
</configuration>]]></xml><html>
|
||||
|
||||
<p>
|
||||
<strong>Programmatic configuration</strong>
|
||||
</p>
|
||||
|
||||
</html><java><![CDATA[configuration
|
||||
.withGenerator(new Generator(
|
||||
.withDatabase(new Database()
|
||||
.withOrderProvider("com.example.CaseInsensitiveOrderProvider");]]></java><html>
|
||||
|
||||
<p>
|
||||
<strong>Gradle configuration</strong>
|
||||
</p>
|
||||
|
||||
</html><java><![CDATA[configuration {
|
||||
generator {
|
||||
database {
|
||||
orderProvider = 'com.example.CaseInsensitiveOrderProvider'
|
||||
}
|
||||
}
|
||||
}]]></java><html>
|
||||
|
||||
<p>
|
||||
This order provider may then look as follows:
|
||||
</p>
|
||||
|
||||
</html><java><![CDATA[package com.example;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.jooq.util.Definition;
|
||||
|
||||
public class CaseInsensitiveOrderProvider implements Comparator<Definition> {
|
||||
@Override
|
||||
public int compare(Definition o1, Definition o2) {
|
||||
return o1.getQualifiedInputName().compareToIgnoreCase(o2.getQualifiedInputName());
|
||||
}
|
||||
}]]></java><html>
|
||||
<p>
|
||||
While changing the order of "top level types" (like tables) is irrelevant to the jOOQ runtime, there may be some side-effects to changing the order of table columns, user-defined type attributes, routine parameters, as the database might expect the exact same order as is defined in the database. In order to only change the ordering for tables, the following order provider can be implemented instead:
|
||||
</p>
|
||||
|
||||
</html><java><![CDATA[package com.example;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.jooq.util.Definition;
|
||||
import org.jooq.util.TableDefinition;
|
||||
|
||||
public class CaseInsensitiveOrderProvider implements Comparator<Definition> {
|
||||
@Override
|
||||
public int compare(Definition o1, Definition o2) {
|
||||
if (o1 instanceof TableDefinition && o2 instanceof TableDefinition)
|
||||
return o1.getQualifiedInputName().compareToIgnoreCase(o2.getQualifiedInputName());
|
||||
else
|
||||
return 0; // Retain input ordering
|
||||
}
|
||||
}]]></java><html>
|
||||
</html></content>
|
||||
</section>
|
||||
|
||||
<section id="codegen-config-forced-types">
|
||||
<title>Forced types</title>
|
||||
<content><html>
|
||||
|
||||
@ -77,12 +77,18 @@
|
||||
<bindings if-exists="true" scd="~tns:CustomTypes">
|
||||
<class ref="org.jooq.util.jaxb.CustomTypes"/>
|
||||
</bindings>
|
||||
<bindings if-exists="true" scd="~tns:EnumTypes">
|
||||
<class ref="org.jooq.util.jaxb.EnumTypes"/>
|
||||
</bindings>
|
||||
<bindings if-exists="true" scd="~tns:ForcedTypes">
|
||||
<class ref="org.jooq.util.jaxb.ForcedTypes"/>
|
||||
</bindings>
|
||||
<bindings if-exists="true" scd="~tns:CustomType">
|
||||
<class ref="org.jooq.util.jaxb.CustomType"/>
|
||||
</bindings>
|
||||
<bindings if-exists="true" scd="~tns:EnumType">
|
||||
<class ref="org.jooq.util.jaxb.EnumType"/>
|
||||
</bindings>
|
||||
<bindings if-exists="true" scd="~tns:ForcedType">
|
||||
<class ref="org.jooq.util.jaxb.ForcedType"/>
|
||||
</bindings>
|
||||
|
||||
@ -46,6 +46,7 @@ import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -128,6 +129,7 @@ public abstract class AbstractDatabase implements Database {
|
||||
private List<ForcedType> configuredForcedTypes;
|
||||
private SchemaVersionProvider schemaVersionProvider;
|
||||
private CatalogVersionProvider catalogVersionProvider;
|
||||
private Comparator<Definition> orderProvider;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Loaded definitions
|
||||
@ -998,6 +1000,16 @@ public abstract class AbstractDatabase implements Database {
|
||||
this.catalogVersionProvider = catalogVersionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Comparator<Definition> getOrderProvider() {
|
||||
return orderProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setOrderProvider(Comparator<Definition> provider) {
|
||||
this.orderProvider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setSupportsUnsignedTypes(boolean supportsUnsignedTypes) {
|
||||
this.supportsUnsignedTypes = supportsUnsignedTypes;
|
||||
@ -1057,7 +1069,7 @@ public abstract class AbstractDatabase implements Database {
|
||||
try {
|
||||
List<SequenceDefinition> s = getSequences0();
|
||||
|
||||
sequences = filterExcludeInclude(s);
|
||||
sequences = sort(filterExcludeInclude(s));
|
||||
log.info("Sequences fetched", fetchedSize(s, sequences));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@ -1159,7 +1171,7 @@ public abstract class AbstractDatabase implements Database {
|
||||
try {
|
||||
List<TableDefinition> t = getTables0();
|
||||
|
||||
tables = filterExcludeInclude(t);
|
||||
tables = sort(filterExcludeInclude(t));
|
||||
log.info("Tables fetched", fetchedSize(t, tables));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@ -1204,7 +1216,7 @@ public abstract class AbstractDatabase implements Database {
|
||||
try {
|
||||
List<EnumDefinition> e = getEnums0();
|
||||
|
||||
enums = filterExcludeInclude(e);
|
||||
enums = sort(filterExcludeInclude(e));
|
||||
enums.addAll(getConfiguredEnums());
|
||||
|
||||
log.info("Enums fetched", fetchedSize(e, enums));
|
||||
@ -1310,7 +1322,7 @@ public abstract class AbstractDatabase implements Database {
|
||||
try {
|
||||
List<DomainDefinition> e = getDomains0();
|
||||
|
||||
domains = filterExcludeInclude(e);
|
||||
domains = sort(filterExcludeInclude(e));
|
||||
log.info("Domains fetched", fetchedSize(e, domains));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@ -1350,7 +1362,7 @@ public abstract class AbstractDatabase implements Database {
|
||||
try {
|
||||
List<ArrayDefinition> a = getArrays0();
|
||||
|
||||
arrays = filterExcludeInclude(a);
|
||||
arrays = sort(filterExcludeInclude(a));
|
||||
log.info("ARRAYs fetched", fetchedSize(a, arrays));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@ -1395,7 +1407,7 @@ public abstract class AbstractDatabase implements Database {
|
||||
try {
|
||||
List<UDTDefinition> u = getUDTs0();
|
||||
|
||||
udts = filterExcludeInclude(u);
|
||||
udts = sort(filterExcludeInclude(u));
|
||||
log.info("UDTs fetched", fetchedSize(u, udts));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@ -1481,7 +1493,7 @@ public abstract class AbstractDatabase implements Database {
|
||||
try {
|
||||
List<RoutineDefinition> r = getRoutines0();
|
||||
|
||||
routines = filterExcludeInclude(r);
|
||||
routines = sort(filterExcludeInclude(r));
|
||||
log.info("Routines fetched", fetchedSize(r, routines));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@ -1507,7 +1519,7 @@ public abstract class AbstractDatabase implements Database {
|
||||
try {
|
||||
List<PackageDefinition> p = getPackages0();
|
||||
|
||||
packages = filterExcludeInclude(p);
|
||||
packages = sort(filterExcludeInclude(p));
|
||||
log.info("Packages fetched", fetchedSize(p, packages));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@ -1595,6 +1607,14 @@ public abstract class AbstractDatabase implements Database {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T extends Definition> List<T> sort(List<T> definitions) {
|
||||
if (orderProvider != null)
|
||||
Collections.sort(definitions, orderProvider);
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<Definition> getIncluded() {
|
||||
return Collections.unmodifiableList(included);
|
||||
|
||||
@ -127,6 +127,8 @@ extends AbstractDefinition {
|
||||
else {
|
||||
elements = e;
|
||||
}
|
||||
|
||||
db.sort(elements);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Error while initialising type", e);
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
package org.jooq.util;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
@ -463,6 +464,11 @@ public interface Database {
|
||||
*/
|
||||
<D extends Definition> List<D> filterExcludeInclude(List<D> definitions);
|
||||
|
||||
/**
|
||||
* Sort a list of definitions according to the {@link #getOrderProvider()} defined in this database.
|
||||
*/
|
||||
<D extends Definition> List<D> sort(List<D> definitions);
|
||||
|
||||
/**
|
||||
* Retrieve all included objects.
|
||||
*/
|
||||
@ -612,6 +618,16 @@ public interface Database {
|
||||
*/
|
||||
void setCatalogVersionProvider(CatalogVersionProvider provider);
|
||||
|
||||
/**
|
||||
* The database's order provider.
|
||||
*/
|
||||
Comparator<Definition> getOrderProvider();
|
||||
|
||||
/**
|
||||
* The database's order provider.
|
||||
*/
|
||||
void setOrderProvider(Comparator<Definition> provider);
|
||||
|
||||
/**
|
||||
* Database objects matching any of these field names will be generated as
|
||||
* forced types.
|
||||
|
||||
@ -111,6 +111,9 @@ public class Database implements Serializable
|
||||
@XmlElement(defaultValue = "")
|
||||
@XmlJavaTypeAdapter(StringAdapter.class)
|
||||
protected String catalogVersionProvider = "";
|
||||
@XmlElement(defaultValue = "")
|
||||
@XmlJavaTypeAdapter(StringAdapter.class)
|
||||
protected String orderProvider = "";
|
||||
protected Boolean tableValuedFunctions;
|
||||
@XmlElementWrapper(name = "properties")
|
||||
@XmlElement(name = "property")
|
||||
@ -973,6 +976,32 @@ public class Database implements Serializable
|
||||
this.catalogVersionProvider = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom {@link java.util.Comparator} that can compare two {@link org.jooq.util.Definition} objects to determine their order.
|
||||
* <p>
|
||||
* This comparator can be used to influence the order of any object that is produced by jOOQ meta, and thus, indirectly, the order of declared objects in generated code.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getOrderProvider() {
|
||||
return orderProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the orderProvider property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setOrderProvider(String value) {
|
||||
this.orderProvider = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether table valued functions should be reported as tables.
|
||||
* <p>
|
||||
@ -1227,6 +1256,11 @@ public class Database implements Serializable
|
||||
return this;
|
||||
}
|
||||
|
||||
public Database withOrderProvider(String value) {
|
||||
setOrderProvider(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Database withTableValuedFunctions(Boolean value) {
|
||||
setTableValuedFunctions(value);
|
||||
return this;
|
||||
|
||||
@ -634,6 +634,12 @@ Catalog versions will be generated into the {@link javax.annotation.Generated} a
|
||||
generated artefacts.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="orderProvider" type="string" default="" minOccurs="0" maxOccurs="1">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A custom {@link java.util.Comparator} that can compare two {@link org.jooq.util.Definition} objects to determine their order.
|
||||
<p>
|
||||
This comparator can be used to influence the order of any object that is produced by jOOQ meta, and thus, indirectly, the order of declared objects in generated code.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="customTypes" type="tns:CustomTypes" minOccurs="0" maxOccurs="1">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[@deprecated Use {@link #getForcedTypes()} only]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user