[jOOQ/jOOQ#9734] Add <nonnullAnnotation/> and <nullableAnnotation/>

This commit is contained in:
Lukas Eder 2020-01-15 16:13:42 +01:00
parent 2323b2a3e1
commit c2eb2e0dc7
7 changed files with 251 additions and 44 deletions

View File

@ -66,7 +66,9 @@ abstract class AbstractGenerator implements Generator {
boolean generateInstanceFields = true;
boolean generateGeneratedAnnotation = false;
GeneratedAnnotationType generatedGeneratedAnnotationType = GeneratedAnnotationType.DETECT_FROM_JDK;
boolean generateNonnullAnnotation = false;
String generatedNonnullAnnotationType = "javax.annotation.Nonnull";
boolean generateNullableAnnotation = false;
String generatedNullableAnnotationType = "javax.annotation.Nullable";
boolean useSchemaVersionProvider = false;
boolean useCatalogVersionProvider = false;
@ -299,6 +301,16 @@ abstract class AbstractGenerator implements Generator {
this.generatedGeneratedAnnotationType = generateGeneratedAnnotationType;
}
@Override
public boolean generateNonnullAnnotation() {
return generateNonnullAnnotation;
}
@Override
public void setGenerateNonnullAnnotation(boolean generateNonnullAnnotation) {
this.generateNonnullAnnotation = generateNonnullAnnotation;
}
@Override
public String generatedNonnullAnnotationType() {
return generatedNonnullAnnotationType;
@ -309,6 +321,16 @@ abstract class AbstractGenerator implements Generator {
this.generatedNonnullAnnotationType = generatedNonnullAnnotationType;
}
@Override
public boolean generateNullableAnnotation() {
return generateNullableAnnotation;
}
@Override
public void setGenerateNullableAnnotation(boolean generateNullableAnnotation) {
this.generateNullableAnnotation = generateNullableAnnotation;
}
@Override
public String generatedNullableAnnotationType() {
return generatedNullableAnnotationType;

View File

@ -669,10 +669,14 @@ public class GenerationTool {
generator.setGenerateGeneratedAnnotation(g.getGenerate().isGeneratedAnnotation());
if (g.getGenerate().getGeneratedAnnotationType() != null)
generator.setGenerateGeneratedAnnotationType(g.getGenerate().getGeneratedAnnotationType());
if (g.getGenerate().getGeneratedNonnullAnnotationType() != null)
generator.setGeneratedNonnullAnnotationType(g.getGenerate().getGeneratedNonnullAnnotationType());
if (g.getGenerate().getGeneratedNullableAnnotationType() != null)
generator.setGeneratedNullableAnnotationType(g.getGenerate().getGeneratedNullableAnnotationType());
if (g.getGenerate().isNonnullAnnotation() != null)
generator.setGenerateNonnullAnnotation(g.getGenerate().isNonnullAnnotation());
if (g.getGenerate().getNonnullAnnotationType() != null)
generator.setGeneratedNonnullAnnotationType(g.getGenerate().getNonnullAnnotationType());
if (g.getGenerate().isNullableAnnotation() != null)
generator.setGenerateNullableAnnotation(g.getGenerate().isNullableAnnotation());
if (g.getGenerate().getNullableAnnotationType() != null)
generator.setGeneratedNullableAnnotationType(g.getGenerate().getNullableAnnotationType());
if (g.getGenerate().isRoutines() != null)
generator.setGenerateRoutines(g.getGenerate().isRoutines());
if (g.getGenerate().isSequences() != null)

View File

@ -157,6 +157,24 @@ public interface Generator {
*/
void setGenerateGeneratedAnnotationType(GeneratedAnnotationType generateGeneratedAnnotationType);
/**
* Whether Nonnull annotations should be generated.
* <p>
* In SQL and by consequence in jOOQ, non-nullability cannot be guaranteed
* statically. There may still be some cases (e.g. after unions, outer
* joins, etc.) where a normally non-null value turns out to be null!
*/
boolean generateNonnullAnnotation();
/**
* Whether Nonnull annotations should be generated.
* <p>
* In SQL and by consequence in jOOQ, non-nullability cannot be guaranteed
* statically. There may still be some cases (e.g. after unions, outer
* joins, etc.) where a normally non-null value turns out to be null!
*/
void setGenerateNonnullAnnotation(boolean generateNonnullAnnotation);
/**
* Which type of Nonnull annotation should be generated.
*/
@ -167,6 +185,24 @@ public interface Generator {
*/
void setGeneratedNonnullAnnotationType(String generatedNonnullAnnotationType);
/**
* Whether Nullable annotations should be generated.
* <p>
* Unlike {@link #generateNonnullAnnotation()}, nullability can be
* guaranteed as in SQL, and by consequence in jOOQ, every column expression
* can be made nullable using some SQL operation.
*/
boolean generateNullableAnnotation();
/**
* Whether Nullable annotations should be generated.
* <p>
* Unlike {@link #generateNonnullAnnotation()}, nullability can be
* guaranteed as in SQL, and by consequence in jOOQ, every column expression
* can be made nullable using some SQL operation.
*/
void setGenerateNullableAnnotation(boolean generateNullableAnnotation);
/**
* Which type of Nullable annotation should be generated.
*/

View File

@ -1441,6 +1441,8 @@ public class JavaGenerator extends AbstractGenerator {
else
out.tab(1).overrideInherit();
printNullableOrNonnullAnnotation(out, column);
out.tab(1).println("public %s component%s() {", colType, i);
out.tab(2).println("return %s();", colGetter);
out.tab(1).println("}");
@ -1465,6 +1467,8 @@ public class JavaGenerator extends AbstractGenerator {
else
out.tab(1).overrideInherit();
printNullableOrNonnullAnnotation(out, column);
out.tab(1).println("public %s value%s() {", colType, i);
out.tab(2).println("return %s();", colGetter);
out.tab(1).println("}");
@ -1488,13 +1492,14 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).println("}");
}
else {
final String nullableAnnotation = nullableOrNonnullAnnotation(out, column);
if (printDeprecationIfUnknownType(out, colTypeFull))
out.tab(1).override();
else
out.tab(1).overrideInherit();
out.tab(1).println("public %s value%s(%s value) {", className, i, varargsIfArray(colType));
out.tab(1).println("public %s value%s([[before=@][after= ][%s]]%s value) {", className, i, list(nullableAnnotation), varargsIfArray(colType));
out.tab(2).println("%s(value);", colSetter);
out.tab(2).println("return this;");
out.tab(1).println("}");
@ -1513,7 +1518,9 @@ public class JavaGenerator extends AbstractGenerator {
calls.add("this.value" + i + "(value" + i + ")");
}
else {
arguments.add(colType + " value" + i);
final String nullableAnnotation = nullableOrNonnullAnnotation(out, column);
arguments.add((nullableAnnotation == null ? "" : "@" + nullableAnnotation + " ") + colType + " value" + i);
calls.add("value" + i + "(value" + i + ");");
}
}
@ -1582,10 +1589,14 @@ public class JavaGenerator extends AbstractGenerator {
final String columnMember = getStrategy().getJavaMemberName(column, Mode.DEFAULT);
final String type = out.ref(getJavaType(column.getType(resolver())));
if (scala)
if (scala) {
arguments.add(columnMember + " : " + type);
else
arguments.add(type + " " + columnMember);
}
else {
final String nullableAnnotation = nullableOrNonnullAnnotation(out, column);
arguments.add((nullableAnnotation == null ? "" : "@" + nullableAnnotation + " ") + type + " " + columnMember);
}
}
out.tab(1).javadoc("Create a detached, initialised %s", className);
@ -1675,8 +1686,10 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).println("}");
}
else {
final String nullableAnnotation = nullableOrNonnullAnnotation(out, column);
out.tab(1).overrideIf(generateInterfaces() && !generateImmutableInterfaces() && !isUDT);
out.tab(1).println("public %s %s(%s value) {", setterReturnType, setter, varargsIfArray(type));
out.tab(1).println("public %s %s([[before=@][after= ][%s]]%s value) {", setterReturnType, setter, list(nullableAnnotation), varargsIfArray(type));
out.tab(2).println("set(%s, value);", index);
if (generateFluentSetters())
out.tab(2).println("return this;");
@ -1708,7 +1721,9 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).println("}");
}
else {
out.tab(1).println("public %s %s(%s value) {", setterReturnType, setter, varargsIfArray(columnTypeInterface));
final String nullableAnnotation = nullableOrNonnullAnnotation(out, column);
out.tab(1).println("public %s %s([[before=@][after= ][%s]]%s value) {", setterReturnType, setter, list(nullableAnnotation), varargsIfArray(columnTypeInterface));
out.tab(2).println("if (value == null)");
out.tab(3).println("set(%s, null);", index);
@ -1778,6 +1793,7 @@ public class JavaGenerator extends AbstractGenerator {
if (column instanceof ColumnDefinition)
printColumnJPAAnnotation(out, (ColumnDefinition) column);
printValidationAnnotation(out, column);
printNullableOrNonnullAnnotation(out, column);
if (scala) {
out.tab(1).println("def %s : %s = {", getter, type);
@ -1980,10 +1996,14 @@ public class JavaGenerator extends AbstractGenerator {
if (!printDeprecationIfUnknownType(out, typeFull))
out.tab(1).javadoc("Setter for <code>%s</code>.%s", name, columnComment(column, comment));
if (scala)
if (scala) {
out.tab(1).println("def %s(value : %s) : %s", setter, type, setterReturnType);
else
out.tab(1).println("public %s %s(%s value);", setterReturnType, setter, varargsIfArray(type));
}
else {
final String nullableAnnotation = nullableOrNonnullAnnotation(out, column);
out.tab(1).println("public %s %s([[before=@][after= ][%s]]%s value);", setterReturnType, setter, list(nullableAnnotation), varargsIfArray(type));
}
}
/**
@ -2014,6 +2034,7 @@ public class JavaGenerator extends AbstractGenerator {
printColumnJPAAnnotation(out, (ColumnDefinition) column);
printValidationAnnotation(out, column);
printNullableOrNonnullAnnotation(out, column);
if (scala)
out.tab(1).println("def %s : %s", getter, type);
@ -3375,9 +3396,11 @@ public class JavaGenerator extends AbstractGenerator {
String separator1 = "";
for (TypedElementDefinition<?> column : getTypedElements(tableOrUDT)) {
out.println(separator1);
final String nullableAnnotation = nullableOrNonnullAnnotation(out, column);
out.tab(2).print("%s %s",
out.println(separator1);
out.tab(2).print("[[before=@][after= ][%s]]%s %s",
list(nullableAnnotation),
StringUtils.rightPad(out.ref(getJavaType(column.getType(resolver(Mode.POJO)), Mode.POJO)), maxLength),
getStrategy().getJavaMemberName(column, Mode.POJO));
separator1 = ",";
@ -3506,6 +3529,7 @@ public class JavaGenerator extends AbstractGenerator {
printColumnJPAAnnotation(out, (ColumnDefinition) column);
printValidationAnnotation(out, column);
printNullableOrNonnullAnnotation(out, column);
if (scala) {
out.tab(1).println("def %s : %s = {", columnGetter, columnType);
@ -3558,8 +3582,10 @@ public class JavaGenerator extends AbstractGenerator {
out.tab(1).println("}");
}
else {
final String nullableAnnotation = nullableOrNonnullAnnotation(out, column);
out.tab(1).overrideIf(generateInterfaces() && !generateImmutableInterfaces() && !isUDT);
out.tab(1).println("public %s %s(%s %s) {", columnSetterReturnType, columnSetter, varargsIfArray(columnType), columnMember);
out.tab(1).println("public %s %s([[before=@][after= ][%s]]%s %s) {", columnSetterReturnType, columnSetter, list(nullableAnnotation), varargsIfArray(columnType), columnMember);
out.tab(2).println("this.%s = %s;", columnMember, columnMember);
if (generateFluentSetters())
out.tab(2).println("return this;");
@ -5253,6 +5279,31 @@ public class JavaGenerator extends AbstractGenerator {
}
}
private String nullableOrNonnullAnnotation(JavaWriter out, TypedElementDefinition<?> column) {
return column.getType().isNullable() && generateNullableAnnotation()
? out.ref(generatedNullableAnnotationType())
: !column.getType().isNullable() && generateNonnullAnnotation()
? out.ref(generatedNonnullAnnotationType())
: null;
}
private void printNullableOrNonnullAnnotation(JavaWriter out, TypedElementDefinition<?> column) {
if (column.getType().isNullable())
printNullableAnnotation(out);
else
printNonnullAnnotation(out);
}
protected void printNullableAnnotation(JavaWriter out) {
if (generateNullableAnnotation())
out.tab(1).println("@%s", out.ref(generatedNullableAnnotationType()));
}
protected void printNonnullAnnotation(JavaWriter out) {
if (generateNonnullAnnotation())
out.tab(1).println("@%s", out.ref(generatedNonnullAnnotationType()));
}
private boolean printDeprecationIfUnknownTypes(JavaWriter out, Collection<? extends ParameterDefinition> params) {
for (ParameterDefinition param : params)
if (printDeprecationIfUnknownType(out, getJavaType(param.getType(resolver()))))

View File

@ -49,12 +49,16 @@ public class Generate implements Serializable, XMLAppendable
@XmlElement(defaultValue = "DETECT_FROM_JDK")
@XmlSchemaType(name = "string")
protected GeneratedAnnotationType generatedAnnotationType = GeneratedAnnotationType.DETECT_FROM_JDK;
@XmlElement(defaultValue = "false")
protected Boolean nonnullAnnotation = false;
@XmlElement(defaultValue = "javax.annotation.Nonnull")
@XmlJavaTypeAdapter(StringAdapter.class)
protected String generatedNonnullAnnotationType = "javax.annotation.Nonnull";
protected String nonnullAnnotationType = "javax.annotation.Nonnull";
@XmlElement(defaultValue = "false")
protected Boolean nullableAnnotation = false;
@XmlElement(defaultValue = "javax.annotation.Nullable")
@XmlJavaTypeAdapter(StringAdapter.class)
protected String generatedNullableAnnotationType = "javax.annotation.Nullable";
protected String nullableAnnotationType = "javax.annotation.Nullable";
@XmlElement(defaultValue = "true")
protected Boolean routines = true;
@XmlElement(defaultValue = "true")
@ -393,35 +397,83 @@ public class Generate implements Serializable, XMLAppendable
}
/**
* Specify the qualified annotation name for all non-nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nonnull} type.
* Whether non-nullable items should be annotated with the annotation type specified in {@link #nonnullAnnotationType}. In SQL and by consequence in jOOQ, non-nullability cannot be guaranteed statically. There may still be some cases (e.g. after unions, outer joins, etc.) where a normally non-null value turns out to be null!
*
* @return
* possible object is
* {@link Boolean }
*
*/
public String getGeneratedNonnullAnnotationType() {
return generatedNonnullAnnotationType;
public Boolean isNonnullAnnotation() {
return nonnullAnnotation;
}
/**
* Sets the value of the nonnullAnnotation property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setNonnullAnnotation(Boolean value) {
this.nonnullAnnotation = value;
}
/**
* Specify the qualified annotation name for all non-nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nonnull} type.
*
*/
public void setGeneratedNonnullAnnotationType(String value) {
this.generatedNonnullAnnotationType = value;
public String getNonnullAnnotationType() {
return nonnullAnnotationType;
}
/**
* Specify the qualified annotation name for all non-nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nonnull} type.
*
*/
public void setNonnullAnnotationType(String value) {
this.nonnullAnnotationType = value;
}
/**
* Whether nullable items should be annotated with the annotation type specified in {@link #nullableAnnotationType}. Unlike {@link #nonnullAnnotation}, nullability can be guaranteed as in SQL, and by consequence in jOOQ, every column expression can be made nullable using some SQL operation.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isNullableAnnotation() {
return nullableAnnotation;
}
/**
* Sets the value of the nullableAnnotation property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setNullableAnnotation(Boolean value) {
this.nullableAnnotation = value;
}
/**
* Specify the qualified annotation name for all nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nullable} type.
*
*/
public String getGeneratedNullableAnnotationType() {
return generatedNullableAnnotationType;
public String getNullableAnnotationType() {
return nullableAnnotationType;
}
/**
* Specify the qualified annotation name for all nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nullable} type.
*
*/
public void setGeneratedNullableAnnotationType(String value) {
this.generatedNullableAnnotationType = value;
public void setNullableAnnotationType(String value) {
this.nullableAnnotationType = value;
}
/**
@ -1888,12 +1940,22 @@ public class Generate implements Serializable, XMLAppendable
return this;
}
public Generate withNonnullAnnotation(Boolean value) {
setNonnullAnnotation(value);
return this;
}
/**
* Specify the qualified annotation name for all non-nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nonnull} type.
*
*/
public Generate withGeneratedNonnullAnnotationType(String value) {
setGeneratedNonnullAnnotationType(value);
public Generate withNonnullAnnotationType(String value) {
setNonnullAnnotationType(value);
return this;
}
public Generate withNullableAnnotation(Boolean value) {
setNullableAnnotation(value);
return this;
}
@ -1901,8 +1963,8 @@ public class Generate implements Serializable, XMLAppendable
* Specify the qualified annotation name for all nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nullable} type.
*
*/
public Generate withGeneratedNullableAnnotationType(String value) {
setGeneratedNullableAnnotationType(value);
public Generate withNullableAnnotationType(String value) {
setNullableAnnotationType(value);
return this;
}
@ -2232,8 +2294,10 @@ public class Generate implements Serializable, XMLAppendable
builder.append("instanceFields", instanceFields);
builder.append("generatedAnnotation", generatedAnnotation);
builder.append("generatedAnnotationType", generatedAnnotationType);
builder.append("generatedNonnullAnnotationType", generatedNonnullAnnotationType);
builder.append("generatedNullableAnnotationType", generatedNullableAnnotationType);
builder.append("nonnullAnnotation", nonnullAnnotation);
builder.append("nonnullAnnotationType", nonnullAnnotationType);
builder.append("nullableAnnotation", nullableAnnotation);
builder.append("nullableAnnotationType", nullableAnnotationType);
builder.append("routines", routines);
builder.append("sequences", sequences);
builder.append("udts", udts);
@ -2395,21 +2459,39 @@ public class Generate implements Serializable, XMLAppendable
return false;
}
}
if (generatedNonnullAnnotationType == null) {
if (other.generatedNonnullAnnotationType!= null) {
if (nonnullAnnotation == null) {
if (other.nonnullAnnotation!= null) {
return false;
}
} else {
if (!generatedNonnullAnnotationType.equals(other.generatedNonnullAnnotationType)) {
if (!nonnullAnnotation.equals(other.nonnullAnnotation)) {
return false;
}
}
if (generatedNullableAnnotationType == null) {
if (other.generatedNullableAnnotationType!= null) {
if (nonnullAnnotationType == null) {
if (other.nonnullAnnotationType!= null) {
return false;
}
} else {
if (!generatedNullableAnnotationType.equals(other.generatedNullableAnnotationType)) {
if (!nonnullAnnotationType.equals(other.nonnullAnnotationType)) {
return false;
}
}
if (nullableAnnotation == null) {
if (other.nullableAnnotation!= null) {
return false;
}
} else {
if (!nullableAnnotation.equals(other.nullableAnnotation)) {
return false;
}
}
if (nullableAnnotationType == null) {
if (other.nullableAnnotationType!= null) {
return false;
}
} else {
if (!nullableAnnotationType.equals(other.nullableAnnotationType)) {
return false;
}
}
@ -2960,8 +3042,10 @@ public class Generate implements Serializable, XMLAppendable
result = ((prime*result)+((instanceFields == null)? 0 :instanceFields.hashCode()));
result = ((prime*result)+((generatedAnnotation == null)? 0 :generatedAnnotation.hashCode()));
result = ((prime*result)+((generatedAnnotationType == null)? 0 :generatedAnnotationType.hashCode()));
result = ((prime*result)+((generatedNonnullAnnotationType == null)? 0 :generatedNonnullAnnotationType.hashCode()));
result = ((prime*result)+((generatedNullableAnnotationType == null)? 0 :generatedNullableAnnotationType.hashCode()));
result = ((prime*result)+((nonnullAnnotation == null)? 0 :nonnullAnnotation.hashCode()));
result = ((prime*result)+((nonnullAnnotationType == null)? 0 :nonnullAnnotationType.hashCode()));
result = ((prime*result)+((nullableAnnotation == null)? 0 :nullableAnnotation.hashCode()));
result = ((prime*result)+((nullableAnnotationType == null)? 0 :nullableAnnotationType.hashCode()));
result = ((prime*result)+((routines == null)? 0 :routines.hashCode()));
result = ((prime*result)+((sequences == null)? 0 :sequences.hashCode()));
result = ((prime*result)+((udts == null)? 0 :udts.hashCode()));

View File

@ -1140,11 +1140,19 @@ jOOQ version used for source code.]]></jxb:javadoc></jxb:property></appinfo></an
jOOQ version used for source code.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="generatedNonnullAnnotationType" type="string" default="javax.annotation.Nonnull" minOccurs="0" maxOccurs="1">
<element name="nonnullAnnotation" type="boolean" default="false" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether non-nullable items should be annotated with the annotation type specified in {@link #nonnullAnnotationType}. In SQL and by consequence in jOOQ, non-nullability cannot be guaranteed statically. There may still be some cases (e.g. after unions, outer joins, etc.) where a normally non-null value turns out to be null!]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="nonnullAnnotationType" type="string" default="javax.annotation.Nonnull" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Specify the qualified annotation name for all non-nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nonnull} type.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="generatedNullableAnnotationType" type="string" default="javax.annotation.Nullable" minOccurs="0" maxOccurs="1">
<element name="nullableAnnotation" type="boolean" default="false" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether nullable items should be annotated with the annotation type specified in {@link #nullableAnnotationType}. Unlike {@link #nonnullAnnotation}, nullability can be guaranteed as in SQL, and by consequence in jOOQ, every column expression can be made nullable using some SQL operation.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="nullableAnnotationType" type="string" default="javax.annotation.Nullable" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Specify the qualified annotation name for all nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nullable} type.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>

View File

@ -517,6 +517,8 @@
</modules>
</profile>