[#2530] First working draft

This commit is contained in:
lukaseder 2019-02-22 15:35:35 +01:00
parent 6e8b2d97db
commit 04d03bfda0
33 changed files with 1877 additions and 171 deletions

View File

@ -72,6 +72,7 @@ abstract class AbstractGenerator implements Generator {
boolean generateSequences = true;
boolean generateUDTs = true;
boolean generateTables = true;
boolean generateEmbeddables = true;
boolean generateRecords = true;
boolean generateRecordsImplementingRecordN = true;
boolean generatePojos = false;
@ -356,6 +357,16 @@ abstract class AbstractGenerator implements Generator {
this.generateTables = generateTables;
}
@Override
public boolean generateEmbeddables() {
return generateEmbeddables;
}
@Override
public void setGenerateEmbeddables(boolean generateEmbeddables) {
this.generateEmbeddables = generateEmbeddables;
}
@Override
public boolean generateRecords() {

View File

@ -51,6 +51,7 @@ import org.jooq.meta.ArrayDefinition;
import org.jooq.meta.CatalogDefinition;
import org.jooq.meta.Definition;
import org.jooq.meta.DomainDefinition;
import org.jooq.meta.EmbeddableDefinition;
import org.jooq.meta.EnumDefinition;
import org.jooq.meta.ForeignKeyDefinition;
import org.jooq.meta.IndexDefinition;
@ -294,15 +295,12 @@ public class DefaultGeneratorStrategy extends AbstractGeneratorStrategy {
.replace('.', '_')
));
if (mode == Mode.RECORD) {
if (mode == Mode.RECORD)
result.append("Record");
}
else if (mode == Mode.DAO) {
else if (mode == Mode.DAO)
result.append("Dao");
}
else if (mode == Mode.INTERFACE) {
else if (mode == Mode.INTERFACE)
result.insert(0, "I");
}
return result.toString();
}
@ -312,6 +310,11 @@ public class DefaultGeneratorStrategy extends AbstractGeneratorStrategy {
return "tables";
}
// [#2530] Embeddable types
else if (definition instanceof EmbeddableDefinition) {
return "embeddables";
}
// [#799] UDT's are also packages
else if (definition instanceof UDTDefinition) {
UDTDefinition udt = (UDTDefinition) definition;

View File

@ -490,6 +490,7 @@ public class GenerationTool {
database.setIncludeRoutines(!FALSE.equals(d.isIncludeRoutines()));
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()));
@ -502,6 +503,7 @@ public class GenerationTool {
database.setConfiguredCustomTypes(d.getCustomTypes());
database.setConfiguredEnumTypes(d.getEnumTypes());
database.setConfiguredForcedTypes(d.getForcedTypes());
database.setConfiguredEmbeddables(d.getEmbeddables());
database.setLogSlowQueriesAfterSeconds(defaultIfNull(g.getDatabase().getLogSlowQueriesAfterSeconds(), 5));
if (d.getRegexFlags() != null)
@ -616,6 +618,8 @@ public class GenerationTool {
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)

View File

@ -202,6 +202,16 @@ public interface Generator {
*/
void setGenerateTables(boolean generateTables);
/**
* Whether embeddable types should be generated
*/
boolean generateEmbeddables();
/**
* Whether embeddable types should be generated
*/
void setGenerateEmbeddables(boolean generateEmbeddables);
/**
* Whether TableRecords should be generated in addition to tables
*/

View File

@ -111,6 +111,7 @@ import org.jooq.impl.CatalogImpl;
import org.jooq.impl.DAOImpl;
import org.jooq.impl.DSL;
import org.jooq.impl.DefaultDataType;
import org.jooq.impl.EmbeddableRecordImpl;
import org.jooq.impl.Internal;
import org.jooq.impl.PackageImpl;
import org.jooq.impl.SQLDataType;
@ -131,6 +132,8 @@ import org.jooq.meta.Database;
import org.jooq.meta.DefaultDataTypeDefinition;
import org.jooq.meta.Definition;
import org.jooq.meta.DomainDefinition;
import org.jooq.meta.EmbeddableColumnDefinition;
import org.jooq.meta.EmbeddableDefinition;
import org.jooq.meta.EnumDefinition;
import org.jooq.meta.ForeignKeyDefinition;
import org.jooq.meta.IdentityDefinition;
@ -507,6 +510,10 @@ public class JavaGenerator extends AbstractGenerator {
generateTables(schema);
}
if (generateEmbeddables() && database.getEmbeddables(schema).size() > 0) {
generateEmbeddables(schema);
}
if (generatePojos() && database.getTables(schema).size() > 0) {
generatePojos(schema);
}
@ -1011,7 +1018,7 @@ public class JavaGenerator extends AbstractGenerator {
out.println();
if (scala)
out.tab(1).println("private object Identities%s {", block);
out.tab(1).println("private object Identities%s {", block);
else
out.tab(1).println("private static class Identities%s {", block);
}
@ -1063,7 +1070,7 @@ public class JavaGenerator extends AbstractGenerator {
out.println();
if (scala)
out.tab(1).println("private object UniqueKeys%s {", block);
out.tab(1).println("private object UniqueKeys%s {", block);
else
out.tab(1).println("private static class UniqueKeys%s {", block);
}
@ -1114,13 +1121,13 @@ public class JavaGenerator extends AbstractGenerator {
out.println();
if (scala)
out.tab(1).println("private object ForeignKeys%s {", block);
out.tab(1).println("private object ForeignKeys%s {", block);
else
out.tab(1).println("private static class ForeignKeys%s {", block);
}
if (scala)
out.tab(2).println("val %s : %s[%s, %s] = %s.createForeignKey(%s, %s, \"%s\", [[%s]])",
out.tab(2).println("val %s : %s[%s, %s] = %s.createForeignKey(%s, %s, \"%s\", [[%s]])",
getStrategy().getJavaIdentifier(foreignKey),
ForeignKey.class,
out.ref(getStrategy().getFullJavaClassName(foreignKey.getKeyTable(), Mode.RECORD)),
@ -1180,29 +1187,35 @@ public class JavaGenerator extends AbstractGenerator {
generateRecord0(udt, out);
}
private final void generateRecord0(Definition tableOrUdt, JavaWriter out) {
final UniqueKeyDefinition key = (tableOrUdt instanceof TableDefinition)
? ((TableDefinition) tableOrUdt).getPrimaryKey()
private final void generateRecord0(Definition tableUdtOrEmbeddable, JavaWriter out) {
final UniqueKeyDefinition key = (tableUdtOrEmbeddable instanceof TableDefinition)
? ((TableDefinition) tableUdtOrEmbeddable).getPrimaryKey()
: null;
final String className = getStrategy().getJavaClassName(tableOrUdt, Mode.RECORD);
final String tableIdentifier = out.ref(getStrategy().getFullJavaIdentifier(tableOrUdt), 2);
final List<String> interfaces = out.ref(getStrategy().getJavaClassImplements(tableOrUdt, Mode.RECORD));
final List<? extends TypedElementDefinition<?>> columns = getTypedElements(tableOrUdt);
final String className = getStrategy().getJavaClassName(tableUdtOrEmbeddable, Mode.RECORD);
final String tableIdentifier = !(tableUdtOrEmbeddable instanceof EmbeddableDefinition)
? out.ref(getStrategy().getFullJavaIdentifier(tableUdtOrEmbeddable), 2)
: null;
final List<String> interfaces = out.ref(getStrategy().getJavaClassImplements(tableUdtOrEmbeddable, Mode.RECORD));
final List<? extends TypedElementDefinition<?>> columns = getTypedElements(tableUdtOrEmbeddable);
printPackage(out, tableOrUdt, Mode.RECORD);
printPackage(out, tableUdtOrEmbeddable, Mode.RECORD);
if (tableOrUdt instanceof TableDefinition)
generateRecordClassJavadoc((TableDefinition) tableOrUdt, out);
if (tableUdtOrEmbeddable instanceof TableDefinition)
generateRecordClassJavadoc((TableDefinition) tableUdtOrEmbeddable, out);
else if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
generateEmbeddableClassJavadoc((EmbeddableDefinition) tableUdtOrEmbeddable, out);
else
generateUDTRecordClassJavadoc((UDTDefinition) tableOrUdt, out);
generateUDTRecordClassJavadoc((UDTDefinition) tableUdtOrEmbeddable, out);
printClassAnnotations(out, tableOrUdt.getSchema());
if (tableOrUdt instanceof TableDefinition)
printTableJPAAnnotation(out, (TableDefinition) tableOrUdt);
printClassAnnotations(out, tableUdtOrEmbeddable.getSchema());
if (tableUdtOrEmbeddable instanceof TableDefinition)
printTableJPAAnnotation(out, (TableDefinition) tableUdtOrEmbeddable);
Class<?> baseClass;
if (tableOrUdt instanceof UDTDefinition)
if (tableUdtOrEmbeddable instanceof UDTDefinition)
baseClass = UDTRecordImpl.class;
else if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
baseClass = EmbeddableRecordImpl.class;
else if (generateRelations() && key != null)
baseClass = UpdatableRecordImpl.class;
else
@ -1225,12 +1238,14 @@ public class JavaGenerator extends AbstractGenerator {
interfaces.add(rowTypeRecord);
}
if (generateInterfaces()) {
interfaces.add(out.ref(getStrategy().getFullJavaClassName(tableOrUdt, Mode.INTERFACE)));
}
if (generateInterfaces())
interfaces.add(out.ref(getStrategy().getFullJavaClassName(tableUdtOrEmbeddable, Mode.INTERFACE)));
if (scala)
out.println("class %s extends %s[%s](%s)[[before= with ][separator= with ][%s]] {", className, baseClass, className, tableIdentifier, interfaces);
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.println("class %s extends %s[%s]()[[before= with ][separator= with ][%s]] {", className, baseClass, className, interfaces);
else
out.println("class %s extends %s[%s](%s)[[before= with ][separator= with ][%s]] {", className, baseClass, className, tableIdentifier, interfaces);
else
out.println("public class %s extends %s<%s>[[before= implements ][%s]] {", className, baseClass, className, interfaces);
@ -1239,16 +1254,30 @@ public class JavaGenerator extends AbstractGenerator {
for (int i = 0; i < degree; i++) {
TypedElementDefinition<?> column = columns.get(i);
if (tableOrUdt instanceof TableDefinition) {
if (tableUdtOrEmbeddable instanceof TableDefinition) {
generateRecordSetter(column, i, out);
generateRecordGetter(column, i, out);
}
else if (tableUdtOrEmbeddable instanceof EmbeddableDefinition) {
generateEmbeddableSetter(column, i, out);
generateEmbeddableGetter(column, i, out);
}
else {
generateUDTRecordSetter(column, i, out);
generateUDTRecordGetter(column, i, out);
}
}
if (tableUdtOrEmbeddable instanceof TableDefinition) {
List<EmbeddableDefinition> embeddables = ((TableDefinition) tableUdtOrEmbeddable).getEmbeddables();
for (int i = 0; i < embeddables.size(); i++) {
EmbeddableDefinition embeddable = embeddables.get(i);
// [#2530] TODO: Implement setters and getters for embeddables here
}
}
if (generateRelations() && key != null) {
int keyDegree = key.getKeyColumns().size();
@ -1270,10 +1299,10 @@ public class JavaGenerator extends AbstractGenerator {
}
}
if (tableOrUdt instanceof UDTDefinition) {
if (tableUdtOrEmbeddable instanceof UDTDefinition) {
// [#799] Oracle UDT's can have member procedures
for (RoutineDefinition routine : ((UDTDefinition) tableOrUdt).getRoutines()) {
for (RoutineDefinition routine : ((UDTDefinition) tableUdtOrEmbeddable).getRoutines()) {
// Instance methods ship with a SELF parameter at the first position
// [#1584] Static methods don't have that
@ -1334,6 +1363,9 @@ public class JavaGenerator extends AbstractGenerator {
for (int i = 1; i <= degree; i++) {
TypedElementDefinition<?> column = columns.get(i - 1);
if (column instanceof EmbeddableColumnDefinition)
column = ((EmbeddableColumnDefinition) column).getColumn();
final String colTypeFull = getJavaType(column.getType(resolver()));
final String colType = out.ref(colTypeFull);
final String colIdentifier = out.ref(getStrategy().getFullJavaIdentifier(column), colRefSegments(column));
@ -1349,7 +1381,12 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).overrideInherit();
out.tab(1).println("public %s<%s> field%s() {", Field.class, colType, i);
out.tab(2).println("return %s;", colIdentifier);
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.tab(2).println("return (%s<%s>) FIELDS[%s];", Field.class, colType, i - 1);
else
out.tab(2).println("return %s;", colIdentifier);
out.tab(1).println("}");
}
}
@ -1471,17 +1508,35 @@ public class JavaGenerator extends AbstractGenerator {
}
}
if (generateInterfaces()) {
printFromAndInto(out, tableOrUdt);
}
if (generateInterfaces())
printFromAndInto(out, tableUdtOrEmbeddable);
if (scala) {
}
else {
out.tab(1).header("Constructors");
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition) {
out.println();
out.tab(1).println("private static final %s<?>[] FIELDS = {", Field.class);
for (EmbeddableColumnDefinition column : ((EmbeddableDefinition) tableUdtOrEmbeddable).getColumns()) {
final String colIdentifier = out.ref(getStrategy().getFullJavaIdentifier(column.getColumn()), colRefSegments(column));
out.tab(2).println("%s.field(%s.name(\"%s\"), %s.getDataType()),", DSL.class, DSL.class, column.getOutputName(), colIdentifier);
}
out.tab(1).println("};");
out.println();
}
out.tab(1).javadoc("Create a detached %s", className);
out.tab(1).println("public %s() {", className);
out.tab(2).println("super(%s);", tableIdentifier);
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.tab(2).println("super(FIELDS);");
else
out.tab(2).println("super(%s);", tableIdentifier);
out.tab(1).println("}");
}
@ -1496,7 +1551,7 @@ public class JavaGenerator extends AbstractGenerator {
final String type = out.ref(getJavaType(column.getType(resolver())));
if (scala)
arguments.add(columnMember + " : " + type);
arguments.add(columnMember + " : " + type);
else
arguments.add(type + " " + columnMember);
}
@ -1509,7 +1564,11 @@ public class JavaGenerator extends AbstractGenerator {
}
else {
out.tab(1).println("public %s([[%s]]) {", className, arguments);
out.tab(2).println("super(%s);", tableIdentifier);
if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
out.tab(2).println("this();", tableIdentifier);
else
out.tab(2).println("super(%s);", tableIdentifier);
}
out.println();
@ -1519,7 +1578,7 @@ public class JavaGenerator extends AbstractGenerator {
final String columnMember = getStrategy().getJavaMemberName(column, Mode.DEFAULT);
if (scala)
out.tab(2).println("set(%s, %s)", i, columnMember);
out.tab(2).println("set(%s, %s)", i, columnMember);
else
out.tab(2).println("set(%s, %s);", i, columnMember);
}
@ -1527,10 +1586,12 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).println("}");
}
if (tableOrUdt instanceof TableDefinition)
generateRecordClassFooter((TableDefinition) tableOrUdt, out);
if (tableUdtOrEmbeddable instanceof TableDefinition)
generateRecordClassFooter((TableDefinition) tableUdtOrEmbeddable, out);
else if (tableUdtOrEmbeddable instanceof EmbeddableDefinition)
generateEmbeddableClassFooter((EmbeddableDefinition) tableUdtOrEmbeddable, out);
else
generateUDTRecordClassFooter((UDTDefinition) tableOrUdt, out);
generateUDTRecordClassFooter((UDTDefinition) tableUdtOrEmbeddable, out);
out.println("}");
}
@ -1542,6 +1603,13 @@ public class JavaGenerator extends AbstractGenerator {
generateRecordSetter0(column, index, out);
}
/**
* Subclasses may override this method to provide their own embeddable setters.
*/
protected void generateEmbeddableSetter(TypedElementDefinition<?> column, int index, JavaWriter out) {
generateRecordSetter0(column, index, out);
}
/**
* Subclasses may override this method to provide their own record setters.
*/
@ -1651,6 +1719,13 @@ public class JavaGenerator extends AbstractGenerator {
generateRecordGetter0(column, index, out);
}
/**
* Subclasses may override this method to provide their own embeddable getters.
*/
protected void generateEmbeddableGetter(TypedElementDefinition<?> column, int index, JavaWriter out) {
generateRecordGetter0(column, index, out);
}
/**
* Subclasses may override this method to provide their own record getters.
*/
@ -1668,7 +1743,7 @@ public class JavaGenerator extends AbstractGenerator {
if (!printDeprecationIfUnknownType(out, typeFull))
out.tab(1).javadoc("Getter for <code>%s</code>.%s", name, columnComment(column, comment));
if (column.getContainer() instanceof TableDefinition)
if (column instanceof ColumnDefinition)
printColumnJPAAnnotation(out, (ColumnDefinition) column);
printValidationAnnotation(out, column);
@ -1718,6 +1793,19 @@ public class JavaGenerator extends AbstractGenerator {
printClassJavadoc(out, "The table <code>" + table.getQualifiedInputName() + "</code>.");
}
/**
* Subclasses may override this method to provide record class footer code.
*/
@SuppressWarnings("unused")
protected void generateEmbeddableClassFooter(EmbeddableDefinition embeddable, JavaWriter out) {}
/**
* Subclasses may override this method to provide their own Javadoc.
*/
protected void generateEmbeddableClassJavadoc(EmbeddableDefinition embeddable, JavaWriter out) {
printClassJavadoc(out, "The embeddable <code>" + embeddable.getQualifiedInputName() + "</code>.");
}
private String refRowType(JavaWriter out, Collection<? extends TypedElementDefinition<?>> columns) {
StringBuilder result = new StringBuilder();
String separator = "";
@ -1784,7 +1872,7 @@ public class JavaGenerator extends AbstractGenerator {
printTableJPAAnnotation(out, (TableDefinition) tableOrUDT);
if (scala)
out.println("trait %s[[before= extends ][%s]] {", className, interfaces);
out.println("trait %s[[before= extends ][%s]] {", className, interfaces);
else
out.println("public interface %s[[before= extends ][%s]] {", className, interfaces);
@ -1813,14 +1901,14 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).javadoc("Load data from another generated Record/POJO implementing the common interface %s", local);
if (scala)
out.tab(1).println("def from(from : %s)", qualified);
out.tab(1).println("def from(from : %s)", qualified);
else
out.tab(1).println("public void from(%s from);", qualified);
out.tab(1).javadoc("Copy data into another generated Record/POJO implementing the common interface %s", local);
if (scala)
out.tab(1).println("def into [E <: %s](into : E) : E", qualified);
out.tab(1).println("def into [E <: %s](into : E) : E", qualified);
else
out.tab(1).println("public <E extends %s> E into(E into);", qualified);
}
@ -2221,7 +2309,7 @@ public class JavaGenerator extends AbstractGenerator {
printClassAnnotations(out, schema);
if (scala)
out.println("object UDTs {");
out.println("object UDTs {");
else
out.println("public class UDTs {");
@ -2233,7 +2321,7 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).javadoc("The type <code>%s</code>", udt.getQualifiedOutputName());
if (scala)
out.tab(1).println("val %s = %s", id, fullId);
out.tab(1).println("val %s = %s", id, fullId);
else
out.tab(1).println("public static %s %s = %s;", className, id, fullId);
}
@ -2811,7 +2899,7 @@ public class JavaGenerator extends AbstractGenerator {
printClassAnnotations(out, schema);
if (scala)
out.println("object Tables {");
out.println("object Tables {");
else
out.println("public class Tables {");
@ -2832,9 +2920,9 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).javadoc(comment);
if (scala)
out.tab(1).println("val %s = %s", id, fullId);
out.tab(1).println("val %s = %s", id, fullId);
else
out.tab(1).println("public static final %s %s = %s;", className, id, fullId);
out.tab(1).println("public static final %s %s = %s;", className, id, fullId);
}
// [#3797] Table-valued functions generate two different literals in
@ -2902,7 +2990,7 @@ public class JavaGenerator extends AbstractGenerator {
}
if (scala)
tType = Record.class.getName() + keyColumns.size() + "[" + generics + "]";
tType = Record.class.getName() + keyColumns.size() + "[" + generics + "]";
else
tType = Record.class.getName() + keyColumns.size() + "<" + generics + ">";
}
@ -2968,10 +3056,10 @@ public class JavaGenerator extends AbstractGenerator {
}
if (keyColumns.size() == 1) {
if (scala)
if (scala)
out.tab(2).println("o.%s", getStrategy().getJavaGetterName(keyColumns.get(0), Mode.POJO));
else
out.tab(2).println("return object.%s();", getStrategy().getJavaGetterName(keyColumns.get(0), Mode.POJO));
else
out.tab(2).println("return object.%s();", getStrategy().getJavaGetterName(keyColumns.get(0), Mode.POJO));
}
// [#2574] This should be replaced by a call to a method on the target table's Key type
@ -2980,16 +3068,16 @@ public class JavaGenerator extends AbstractGenerator {
String separator = "";
for (ColumnDefinition column : keyColumns) {
if (scala)
params += separator + "o." + getStrategy().getJavaGetterName(column, Mode.POJO);
else
params += separator + "object." + getStrategy().getJavaGetterName(column, Mode.POJO) + "()";
if (scala)
params += separator + "o." + getStrategy().getJavaGetterName(column, Mode.POJO);
else
params += separator + "object." + getStrategy().getJavaGetterName(column, Mode.POJO) + "()";
separator = ", ";
}
if (scala)
out.tab(2).println("compositeKeyRecord(%s)", params);
out.tab(2).println("compositeKeyRecord(%s)", params);
else
out.tab(2).println("return compositeKeyRecord(%s);", params);
}
@ -3653,18 +3741,16 @@ public class JavaGenerator extends AbstractGenerator {
}
private List<? extends TypedElementDefinition<? extends Definition>> getTypedElements(Definition definition) {
if (definition instanceof TableDefinition) {
if (definition instanceof TableDefinition)
return ((TableDefinition) definition).getColumns();
}
else if (definition instanceof UDTDefinition) {
else if (definition instanceof EmbeddableDefinition)
return ((EmbeddableDefinition) definition).getColumns();
else if (definition instanceof UDTDefinition)
return ((UDTDefinition) definition).getAttributes();
}
else if (definition instanceof RoutineDefinition) {
else if (definition instanceof RoutineDefinition)
return ((RoutineDefinition) definition).getAllParameters();
}
else {
else
throw new IllegalArgumentException("Unsupported type : " + definition);
}
}
/**
@ -3761,7 +3847,7 @@ public class JavaGenerator extends AbstractGenerator {
}
else {
out.println("public class %s extends %s<%s>[[before= implements ][%s]] {",
className, TableImpl.class, recordType, interfaces);
className, TableImpl.class, recordType, interfaces);
out.printSerial();
printSingletonInstance(out, table);
}
@ -3794,6 +3880,27 @@ public class JavaGenerator extends AbstractGenerator {
}
}
// [#2530] Embeddable types
for (EmbeddableDefinition embeddable : table.getEmbeddables()) {
final String columnId = out.ref(getStrategy().getJavaIdentifier(embeddable), colRefSegments(null));
final String columnType = out.ref(getStrategy().getFullJavaClassName(embeddable, Mode.RECORD));
final List<String> columnIds = new ArrayList<String>();
for (EmbeddableColumnDefinition column : embeddable.getColumns())
columnIds.add(out.ref(getStrategy().getJavaIdentifier(column), colRefSegments(column)));
out.tab(1).javadoc("The embeddable type <code>%s</code>.", embeddable.getOutputName());
if (scala) {
out.tab(1).println("val %s : %s[%s, %s] = %s.createEmbeddable(%s.name(\"%s\"), classOf[%s], this, [[%s]])",
columnId, TableField.class, recordType, columnType, Internal.class, DSL.class, embeddable.getName(), columnType, columnIds);
}
else {
out.tab(1).println("public final %s<%s, %s> %s = %s.createEmbeddable(%s.name(\"%s\"), %s.class, this, [[%s]]);",
TableField.class, recordType, columnType, columnId, Internal.class, DSL.class, embeddable.getName(), columnType, columnIds);
}
}
if (scala) {
out.tab(1).javadoc("Create a <code>%s</code> table reference", table.getQualifiedOutputName());
out.tab(1).println("def this() = {");
@ -4335,6 +4442,28 @@ public class JavaGenerator extends AbstractGenerator {
closeJavaWriter(out);
}
protected void generateEmbeddables(SchemaDefinition schema) {
log.info("Generating embeddables");
for (EmbeddableDefinition embeddable : database.getEmbeddables(schema)) {
try {
generateEmbeddable(schema, embeddable);
}
catch (Exception e) {
log.error("Error while generating embeddable " + embeddable, e);
}
}
watch.splitInfo("Tables generated");
}
@SuppressWarnings("unused")
protected void generateEmbeddable(SchemaDefinition schema, EmbeddableDefinition embeddable) {
JavaWriter out = newJavaWriter(getFile(embeddable, Mode.RECORD));
generateRecord0(embeddable, out);
closeJavaWriter(out);
}
private String converterTemplate(List<String> converter) {
if (converter == null || converter.isEmpty())
return "[[]]";
@ -4644,7 +4773,7 @@ public class JavaGenerator extends AbstractGenerator {
String getter = getStrategy().getJavaGetterName(column, Mode.INTERFACE);
if (scala)
out.tab(2).println("%s(from.%s)", setter, getter);
out.tab(2).println("%s(from.%s)", setter, getter);
else
out.tab(2).println("%s(from.%s());", setter, getter);
}
@ -4653,7 +4782,7 @@ public class JavaGenerator extends AbstractGenerator {
if (generateInterfaces() && !generateImmutableInterfaces()) {
if (scala) {
out.tab(1).println("public <E extends %s> E into(E into) {", qualified);
out.tab(1).println("public <E extends %s> E into(E into) {", qualified);
out.tab(2).println("into.from(this)");
out.tab(2).println("return into");
out.tab(1).println("}");
@ -4962,7 +5091,7 @@ public class JavaGenerator extends AbstractGenerator {
printPackage(out, routine);
if (scala) {
out.println("object %s {", className);
out.println("object %s {", className);
for (ParameterDefinition parameter : routine.getAllParameters()) {
final String paramTypeFull = getJavaType(parameter.getType(resolver()));
final String paramType = out.ref(paramTypeFull);
@ -4997,7 +5126,7 @@ public class JavaGenerator extends AbstractGenerator {
}
else {
out.println("public class %s extends %s<%s>[[before= implements ][%s]] {",
className, AbstractRoutine.class, returnType, interfaces);
className, AbstractRoutine.class, returnType, interfaces);
out.printSerial();
for (ParameterDefinition parameter : routine.getAllParameters()) {
@ -5022,7 +5151,7 @@ public class JavaGenerator extends AbstractGenerator {
if (scala) {
out.tab(1).println("{");
out.tab(1).println("{");
}
else {
out.tab(1).javadoc("Create a new routine call instance");
@ -5039,30 +5168,30 @@ public class JavaGenerator extends AbstractGenerator {
final String paramId = getStrategy().getJavaIdentifier(parameter);
if (parameter.equals(routine.getReturnValue())) {
if (scala)
if (scala)
out.tab(2).println("setReturnParameter(%s.%s)", className, paramId);
else
out.tab(2).println("setReturnParameter(%s);", paramId);
else
out.tab(2).println("setReturnParameter(%s);", paramId);
}
else if (routine.getInParameters().contains(parameter)) {
if (routine.getOutParameters().contains(parameter)) {
if (scala)
if (scala)
out.tab(2).println("addInOutParameter(%s.%s)", className, paramId);
else
out.tab(2).println("addInOutParameter(%s);", paramId);
else
out.tab(2).println("addInOutParameter(%s);", paramId);
}
else {
if (scala)
if (scala)
out.tab(2).println("addInParameter(%s.%s)", className, paramId);
else
out.tab(2).println("addInParameter(%s);", paramId);
else
out.tab(2).println("addInParameter(%s);", paramId);
}
}
else {
if (scala)
if (scala)
out.tab(2).println("addOutParameter(%s.%s)", className, paramId);
else
out.tab(2).println("addOutParameter(%s);", paramId);
else
out.tab(2).println("addOutParameter(%s);", paramId);
}
@ -5078,7 +5207,7 @@ public class JavaGenerator extends AbstractGenerator {
}
if (routine.getOverload() != null) {
if (scala)
if (scala)
out.tab(2).println("setOverloaded(true)");
else
out.tab(2).println("setOverloaded(true);");
@ -5106,7 +5235,7 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).javadoc("Set the <code>%s</code> parameter IN value to the routine", parameter.getOutputName());
if (scala) {
out.tab(1).println("def %s(%s : %s) : Unit = {", setter, paramName, refNumberType(out, parameter.getType(resolver())));
out.tab(1).println("def %s(%s : %s) : Unit = {", setter, paramName, refNumberType(out, parameter.getType(resolver())));
out.tab(2).println("set%s(%s.%s, %s)", numberValue, className, paramId, paramName);
out.tab(1).println("}");
}
@ -5208,7 +5337,7 @@ public class JavaGenerator extends AbstractGenerator {
if (scala)
out.tab(1).print("def %s(",
getStrategy().getJavaMethodName(function, Mode.DEFAULT));
getStrategy().getJavaMethodName(function, Mode.DEFAULT));
else
out.tab(1).print("public static %s<%s> %s(",
function.isAggregate() ? AggregateFunction.class : Field.class,
@ -5220,7 +5349,7 @@ public class JavaGenerator extends AbstractGenerator {
out.print(separator);
if (scala) {
out.print("%s : ", getStrategy().getJavaMemberName(parameter));
out.print("%s : ", getStrategy().getJavaMemberName(parameter));
if (parametersAsField) {
out.print("%s[%s]", Field.class, refExtendsNumberType(out, parameter.getType(resolver())));
@ -5242,13 +5371,13 @@ public class JavaGenerator extends AbstractGenerator {
}
if (scala) {
out.println(") : %s[%s] = {",
out.println(") : %s[%s] = {",
function.isAggregate() ? AggregateFunction.class : Field.class,
functionType);
out.tab(2).println("val %s = new %s", localVar, className);
}
else {
out.println(") {");
out.println(") {");
out.tab(2).println("%s %s = new %s();", className, localVar, className);
}
@ -5402,10 +5531,10 @@ public class JavaGenerator extends AbstractGenerator {
String glue = "";
if (!instance) {
if (scala)
out.print("%s : %s", configurationArgument, Configuration.class);
else
out.print("%s %s", Configuration.class, configurationArgument);
if (scala)
out.print("%s : %s", configurationArgument, Configuration.class);
else
out.print("%s %s", Configuration.class, configurationArgument);
glue = ", ";
}
@ -5420,7 +5549,7 @@ public class JavaGenerator extends AbstractGenerator {
final String paramMember = getStrategy().getJavaMemberName(parameter);
if (scala)
out.print("%s%s : %s", glue, paramMember, paramType);
out.print("%s%s : %s", glue, paramMember, paramType);
else
out.print("%s%s %s", glue, paramType, paramMember);
@ -5428,7 +5557,7 @@ public class JavaGenerator extends AbstractGenerator {
}
if (scala) {
out.println(") : %s = {", functionType);
out.println(") : %s = {", functionType);
out.tab(2).println("val %s = new %s()", localVar, className);
}
else {
@ -5482,7 +5611,7 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).javadoc("Call <code>%s</code>", procedure.getQualifiedOutputName());
if (scala) {
out.tab(1).print("def ");
out.tab(1).print("def ");
}
else {
out.tab(1).print("public ");
@ -5508,10 +5637,10 @@ public class JavaGenerator extends AbstractGenerator {
String glue = "";
if (!instance) {
if (scala)
out.print("%s : %s", configurationArgument, Configuration.class);
else
out.print("%s %s", Configuration.class, configurationArgument);
if (scala)
out.print("%s : %s", configurationArgument, Configuration.class);
else
out.print("%s %s", Configuration.class, configurationArgument);
glue = ", ";
}
@ -5594,24 +5723,24 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(2).println("from((%s) %s.%s());", columnTypeInterface, localVar, getter);
}
else {
if (scala)
if (scala)
out.tab(2).println("from(%s.%s)", localVar, getter);
else
out.tab(2).println("from(%s.%s());", localVar, getter);
else
out.tab(2).println("from(%s.%s());", localVar, getter);
}
}
if (outParams.size() == 1) {
if (scala)
if (scala)
out.tab(2).println("return %s.%s", localVar, getter);
else
out.tab(2).println("return %s.%s();", localVar, getter);
else
out.tab(2).println("return %s.%s();", localVar, getter);
}
else if (outParams.size() > 1) {
if (scala)
if (scala)
out.tab(2).println("return %s", localVar);
else
out.tab(2).println("return %s;", localVar);
else
out.tab(2).println("return %s;", localVar);
}
}
@ -5780,10 +5909,10 @@ public class JavaGenerator extends AbstractGenerator {
boolean hasCatalogVersion = !StringUtils.isBlank(catalogVersions.get(catalog));
boolean hasSchemaVersion = !StringUtils.isBlank(schemaVersions.get(schema));
if (scala)
if (scala)
out.tab(1).println("value = %s(", out.ref("scala.Array"));
else
out.tab(1).println("value = {");
else
out.tab(1).println("value = {");
out.tab(2).println("\"http://www.jooq.org\",");
out.tab(2).println("\"jOOQ version:%s\"%s", Constants.VERSION, (hasCatalogVersion || hasSchemaVersion ? "," : ""));
@ -5802,10 +5931,10 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).println("comments = \"This class is generated by jOOQ\"");
}
else {
if (scala)
if (scala)
out.tab(1).println("value = %s(", out.ref("scala.Array"));
else
out.tab(1).println("value = {");
else
out.tab(1).println("value = {");
out.tab(2).println("\"http://www.jooq.org\",");
out.tab(2).println("\"jOOQ version:%s\"", Constants.VERSION);

View File

@ -173,6 +173,12 @@
</bindings>
<bindings if-exists="true" scd="~tns:Embeddables">
<class ref="org.jooq.meta.jaxb.Embeddables"/>
</bindings>
<bindings if-exists="true" scd="~tns:ForcedTypes">
<class ref="org.jooq.meta.jaxb.ForcedTypes"/>
@ -191,6 +197,24 @@
</bindings>
<bindings if-exists="true" scd="~tns:Embeddable">
<class ref="org.jooq.meta.jaxb.Embeddable"/>
</bindings>
<bindings if-exists="true" scd="~tns:EmbeddableFields">
<class ref="org.jooq.meta.jaxb.EmbeddableFields"/>
</bindings>
<bindings if-exists="true" scd="~tns:EmbeddableField">
<class ref="org.jooq.meta.jaxb.EmbeddableField"/>
</bindings>
<bindings if-exists="true" scd="~tns:ForcedType">
<class ref="org.jooq.meta.jaxb.ForcedType"/>

View File

@ -40,6 +40,7 @@ package org.jooq.meta;
import static org.jooq.impl.DSL.falseCondition;
import static org.jooq.meta.AbstractTypedElementDefinition.customType;
import static org.jooq.tools.StringUtils.defaultIfEmpty;
import java.io.IOException;
import java.io.StringReader;
@ -76,6 +77,8 @@ import org.jooq.impl.DefaultExecuteListenerProvider;
import org.jooq.impl.SQLDataType;
import org.jooq.meta.jaxb.CatalogMappingType;
import org.jooq.meta.jaxb.CustomType;
import org.jooq.meta.jaxb.Embeddable;
import org.jooq.meta.jaxb.EmbeddableField;
import org.jooq.meta.jaxb.EnumType;
import org.jooq.meta.jaxb.ForcedType;
import org.jooq.meta.jaxb.ForcedTypeObjectType;
@ -112,6 +115,7 @@ public abstract class AbstractDatabase implements Database {
private boolean includeExcludeColumns;
private boolean includeInvisibleColumns = true;
private boolean includeTables = true;
private boolean includeEmbeddables = true;
private boolean includeRoutines = true;
private boolean includeTriggerRoutines = false;
private boolean includePackages = true;
@ -138,6 +142,7 @@ public abstract class AbstractDatabase implements Database {
private List<CustomType> configuredCustomTypes;
private List<EnumType> configuredEnumTypes;
private List<ForcedType> configuredForcedTypes;
private List<Embeddable> configuredEmbeddables;
private SchemaVersionProvider schemaVersionProvider;
private CatalogVersionProvider catalogVersionProvider;
private Comparator<Definition> orderProvider;
@ -161,6 +166,7 @@ public abstract class AbstractDatabase implements Database {
private List<ForeignKeyDefinition> foreignKeys;
private List<CheckConstraintDefinition> checkConstraints;
private List<TableDefinition> tables;
private List<EmbeddableDefinition> embeddables;
private List<EnumDefinition> enums;
private List<DomainDefinition> domains;
private List<UDTDefinition> udts;
@ -177,6 +183,8 @@ public abstract class AbstractDatabase implements Database {
private transient Map<SchemaDefinition, List<ForeignKeyDefinition>> foreignKeysBySchema;
private transient Map<SchemaDefinition, List<CheckConstraintDefinition>> checkConstraintsBySchema;
private transient Map<SchemaDefinition, List<TableDefinition>> tablesBySchema;
private transient Map<SchemaDefinition, List<EmbeddableDefinition>> embeddablesBySchema;
private transient Map<TableDefinition, List<EmbeddableDefinition>> embeddablesByTable;
private transient Map<SchemaDefinition, List<EnumDefinition>> enumsBySchema;
private transient Map<SchemaDefinition, List<UDTDefinition>> udtsBySchema;
private transient Map<SchemaDefinition, List<ArrayDefinition>> arraysBySchema;
@ -357,6 +365,9 @@ public abstract class AbstractDatabase implements Database {
}
final boolean matches(Pattern pattern, Definition definition) {
if (pattern == null)
return false;
if (!getRegexMatchesPartialQualification())
return pattern.matcher(definition.getName()).matches()
|| pattern.matcher(definition.getQualifiedName()).matches();
@ -371,6 +382,9 @@ public abstract class AbstractDatabase implements Database {
}
final Pattern pattern(String regex) {
if (regex == null)
return null;
Pattern pattern = patterns.get(regex);
if (pattern == null) {
@ -766,6 +780,16 @@ public abstract class AbstractDatabase implements Database {
this.includeTables = includeTables;
}
@Override
public final boolean getIncludeEmbeddables() {
return includeEmbeddables;
}
@Override
public final void setIncludeEmbeddables(boolean includeEmbeddables) {
this.includeEmbeddables = includeEmbeddables;
}
@Override
public final boolean getIncludeRoutines() {
return includeRoutines;
@ -1453,6 +1477,84 @@ public abstract class AbstractDatabase implements Database {
return null;
}
@Override
public final void setConfiguredEmbeddables(List<Embeddable> configuredEmbeddables) {
this.configuredEmbeddables = configuredEmbeddables;
}
@Override
public final List<Embeddable> getConfiguredEmbeddables() {
if (configuredEmbeddables == null)
configuredEmbeddables = new ArrayList<Embeddable>();
return configuredEmbeddables;
}
@Override
public final List<EmbeddableDefinition> getEmbeddables() {
List<EmbeddableDefinition> result = new ArrayList<EmbeddableDefinition>();
for (SchemaDefinition schema : getSchemata()) {
for (TableDefinition table : getTables(schema)) {
for (Embeddable embeddable : getConfiguredEmbeddables()) {
List<ColumnDefinition> columns = new ArrayList<ColumnDefinition>();
List<String> names = new ArrayList<String>();
for (EmbeddableField embeddableField : embeddable.getFields()) {
boolean matched = false;
for (ColumnDefinition column : table.getColumns())
if (matches(pattern(embeddableField.getExpression()), column))
if (matched)
log.warn("EmbeddableField configuration matched several columns in table " + table + ": " + embeddableField);
else
matched = columns.add(column) && names.add(defaultIfEmpty(embeddableField.getName(), column.getName()));
}
if (columns.size() == embeddable.getFields().size())
result.add(new DefaultEmbeddableDefinition(embeddable.getName(), names, table, columns));
}
}
}
return result;
}
@Override
public final List<EmbeddableDefinition> getEmbeddables(SchemaDefinition schema) {
if (embeddables == null) {
embeddables = new ArrayList<EmbeddableDefinition>();
if (getIncludeEmbeddables()) {
try {
List<EmbeddableDefinition> r = getEmbeddables();
embeddables = sort(r);
// indexes = sort(filterExcludeInclude(r)); TODO Support include / exclude for indexes (and constraints!)
log.info("Embeddables fetched", fetchedSize(r, embeddables));
}
catch (Exception e) {
log.error("Error while fetching embeddables", e);
}
}
else
log.info("Embeddables excluded");
}
if (embeddablesBySchema == null)
embeddablesBySchema = new LinkedHashMap<SchemaDefinition, List<EmbeddableDefinition>>();
return filterSchema(embeddables, schema, embeddablesBySchema);
}
@Override
public final List<EmbeddableDefinition> getEmbeddables(TableDefinition table) {
if (embeddablesByTable == null)
embeddablesByTable = new LinkedHashMap<TableDefinition, List<EmbeddableDefinition>>();
return filterTable(getEmbeddables(table.getSchema()), table, embeddablesByTable);
}
@Override
public final EnumDefinition getEnum(SchemaDefinition schema, String name) {
return getEnum(schema, name, false);
@ -1795,18 +1897,40 @@ public abstract class AbstractDatabase implements Database {
}
protected final <T extends Definition> List<T> filterSchema(List<T> definitions, SchemaDefinition schema) {
if (schema == null) {
if (schema == null)
return definitions;
}
else {
List<T> result = new ArrayList<T>();
for (T definition : definitions)
if (definition.getSchema().equals(schema))
result.add(definition);
List<T> result = new ArrayList<T>();
return result;
for (T definition : definitions)
if (definition.getSchema().equals(schema))
result.add(definition);
return result;
}
protected final <T extends TableElementDefinition> List<T> filterTable(List<T> definitions, TableDefinition table, Map<TableDefinition, List<T>> cache) {
List<T> result = cache.get(table);
if (result == null) {
result = filterTable(definitions, table);
cache.put(table, result);
}
return result;
}
protected final <T extends TableElementDefinition> List<T> filterTable(List<T> definitions, TableDefinition table) {
if (table == null)
return definitions;
List<T> result = new ArrayList<T>();
for (T definition : definitions)
if (definition.getTable().equals(table))
result.add(definition);
return result;
}
@Override

View File

@ -57,9 +57,9 @@ public abstract class AbstractTableDefinition
extends AbstractElementContainerDefinition<ColumnDefinition>
implements TableDefinition {
private List<ParameterDefinition> parameters;
private TableDefinition parentTable;
private List<TableDefinition> childTables;
private List<ParameterDefinition> parameters;
private TableDefinition parentTable;
private List<TableDefinition> childTables;
public AbstractTableDefinition(SchemaDefinition schema, String name, String comment) {
super(schema, name, comment);
@ -68,6 +68,11 @@ implements TableDefinition {
this.childTables = new ArrayList<TableDefinition>();
}
@Override
public final List<EmbeddableDefinition> getEmbeddables() {
return getDatabase().getEmbeddables(this);
}
@Override
public final UniqueKeyDefinition getPrimaryKey() {
UniqueKeyDefinition primaryKey = null;

View File

@ -49,6 +49,7 @@ import org.jooq.SQLDialect;
import org.jooq.Table;
import org.jooq.meta.jaxb.CatalogMappingType;
import org.jooq.meta.jaxb.CustomType;
import org.jooq.meta.jaxb.Embeddable;
import org.jooq.meta.jaxb.EnumType;
import org.jooq.meta.jaxb.ForcedType;
import org.jooq.meta.jaxb.RegexFlag;
@ -151,6 +152,21 @@ public interface Database extends AutoCloseable {
*/
TableDefinition getTable(SchemaDefinition schema, Name name, boolean ignoreCase);
/**
* Get all embeddables.
*/
List<EmbeddableDefinition> getEmbeddables();
/**
* Get all embeddables for a given schema.
*/
List<EmbeddableDefinition> getEmbeddables(SchemaDefinition schema);
/**
* Get all embeddables for a given table.
*/
List<EmbeddableDefinition> getEmbeddables(TableDefinition table);
/**
* The enum UDTs defined in this database.
*/
@ -511,6 +527,16 @@ public interface Database extends AutoCloseable {
*/
boolean getIncludeTables();
/**
* Whether embeddable types should be included.
*/
void setIncludeEmbeddables(boolean includeEmbeddables);
/**
* Whether embeddable types should be included.
*/
boolean getIncludeEmbeddables();
/**
* Whether invisible columns should be included.
*/
@ -755,6 +781,17 @@ public interface Database extends AutoCloseable {
*/
ForcedType getConfiguredForcedType(Definition definition, DataTypeDefinition definedType);
/**
* Configure the embeddable types.
*/
void setConfiguredEmbeddables(List<Embeddable> configuredEmbeddables);
/**
* Get the configured embeddable type definitions for any given
* {@link Definition}.
*/
List<Embeddable> getConfiguredEmbeddables();
/**
* Get the dialect for this database.
*/

View File

@ -0,0 +1,66 @@
/*
* 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.meta;
/**
* @author Lukas Eder
*/
public class DefaultEmbeddableColumnDefinition
extends AbstractTypedElementDefinition<EmbeddableDefinition>
implements EmbeddableColumnDefinition {
private final ColumnDefinition column;
private final int position;
public DefaultEmbeddableColumnDefinition(EmbeddableDefinition container, String name, ColumnDefinition column, int position) {
super(container, name, position, column.getDefinedType(), column.getComment());
this.column = column;
this.position = position;
}
@Override
public final int getPosition() {
return position;
}
@Override
public final ColumnDefinition getColumn() {
return column;
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.meta;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @author Lukas Eder
*/
public class DefaultEmbeddableDefinition
extends AbstractElementContainerDefinition<EmbeddableColumnDefinition>
implements EmbeddableDefinition {
private final List<String> columnNames;
private final TableDefinition table;
private final List<EmbeddableColumnDefinition> embeddableColumns;
public DefaultEmbeddableDefinition(String name, List<String> columnNames, TableDefinition table, List<ColumnDefinition> columns) {
super(table.getSchema(), name, "");
this.columnNames = columnNames;
this.table = table;
this.embeddableColumns = new ArrayList<EmbeddableColumnDefinition>();
for (int i = 0; i < columns.size(); i++)
embeddableColumns.add(new DefaultEmbeddableColumnDefinition(this, columnNames.get(i), columns.get(i), i));
}
@Override
public final TableDefinition getTable() {
return table;
}
@Override
protected List<EmbeddableColumnDefinition> getElements0() throws SQLException {
return embeddableColumns;
}
@Override
public final List<EmbeddableColumnDefinition> getColumns() {
return getElements();
}
@Override
public final EmbeddableColumnDefinition getColumn(String columnName) {
return getElement(columnName);
}
@Override
public final EmbeddableColumnDefinition getColumn(String columnName, boolean ignoreCase) {
return getElement(columnName, ignoreCase);
}
@Override
public final EmbeddableColumnDefinition getColumn(int columnIndex) {
return getElement(columnIndex);
}
}

View File

@ -0,0 +1,58 @@
/*
* 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.meta;
/**
* An interface defining a column of an embeddable type.
*
* @author Lukas Eder
*/
public interface EmbeddableColumnDefinition extends TypedElementDefinition<EmbeddableDefinition> {
/**
* The column position in the embeddable type.
*/
int getPosition();
/**
* The backing column definition.
*/
ColumnDefinition getColumn();
}

View File

@ -0,0 +1,70 @@
/*
* 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.meta;
import java.util.List;
/**
* The definition of an embeddable type.
*
* @author Lukas Eder
*/
public interface EmbeddableDefinition extends TableElementDefinition {
/**
* All columns in the type, table or view.
*/
List<EmbeddableColumnDefinition> getColumns();
/**
* Get a column in this type by its name.
*/
EmbeddableColumnDefinition getColumn(String columnName);
/**
* Get a column in this type by its name.
*/
EmbeddableColumnDefinition getColumn(String columnName, boolean ignoreCase);
/**
* Get a column in this type by its index (starting at 0).
*/
EmbeddableColumnDefinition getColumn(int columnIndex);
}

View File

@ -44,12 +44,7 @@ import java.util.List;
*
* @author Lukas Eder
*/
public interface IndexDefinition extends Definition {
/**
* The table holding this index.
*/
TableDefinition getTable();
public interface IndexDefinition extends TableElementDefinition {
/**
* The list of columns making up the index.

View File

@ -70,6 +70,11 @@ public interface TableDefinition extends Definition {
*/
ColumnDefinition getColumn(int columnIndex);
/**
* All embeddable types in the table.
*/
List<EmbeddableDefinition> getEmbeddables();
/**
* Get the indexes for this table.
*/

View File

@ -0,0 +1,53 @@
/*
* 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.meta;
/**
* The definition of an object that is contained in a table.
*
* @author Lukas Eder
*/
public interface TableElementDefinition extends Definition {
/**
* The table that this object is part of.
*/
TableDefinition getTable();
}

View File

@ -57,6 +57,8 @@ public class Database implements Serializable
@XmlElement(defaultValue = "true")
protected Boolean includeTables = true;
@XmlElement(defaultValue = "true")
protected Boolean includeEmbeddables = true;
@XmlElement(defaultValue = "true")
protected Boolean includeRoutines = true;
@XmlElement(defaultValue = "false")
protected Boolean includeTriggerRoutines = false;
@ -140,6 +142,9 @@ public class Database implements Serializable
@XmlElementWrapper(name = "schemata")
@XmlElement(name = "schema")
protected List<SchemaMappingType> schemata;
@XmlElementWrapper(name = "embeddables")
@XmlElement(name = "embeddable")
protected List<Embeddable> embeddables;
@XmlElementWrapper(name = "customTypes")
@XmlElement(name = "customType")
protected List<CustomType> customTypes;
@ -379,6 +384,30 @@ public class Database implements Serializable
this.includeTables = value;
}
/**
* This flag indicates whether embeddable types should be included in output produced by this database
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isIncludeEmbeddables() {
return includeEmbeddables;
}
/**
* Sets the value of the includeEmbeddables property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setIncludeEmbeddables(Boolean value) {
this.includeEmbeddables = value;
}
/**
* This flag indicates whether routines should be included in output produced by this database
*
@ -1299,6 +1328,17 @@ public class Database implements Serializable
this.schemata = schemata;
}
public List<Embeddable> getEmbeddables() {
if (embeddables == null) {
embeddables = new ArrayList<Embeddable>();
}
return embeddables;
}
public void setEmbeddables(List<Embeddable> embeddables) {
this.embeddables = embeddables;
}
public List<CustomType> getCustomTypes() {
if (customTypes == null) {
customTypes = new ArrayList<CustomType>();
@ -1378,6 +1418,11 @@ public class Database implements Serializable
return this;
}
public Database withIncludeEmbeddables(Boolean value) {
setIncludeEmbeddables(value);
return this;
}
public Database withIncludeRoutines(Boolean value) {
setIncludeRoutines(value);
return this;
@ -1606,6 +1651,27 @@ public class Database implements Serializable
return this;
}
public Database withEmbeddables(Embeddable... values) {
if (values!= null) {
for (Embeddable value: values) {
getEmbeddables().add(value);
}
}
return this;
}
public Database withEmbeddables(Collection<Embeddable> values) {
if (values!= null) {
getEmbeddables().addAll(values);
}
return this;
}
public Database withEmbeddables(List<Embeddable> embeddables) {
setEmbeddables(embeddables);
return this;
}
public Database withCustomTypes(CustomType... values) {
if (values!= null) {
for (CustomType value: values) {
@ -1711,6 +1777,11 @@ public class Database implements Serializable
sb.append(includeTables);
sb.append("</includeTables>");
}
if (includeEmbeddables!= null) {
sb.append("<includeEmbeddables>");
sb.append(includeEmbeddables);
sb.append("</includeEmbeddables>");
}
if (includeRoutines!= null) {
sb.append("<includeRoutines>");
sb.append(includeRoutines);
@ -1903,6 +1974,15 @@ public class Database implements Serializable
}
sb.append("</schemata>");
}
if (embeddables!= null) {
sb.append("<embeddables>");
for (int i = 0; (i<embeddables.size()); i ++) {
sb.append("<embeddable>");
sb.append(embeddables.get(i));
sb.append("</embeddable>");
}
sb.append("</embeddables>");
}
if (customTypes!= null) {
sb.append("<customTypes>");
for (int i = 0; (i<customTypes.size()); i ++) {
@ -2008,6 +2088,15 @@ public class Database implements Serializable
return false;
}
}
if (includeEmbeddables == null) {
if (other.includeEmbeddables!= null) {
return false;
}
} else {
if (!includeEmbeddables.equals(other.includeEmbeddables)) {
return false;
}
}
if (includeRoutines == null) {
if (other.includeRoutines!= null) {
return false;
@ -2332,6 +2421,15 @@ public class Database implements Serializable
return false;
}
}
if (embeddables == null) {
if (other.embeddables!= null) {
return false;
}
} else {
if (!embeddables.equals(other.embeddables)) {
return false;
}
}
if (customTypes == null) {
if (other.customTypes!= null) {
return false;
@ -2373,6 +2471,7 @@ public class Database implements Serializable
result = ((prime*result)+((excludes == null)? 0 :excludes.hashCode()));
result = ((prime*result)+((includeExcludeColumns == null)? 0 :includeExcludeColumns.hashCode()));
result = ((prime*result)+((includeTables == null)? 0 :includeTables.hashCode()));
result = ((prime*result)+((includeEmbeddables == null)? 0 :includeEmbeddables.hashCode()));
result = ((prime*result)+((includeRoutines == null)? 0 :includeRoutines.hashCode()));
result = ((prime*result)+((includeTriggerRoutines == null)? 0 :includeTriggerRoutines.hashCode()));
result = ((prime*result)+((includePackages == null)? 0 :includePackages.hashCode()));
@ -2409,6 +2508,7 @@ public class Database implements Serializable
result = ((prime*result)+((properties == null)? 0 :properties.hashCode()));
result = ((prime*result)+((catalogs == null)? 0 :catalogs.hashCode()));
result = ((prime*result)+((schemata == null)? 0 :schemata.hashCode()));
result = ((prime*result)+((embeddables == null)? 0 :embeddables.hashCode()));
result = ((prime*result)+((customTypes == null)? 0 :customTypes.hashCode()));
result = ((prime*result)+((enumTypes == null)? 0 :enumTypes.hashCode()));
result = ((prime*result)+((forcedTypes == null)? 0 :forcedTypes.hashCode()));

View File

@ -0,0 +1,170 @@
package org.jooq.meta.jaxb;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.jooq.util.jaxb.tools.StringAdapter;
/**
* An embeddable type declaration
*
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Embeddable", propOrder = {
})
@SuppressWarnings({
"all"
})
public class Embeddable implements Serializable
{
private final static long serialVersionUID = 31200L;
@XmlJavaTypeAdapter(StringAdapter.class)
protected String name;
@XmlElementWrapper(name = "fields")
@XmlElement(name = "field")
protected List<EmbeddableField> fields;
/**
* The name of the embeddable type
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
public List<EmbeddableField> getFields() {
if (fields == null) {
fields = new ArrayList<EmbeddableField>();
}
return fields;
}
public void setFields(List<EmbeddableField> fields) {
this.fields = fields;
}
public Embeddable withName(String value) {
setName(value);
return this;
}
public Embeddable withFields(EmbeddableField... values) {
if (values!= null) {
for (EmbeddableField value: values) {
getFields().add(value);
}
}
return this;
}
public Embeddable withFields(Collection<EmbeddableField> values) {
if (values!= null) {
getFields().addAll(values);
}
return this;
}
public Embeddable withFields(List<EmbeddableField> fields) {
setFields(fields);
return this;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (name!= null) {
sb.append("<name>");
sb.append(name);
sb.append("</name>");
}
if (fields!= null) {
sb.append("<fields>");
for (int i = 0; (i<fields.size()); i ++) {
sb.append("<field>");
sb.append(fields.get(i));
sb.append("</field>");
}
sb.append("</fields>");
}
return sb.toString();
}
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass()!= that.getClass()) {
return false;
}
Embeddable other = ((Embeddable) that);
if (name == null) {
if (other.name!= null) {
return false;
}
} else {
if (!name.equals(other.name)) {
return false;
}
}
if (fields == null) {
if (other.fields!= null) {
return false;
}
} else {
if (!fields.equals(other.fields)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = ((prime*result)+((name == null)? 0 :name.hashCode()));
result = ((prime*result)+((fields == null)? 0 :fields.hashCode()));
return result;
}
}

View File

@ -0,0 +1,173 @@
package org.jooq.meta.jaxb;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.jooq.util.jaxb.tools.StringAdapter;
/**
* <p>Java class for EmbeddableField complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType name="EmbeddableField"&gt;
* &lt;complexContent&gt;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
* &lt;all&gt;
* &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
* &lt;element name="expression" type="{http://www.w3.org/2001/XMLSchema}string"/&gt;
* &lt;/all&gt;
* &lt;/restriction&gt;
* &lt;/complexContent&gt;
* &lt;/complexType&gt;
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "EmbeddableField", propOrder = {
})
@SuppressWarnings({
"all"
})
public class EmbeddableField implements Serializable
{
private final static long serialVersionUID = 31200L;
@XmlJavaTypeAdapter(StringAdapter.class)
protected String name;
@XmlElement(required = true)
@XmlJavaTypeAdapter(StringAdapter.class)
protected String expression;
/**
* A name for the field in case the regex does not produce unique names for all matches.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
/**
* A regex matching all column names that are part of the embeddable type. The regex must match only one column per table.
*
* @return
* possible object is
* {@link String }
*
*/
public String getExpression() {
return expression;
}
/**
* Sets the value of the expression property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setExpression(String value) {
this.expression = value;
}
public EmbeddableField withName(String value) {
setName(value);
return this;
}
public EmbeddableField withExpression(String value) {
setExpression(value);
return this;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (name!= null) {
sb.append("<name>");
sb.append(name);
sb.append("</name>");
}
if (expression!= null) {
sb.append("<expression>");
sb.append(expression);
sb.append("</expression>");
}
return sb.toString();
}
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass()!= that.getClass()) {
return false;
}
EmbeddableField other = ((EmbeddableField) that);
if (name == null) {
if (other.name!= null) {
return false;
}
} else {
if (!name.equals(other.name)) {
return false;
}
}
if (expression == null) {
if (other.expression!= null) {
return false;
}
} else {
if (!expression.equals(other.expression)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = ((prime*result)+((name == null)? 0 :name.hashCode()));
result = ((prime*result)+((expression == null)? 0 :expression.hashCode()));
return result;
}
}

View File

@ -67,6 +67,8 @@ public class Generate implements Serializable
@XmlElement(defaultValue = "true")
protected Boolean tables = true;
@XmlElement(defaultValue = "true")
protected Boolean embeddables = true;
@XmlElement(defaultValue = "true")
protected Boolean records = true;
@XmlElement(defaultValue = "true")
protected Boolean recordsImplementingRecordN = true;
@ -534,6 +536,30 @@ public class Generate implements Serializable
this.tables = value;
}
/**
* Generate embeddable classes.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isEmbeddables() {
return embeddables;
}
/**
* Sets the value of the embeddables property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setEmbeddables(Boolean value) {
this.embeddables = value;
}
/**
* Generate TableRecord classes.
*
@ -1835,6 +1861,11 @@ public class Generate implements Serializable
return this;
}
public Generate withEmbeddables(Boolean value) {
setEmbeddables(value);
return this;
}
public Generate withRecords(Boolean value) {
setRecords(value);
return this;
@ -2163,6 +2194,11 @@ public class Generate implements Serializable
sb.append(tables);
sb.append("</tables>");
}
if (embeddables!= null) {
sb.append("<embeddables>");
sb.append(embeddables);
sb.append("</embeddables>");
}
if (records!= null) {
sb.append("<records>");
sb.append(records);
@ -2563,6 +2599,15 @@ public class Generate implements Serializable
return false;
}
}
if (embeddables == null) {
if (other.embeddables!= null) {
return false;
}
} else {
if (!embeddables.equals(other.embeddables)) {
return false;
}
}
if (records == null) {
if (other.records!= null) {
return false;
@ -3035,6 +3080,7 @@ public class Generate implements Serializable
result = ((prime*result)+((links == null)? 0 :links.hashCode()));
result = ((prime*result)+((keys == null)? 0 :keys.hashCode()));
result = ((prime*result)+((tables == null)? 0 :tables.hashCode()));
result = ((prime*result)+((embeddables == null)? 0 :embeddables.hashCode()));
result = ((prime*result)+((records == null)? 0 :records.hashCode()));
result = ((prime*result)+((recordsImplementingRecordN == null)? 0 :recordsImplementingRecordN.hashCode()));
result = ((prime*result)+((pojos == null)? 0 :pojos.hashCode()));

View File

@ -180,6 +180,22 @@ public class ObjectFactory {
return new EnumType();
}
/**
* Create an instance of {@link Embeddable }
*
*/
public Embeddable createEmbeddable() {
return new Embeddable();
}
/**
* Create an instance of {@link EmbeddableField }
*
*/
public EmbeddableField createEmbeddableField() {
return new EmbeddableField();
}
/**
* Create an instance of {@link ForcedType }
*

View File

@ -471,6 +471,10 @@ Excludes match before includes, i.e. excludes have a higher priority.]]></jxb:ja
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[This flag indicates whether tables should be included in output produced by this database]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="includeEmbeddables" type="boolean" default="true" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[This flag indicates whether embeddable types should be included in output produced by this database]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="includeRoutines" type="boolean" default="true" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[This flag indicates whether routines should be included in output produced by this database]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
@ -695,6 +699,10 @@ generated artefacts.]]></jxb:javadoc></jxb:property></appinfo></annotation>
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="embeddables" type="tns:Embeddables" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Configure embeddable types.]]></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>
@ -791,6 +799,12 @@ for Oracle.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</sequence>
</complexType>
<complexType name="Embeddables">
<sequence>
<element name="embeddable" type="tns:Embeddable" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="ForcedTypes">
<sequence>
<element name="forcedType" type="tns:ForcedType" minOccurs="0" maxOccurs="unbounded" />
@ -829,6 +843,38 @@ for Oracle.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</all>
</complexType>
<complexType name="Embeddable">
<annotation><appinfo><jxb:class><jxb:javadoc><![CDATA[An embeddable type declaration]]></jxb:javadoc></jxb:class></appinfo></annotation>
<all>
<element name="name" type="string" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The name of the embeddable type]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="fields" type="tns:EmbeddableFields" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A set of field specifications for the embeddable type.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
</all>
</complexType>
<complexType name="EmbeddableFields">
<sequence>
<element name="field" type="tns:EmbeddableField" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="EmbeddableField">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A field specification for an embeddable type.]]></jxb:javadoc></jxb:property></appinfo></annotation>
<all>
<element name="name" type="string" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A name for the field in case the regex does not produce unique names for all matches.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="expression" type="string" minOccurs="1" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A regex matching all column names that are part of the embeddable type. The regex must match only one column per table.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
</all>
</complexType>
<complexType name="ForcedType">
<annotation><appinfo><jxb:class><jxb:javadoc><![CDATA[A forced type declaration]]></jxb:javadoc></jxb:class></appinfo></annotation>
<all>
@ -959,6 +1005,10 @@ jOOQ version used for source code.]]></jxb:javadoc></jxb:property></appinfo></an
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Generate Table classes.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="embeddables" type="boolean" default="true" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Generate embeddable classes.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="records" type="boolean" default="true" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Generate TableRecord classes.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>

View File

@ -0,0 +1,65 @@
/*
* 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;
/**
* A record originating from a single table
*
* @param <R> The embeddable record type
* @author Lukas Eder
*/
public interface EmbeddableRecord<R extends EmbeddableRecord<R>> extends Record {
/**
* {@inheritDoc}
*/
@Override
R original();
/**
* {@inheritDoc}
*/
@Override
<T> R with(Field<T> field, T value);
/**
* {@inheritDoc}
*/
@Override
<T, U> R with(Field<T> field, U value, Converter<? extends T, ? super U> converter);
}

View File

@ -1460,32 +1460,26 @@ abstract class AbstractField<T> extends AbstractNamed implements Field<T> {
@SuppressWarnings("unchecked")
private final <Z extends Number> Field<Z> numeric() {
if (getDataType().isNumeric()) {
if (getDataType().isNumeric())
return (Field<Z>) this;
}
else {
else
return (Field<Z>) cast(BigDecimal.class);
}
}
@SuppressWarnings("unchecked")
private final Field<String> varchar() {
if (getDataType().isString()) {
if (getDataType().isString())
return (Field<String>) this;
}
else {
else
return cast(String.class);
}
}
@SuppressWarnings("unchecked")
private final <Z extends java.util.Date> Field<Z> date() {
if (getDataType().isTemporal()) {
if (getDataType().isTemporal())
return (Field<Z>) this;
}
else {
else
return (Field<Z>) cast(Timestamp.class);
}
}
@Override

View File

@ -40,7 +40,9 @@ package org.jooq.impl;
import static java.util.Arrays.asList;
import static org.jooq.conf.SettingsTools.updatablePrimaryKeys;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.indexOrFail;
import static org.jooq.impl.Tools.isEmbeddable;
import static org.jooq.impl.Tools.resetChangedOnNotNull;
import static org.jooq.impl.Tools.settings;
import static org.jooq.impl.Tools.ThreadGuard.Guard.RECORD_TOSTRING;
@ -62,6 +64,7 @@ import org.jooq.CSVFormat;
import org.jooq.ChartFormat;
import org.jooq.Converter;
import org.jooq.DataType;
import org.jooq.EmbeddableRecord;
import org.jooq.Field;
import org.jooq.JSONFormat;
import org.jooq.Name;
@ -240,7 +243,16 @@ abstract class AbstractRecord extends AbstractStore implements Record {
@Override
public final <T> T get(Field<T> field) {
return (T) get(indexOrFail(fieldsRow(), field));
if (field instanceof EmbeddableTableField) {
Field<?>[] f = embeddedFields(field);
return (T) Tools
.newRecord(fetched, ((EmbeddableTableField<?, ?>) field).recordType)
.operate(new TransferRecordState<Record>(f));
}
else {
return (T) get(indexOrFail(fieldsRow(), field));
}
}
@Override
@ -310,15 +322,24 @@ abstract class AbstractRecord extends AbstractStore implements Record {
}
protected final void set(int index, Object value) {
set(index, (Field) field(index), value);
set(index, field(index), value);
}
@Override
public final <T> void set(Field<T> field, T value) {
set(indexOrFail(fields, field), field, value);
if (isEmbeddable(field) && value instanceof EmbeddableRecord) {
Field<?>[] f = embeddedFields(field);
Object[] v = ((EmbeddableRecord) value).intoArray();
for (int i = 0; i < f.length; i++)
set(indexOrFail(fields, f[i]), f[i], v[i]);
}
else {
set(indexOrFail(fields, field), field, value);
}
}
final <T> void set(int index, Field<T> field, T value) {
final void set(int index, Field<?> field, Object value) {
// Relevant issues documenting this method's behaviour:
// [#945] Avoid bugs resulting from setting the same value twice
// [#948] To allow for controlling the number of hard-parses

View File

@ -55,10 +55,13 @@ import static org.jooq.SQLDialect.POSTGRES;
// ...
import static org.jooq.conf.ParamType.INLINED;
import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.row;
import static org.jooq.impl.Keywords.K_AS;
import static org.jooq.impl.Keywords.K_CAST;
import static org.jooq.impl.Keywords.K_ESCAPE;
import static org.jooq.impl.Keywords.K_VARCHAR;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.isEmbeddable;
import java.util.EnumSet;
@ -99,6 +102,13 @@ final class CompareCondition extends AbstractCondition implements LikeEscapeStep
@Override
public final void accept(Context<?> ctx) {
if (isEmbeddable(field1) && isEmbeddable(field2))
ctx.visit(row(embeddedFields(field1)).compare(comparator, embeddedFields(field2)));
else
accept0(ctx);
}
private final void accept0(Context<?> ctx) {
SQLDialect family = ctx.family();
Field<?> lhs = field1;
Field<?> rhs = field2;

View File

@ -0,0 +1,97 @@
/*
* 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.impl;
import org.jooq.Converter;
import org.jooq.EmbeddableRecord;
import org.jooq.Field;
import org.jooq.Row;
/**
* A record implementation for a record originating from a single table
* <p>
* This type is for JOOQ INTERNAL USE only. Do not reference directly
*
* @author Lukas Eder
*/
public class EmbeddableRecordImpl<R extends EmbeddableRecord<R>> extends AbstractRecord implements EmbeddableRecord<R> {
/**
* Generated UID
*/
private static final long serialVersionUID = -1260149220986944763L;
public EmbeddableRecordImpl(Field<?>... fields) {
super(fields);
}
@SuppressWarnings("unchecked")
@Override
public final <T> R with(Field<T> field, T value) {
return (R) super.with(field, value);
}
@SuppressWarnings("unchecked")
@Override
public final <T, U> R with(Field<T> field, U value, Converter<? extends T, ? super U> converter) {
return (R) super.with(field, value, converter);
}
/*
* Subclasses may override this method
*/
@Override
public Row fieldsRow() {
return fields;
}
/*
* Subclasses may override this method
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Row valuesRow() {
return new RowImpl(Tools.fields(intoArray(), fields.fields.fields()));
}
@SuppressWarnings("unchecked")
@Override
public final R original() {
return (R) super.original();
}
}

View File

@ -0,0 +1,87 @@
/*
* 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.impl;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_LIST_ALREADY_INDENTED;
import org.jooq.Context;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.SQLDialect;
import org.jooq.Table;
import org.jooq.TableField;
/**
* @author Lukas Eder
*/
final class EmbeddableTableField<R extends Record, T extends Record> extends AbstractField<T> implements TableField<R, T> {
/**
* Generated UID
*/
private static final long serialVersionUID = -7105430856294526440L;
final Table<R> table;
final TableField<R, ?>[] fields;
final Class<T> recordType;
EmbeddableTableField(Name name, Class<T> recordType, Table<R> table, TableField<R, ?>[] fields) {
super(name, new DefaultDataType<T>(SQLDialect.DEFAULT, recordType, name.last()));
this.table = table;
this.recordType = recordType;
this.fields = fields;
}
// -------------------------------------------------------------------------
// TableField API
// -------------------------------------------------------------------------
@Override
public final void accept(Context<?> ctx) {
Object previous = ctx.data(DATA_LIST_ALREADY_INDENTED);
ctx.data(DATA_LIST_ALREADY_INDENTED, true);
ctx.visit(new QueryPartList<TableField<?, ?>>(fields));
ctx.data(DATA_LIST_ALREADY_INDENTED, previous);
}
@Override
public final Table<R> getTable() {
return table;
}
}

View File

@ -43,6 +43,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
import static org.jooq.impl.Tools.flattenEntrySet;
import java.util.EnumSet;
import java.util.Map;
@ -87,12 +88,11 @@ final class FieldMapForUpdate extends AbstractQueryPartMap<Field<?>, Field<?>> {
boolean restoreQualify = ctx.qualify();
boolean supportsQualify = NO_SUPPORT_QUALIFY.contains(ctx.family()) ? false : restoreQualify;
for (Entry<Field<?>, Field<?>> entry : entrySet()) {
for (Entry<Field<?>, Field<?>> entry : flattenEntrySet(entrySet())) {
ctx.sql(separator);
if (!"".equals(separator)) {
if (!"".equals(separator))
ctx.formatNewLine();
}
ctx.start(assignmentClause)
.qualify(supportsQualify)

View File

@ -61,6 +61,13 @@ import org.jooq.UniqueKey;
*/
public final class Internal {
/**
* Factory method for embeddable types.
*/
public static final <R extends Record, T extends Record> TableField<R, T> createEmbeddable(Name name, Class<T> recordType, Table<R> table, TableField<R, ?>... fields) {
return new EmbeddableTableField<R, T>(name, recordType, table, fields);
}
/**
* Factory method for indexes.
*/

View File

@ -133,34 +133,39 @@ final class SortFieldImpl<T> extends AbstractQueryPart implements SortField<T> {
ctx.visit(nvl2(field, ifNotNull, ifNull))
.sql(", ");
acceptFieldAndOrder(ctx);
acceptFieldAndOrder(ctx, false);
break;
}
// DERBY, H2, HSQLDB, ORACLE, POSTGRES
default: {
acceptFieldAndOrder(ctx);
if (nullsFirst)
ctx.sql(' ').visit(K_NULLS_FIRST);
else
ctx.sql(' ').visit(K_NULLS_LAST);
acceptFieldAndOrder(ctx, true);
break;
}
}
}
else {
acceptFieldAndOrder(ctx);
acceptFieldAndOrder(ctx, false);
}
}
private final void acceptFieldAndOrder(Context<?> ctx) {
ctx.visit(field);
private final void acceptFieldAndOrder(Context<?> ctx, boolean includeNulls) {
String separator = "";
if (order != SortOrder.DEFAULT)
ctx.sql(' ')
.visit(order.toKeyword());
for (Field<?> f : Tools.flatten(field)) {
ctx.sql(separator).visit(f);
if (order != SortOrder.DEFAULT)
ctx.sql(' ')
.visit(order.toKeyword());
if (includeNulls)
if (nullsFirst)
ctx.sql(' ').visit(K_NULLS_FIRST);
else
ctx.sql(' ').visit(K_NULLS_LAST);
separator = ", ";
}
}
}

View File

@ -40,6 +40,7 @@ package org.jooq.impl;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static java.lang.Character.isJavaIdentifierPart;
import static java.util.Collections.singletonList;
// ...
// ...
// ...
@ -166,6 +167,7 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -176,6 +178,8 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@ -201,6 +205,7 @@ import org.jooq.Context;
import org.jooq.Cursor;
import org.jooq.DSLContext;
import org.jooq.DataType;
import org.jooq.EmbeddableRecord;
import org.jooq.EnumType;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
@ -4772,4 +4777,164 @@ final class Tools {
static final boolean isEmpty(Object[] array) {
return array == null || array.length == 0;
}
static final boolean isEmbeddable(Object object) {
return object instanceof EmbeddableTableField
|| object instanceof Val && ((Val<?>) object).value instanceof EmbeddableRecord
|| object instanceof EmbeddableRecord;
}
static final Field<?>[] embeddedFields(Object object) {
return object instanceof EmbeddableTableField
? ((EmbeddableTableField<?, ?>) object).fields
: object instanceof Val && ((Val<?>) object).value instanceof EmbeddableRecord
? ((EmbeddableRecord<?>) ((Val<?>) object).value).valuesRow().fields()
: object instanceof EmbeddableRecord
? ((EmbeddableRecord<?>) object).valuesRow().fields()
: null;
}
/**
* Flatten out an {@link EmbeddableTableField}.
*/
static final <E extends Field<?>> Iterable<E> flatten(final E field) {
return new Iterable<E>() {
@Override
public Iterator<E> iterator() {
Iterator<E> it = singletonList(field).iterator();
if (field instanceof EmbeddableTableField)
return new FlatteningIterator<E>(it) {
@SuppressWarnings("unchecked")
@Override
List<E> flatten(E e) {
return (List<E>) Arrays.asList(((EmbeddableTableField<?, ?>) e).fields);
}
};
else
return it;
}
};
}
/**
* Flatten out {@link EmbeddableTableField} elements contained in an
* ordinary iterable.
*/
static final <E extends Field<?>> Iterable<E> flattenCollection(final Iterable<E> iterable) {
return new Iterable<E>() {
@Override
public Iterator<E> iterator() {
return new FlatteningIterator<E>(iterable.iterator()) {
@SuppressWarnings("unchecked")
@Override
List<E> flatten(E e) {
if (e instanceof EmbeddableTableField)
return (List<E>) Arrays.asList(((EmbeddableTableField<?, ?>) e).fields);
return null;
}
};
}
};
}
/**
* Flatten out {@link EmbeddableTableField} elements contained in an
* entry set iterable.
*/
static final <E extends Entry<Field<?>, Field<?>>> Iterable<E> flattenEntrySet(final Iterable<E> iterable) {
return new Iterable<E>() {
@Override
public Iterator<E> iterator() {
return new FlatteningIterator<E>(iterable.iterator()) {
@SuppressWarnings("unchecked")
@Override
List<E> flatten(E e) {
if (e.getKey() instanceof EmbeddableTableField) {
List<E> result = new ArrayList<E>();
Field<?>[] keys = embeddedFields(e.getKey());
Field<?>[] values = embeddedFields(e.getValue());
for (int i = 0; i < keys.length; i++)
result.add((E) new SimpleImmutableEntry<Field<?>, Field<?>>(
keys[i], values[i]
));
return result;
}
return null;
}
};
}
};
}
/**
* A base implementation for {@link EmbeddableTableField} flattening
* iterators with a default implementation for {@link Iterator#remove()} for
* convenience in the Java 6 build.
*/
static abstract class FlatteningIterator<E> implements Iterator<E> {
private final Iterator<E> delegate;
private Iterator<E> flatten;
private E next;
FlatteningIterator(Iterator<E> delegate) {
this.delegate = delegate;
}
abstract List<E> flatten(E e);
private final void move() {
if (next == null) {
if (flatten != null) {
if (flatten.hasNext()) {
next = flatten.next();
return;
}
else {
flatten = null;
}
}
if (delegate.hasNext()) {
next = delegate.next();
List<E> flattened = flatten(next);
if (flattened == null)
return;
next = null;
flatten = flattened.iterator();
move();
return;
}
}
}
@Override
public final boolean hasNext() {
move();
return next != null;
}
@Override
public final E next() {
move();
if (next == null)
throw new NoSuchElementException();
E result = next;
next = null;
return result;
}
@Override
public final void remove() {
throw new UnsupportedOperationException("remove");
}
}
}

View File

@ -39,11 +39,15 @@ package org.jooq.impl;
import static org.jooq.conf.ParamType.NAMED;
import static org.jooq.conf.ParamType.NAMED_OR_INLINED;
import static org.jooq.impl.Tools.embeddedFields;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_LIST_ALREADY_INDENTED;
import java.sql.SQLException;
import org.jooq.Context;
import org.jooq.DataType;
import org.jooq.EmbeddableRecord;
import org.jooq.Field;
import org.jooq.RenderContext;
import org.jooq.conf.ParamType;
import org.jooq.exception.DataAccessException;
@ -70,7 +74,14 @@ final class Val<T> extends AbstractParam<T> {
@Override
public void accept(Context<?> ctx) {
if (ctx instanceof RenderContext) {
if (value instanceof EmbeddableRecord) {
Object previous = ctx.data(DATA_LIST_ALREADY_INDENTED);
ctx.data(DATA_LIST_ALREADY_INDENTED, true);
ctx.visit(new QueryPartList<Field<?>>(embeddedFields(this)));
ctx.data(DATA_LIST_ALREADY_INDENTED, previous);
}
else if (ctx instanceof RenderContext) {
ParamType paramType = ctx.paramType();
if (isInline(ctx))