[jOOQ/jOOQ#16002] Add new code generation flag to omit @NotNull / @Nullable annotations on write-only nullable types

This commit is contained in:
Lukas Eder 2024-03-01 16:44:51 +01:00
parent a79ef9bca5
commit f7fe2b866a
6 changed files with 228 additions and 123 deletions

View File

@ -65,134 +65,135 @@ import org.jooq.tools.JooqLogger;
*/
abstract class AbstractGenerator implements Generator {
private static final JooqLogger log = JooqLogger.getLogger(AbstractGenerator.class);
private static final JooqLogger log = JooqLogger.getLogger(AbstractGenerator.class);
boolean generateDeprecated = true;
boolean generateDeprecationOnUnknownTypes = true;
boolean generateIndexes = true;
boolean generateRelations = true;
boolean generateUDTPaths = true;
boolean generateImplicitJoinPathsToOne = true;
boolean generateImplicitJoinPathsToMany = true;
boolean generateImplicitJoinPathTableSubtypes = true;
boolean generateImplicitJoinPathUnusedConstructors = true;
boolean generateImplicitJoinPathsAsKotlinProperties = true;
boolean generateInstanceFields = true;
VisibilityModifier generateVisibilityModifier = VisibilityModifier.DEFAULT;
boolean generateGeneratedAnnotation = false;
GeneratedAnnotationType generatedGeneratedAnnotationType = GeneratedAnnotationType.DETECT_FROM_JDK;
boolean generateGeneratedAnnotationDate = false;
boolean generateGeneratedAnnotationJooqVersion = true;
boolean generateNonnullAnnotation = false;
String generatedNonnullAnnotationType = "javax.annotation.Nonnull";
boolean generateNullableAnnotation = false;
String generatedNullableAnnotationType = "javax.annotation.Nullable";
boolean generateConstructorPropertiesAnnotation = false;
boolean generateDeprecated = true;
boolean generateDeprecationOnUnknownTypes = true;
boolean generateIndexes = true;
boolean generateRelations = true;
boolean generateUDTPaths = true;
boolean generateImplicitJoinPathsToOne = true;
boolean generateImplicitJoinPathsToMany = true;
boolean generateImplicitJoinPathTableSubtypes = true;
boolean generateImplicitJoinPathUnusedConstructors = true;
boolean generateImplicitJoinPathsAsKotlinProperties = true;
boolean generateInstanceFields = true;
VisibilityModifier generateVisibilityModifier = VisibilityModifier.DEFAULT;
boolean generateGeneratedAnnotation = false;
GeneratedAnnotationType generatedGeneratedAnnotationType = GeneratedAnnotationType.DETECT_FROM_JDK;
boolean generateGeneratedAnnotationDate = false;
boolean generateGeneratedAnnotationJooqVersion = true;
boolean generateNonnullAnnotation = false;
String generatedNonnullAnnotationType = "javax.annotation.Nonnull";
boolean generateNullableAnnotation = false;
boolean generateNullableAnnotationOnWriteOnlyNullableTypes = false;
String generatedNullableAnnotationType = "javax.annotation.Nullable";
boolean generateConstructorPropertiesAnnotation = false;
Boolean generateConstructorPropertiesAnnotationOnPojos;
Boolean generateConstructorPropertiesAnnotationOnRecords;
boolean useSchemaVersionProvider = false;
boolean useCatalogVersionProvider = false;
boolean generateRoutines = true;
boolean useSchemaVersionProvider = false;
boolean useCatalogVersionProvider = false;
boolean generateRoutines = true;
boolean generateSequences = true;
boolean generateSequenceFlags = true;
boolean generateUDTs = true;
boolean generateTables = true;
boolean generateEmbeddables = true;
boolean generateRecords = true;
boolean generateRecordsImplementingRecordN = false;
boolean generateEnumsAsScalaSealedTraits = false;
boolean generatePojos = false;
boolean generatePojosAsJavaRecordClasses = false;
boolean generatePojosAsScalaCaseClasses = true;
boolean generatePojosAsKotlinDataClasses = true;
boolean generatePojosEqualsAndHashCode = true;
boolean generatePojosToString = true;
boolean generateImmutablePojos = false;
boolean generateSerializablePojos = true;
boolean generateInterfaces = false;
boolean generateImmutableInterfaces = false;
boolean generateSerializableInterfaces = true;
boolean generateDaos = false;
boolean generateJooqVersionReference = true;
boolean generateJPAAnnotations = false;
String generateJPAVersion = "";
boolean generateValidationAnnotations = false;
boolean generateSpringAnnotations = false;
boolean generateSpringDao = false;
boolean generateKotlinSetterJvmNameAnnotationsOnIsPrefix = true;
boolean generateKotlinNotNullPojoAttributes = false;
boolean generateKotlinNotNullRecordAttributes = false;
boolean generateKotlinNotNullInterfaceAttributes = false;
boolean generateKotlinDefaultedNullablePojoAttributes = true;
boolean generateKotlinDefaultedNullableRecordAttributes = true;
GeneratedSerialVersionUID generatedSerialVersionUID = GeneratedSerialVersionUID.CONSTANT;
int maxMembersPerInitialiser = 500;
boolean generateQueues = true;
boolean generateLinks = true;
boolean generateKeys = true;
boolean generateGlobalObjectNames = true;
boolean generateGlobalObjectReferences = true;
boolean generateGlobalCatalogReferences = true;
boolean generateGlobalSchemaReferences = true;
boolean generateGlobalRoutineReferences = true;
boolean generateGlobalSequenceReferences = true;
boolean generateGlobalTableReferences = true;
boolean generateGlobalDomainReferences = true;
boolean generateSequences = true;
boolean generateSequenceFlags = true;
boolean generateUDTs = true;
boolean generateTables = true;
boolean generateEmbeddables = true;
boolean generateRecords = true;
boolean generateRecordsImplementingRecordN = false;
boolean generateEnumsAsScalaSealedTraits = false;
boolean generatePojos = false;
boolean generatePojosAsJavaRecordClasses = false;
boolean generatePojosAsScalaCaseClasses = true;
boolean generatePojosAsKotlinDataClasses = true;
boolean generatePojosEqualsAndHashCode = true;
boolean generatePojosToString = true;
boolean generateImmutablePojos = false;
boolean generateSerializablePojos = true;
boolean generateInterfaces = false;
boolean generateImmutableInterfaces = false;
boolean generateSerializableInterfaces = true;
boolean generateDaos = false;
boolean generateJooqVersionReference = true;
boolean generateJPAAnnotations = false;
String generateJPAVersion = "";
boolean generateValidationAnnotations = false;
boolean generateSpringAnnotations = false;
boolean generateSpringDao = false;
boolean generateKotlinSetterJvmNameAnnotationsOnIsPrefix = true;
boolean generateKotlinNotNullPojoAttributes = false;
boolean generateKotlinNotNullRecordAttributes = false;
boolean generateKotlinNotNullInterfaceAttributes = false;
boolean generateKotlinDefaultedNullablePojoAttributes = true;
boolean generateKotlinDefaultedNullableRecordAttributes = true;
GeneratedSerialVersionUID generatedSerialVersionUID = GeneratedSerialVersionUID.CONSTANT;
int maxMembersPerInitialiser = 500;
boolean generateQueues = true;
boolean generateLinks = true;
boolean generateKeys = true;
boolean generateGlobalObjectNames = true;
boolean generateGlobalObjectReferences = true;
boolean generateGlobalCatalogReferences = true;
boolean generateGlobalSchemaReferences = true;
boolean generateGlobalRoutineReferences = true;
boolean generateGlobalSequenceReferences = true;
boolean generateGlobalTableReferences = true;
boolean generateGlobalDomainReferences = true;
boolean generateGlobalUDTReferences = true;
boolean generateGlobalQueueReferences = true;
boolean generateGlobalLinkReferences = true;
boolean generateGlobalKeyReferences = true;
boolean generateGlobalIndexReferences = true;
boolean generateDefaultCatalog = true;
boolean generateDefaultSchema = true;
boolean generateJavadoc = true;
boolean generateComments = true;
boolean generateCommentsOnAttributes = true;
boolean generateCommentsOnCatalogs = true;
boolean generateCommentsOnColumns = true;
boolean generateCommentsOnKeys = true;
boolean generateCommentsOnLinks = true;
boolean generateCommentsOnPackages = true;
boolean generateCommentsOnParameters = true;
boolean generateCommentsOnQueues = true;
boolean generateCommentsOnRoutines = true;
boolean generateCommentsOnSchemas = true;
boolean generateCommentsOnSequences = true;
boolean generateCommentsOnTables = true;
boolean generateCommentsOnUDTs = true;
boolean generateCommentsOnEmbeddables = true;
boolean generateSources = true;
boolean generateSourcesOnViews = true;
boolean generateFluentSetters = false;
boolean generateJavaBeansGettersAndSetters = false;
boolean generateUseTableNameForUnambiguousFKs = true;
boolean generateVarargsSetters = true;
String generateFullyQualifiedTypes = "";
boolean generateJavaTimeTypes = true;
boolean generateSpatialTypes = true;
boolean generateXmlTypes = true;
boolean generateJsonTypes = true;
boolean generateIntervalTypes = true;
boolean generateTableValuedFunctions = false;
boolean generateEmptyCatalogs = false;
boolean generateEmptySchemas = false;
String generateNewline = "\n";
boolean generateGlobalUDTReferences = true;
boolean generateGlobalQueueReferences = true;
boolean generateGlobalLinkReferences = true;
boolean generateGlobalKeyReferences = true;
boolean generateGlobalIndexReferences = true;
boolean generateDefaultCatalog = true;
boolean generateDefaultSchema = true;
boolean generateJavadoc = true;
boolean generateComments = true;
boolean generateCommentsOnAttributes = true;
boolean generateCommentsOnCatalogs = true;
boolean generateCommentsOnColumns = true;
boolean generateCommentsOnKeys = true;
boolean generateCommentsOnLinks = true;
boolean generateCommentsOnPackages = true;
boolean generateCommentsOnParameters = true;
boolean generateCommentsOnQueues = true;
boolean generateCommentsOnRoutines = true;
boolean generateCommentsOnSchemas = true;
boolean generateCommentsOnSequences = true;
boolean generateCommentsOnTables = true;
boolean generateCommentsOnUDTs = true;
boolean generateCommentsOnEmbeddables = true;
boolean generateSources = true;
boolean generateSourcesOnViews = true;
boolean generateFluentSetters = false;
boolean generateJavaBeansGettersAndSetters = false;
boolean generateUseTableNameForUnambiguousFKs = true;
boolean generateVarargsSetters = true;
String generateFullyQualifiedTypes = "";
boolean generateJavaTimeTypes = true;
boolean generateSpatialTypes = true;
boolean generateXmlTypes = true;
boolean generateJsonTypes = true;
boolean generateIntervalTypes = true;
boolean generateTableValuedFunctions = false;
boolean generateEmptyCatalogs = false;
boolean generateEmptySchemas = false;
String generateNewline = "\n";
String generateIndentation;
int generatePrintMarginForBlockComment = 80;
GeneratedTextBlocks generateTextBlocks = GeneratedTextBlocks.DETECT_FROM_JDK;
boolean generateWhereMethodOverrides = true;
boolean generateRenameMethodOverrides = true;
boolean generateAsMethodOverrides = true;
int generatePrintMarginForBlockComment = 80;
GeneratedTextBlocks generateTextBlocks = GeneratedTextBlocks.DETECT_FROM_JDK;
boolean generateWhereMethodOverrides = true;
boolean generateRenameMethodOverrides = true;
boolean generateAsMethodOverrides = true;
protected GeneratorStrategyWrapper strategy;
protected String targetEncoding = "UTF-8";
protected boolean targetClean = true;
protected String targetEncoding = "UTF-8";
protected boolean targetClean = true;
final Language languageConfigured;
Language language;
Database database;
@ -476,6 +477,16 @@ abstract class AbstractGenerator implements Generator {
this.generateNullableAnnotation = generateNullableAnnotation;
}
@Override
public boolean generateNullableAnnotationOnWriteOnlyNullableTypes() {
return generateNullableAnnotationOnWriteOnlyNullableTypes;
}
@Override
public void setGenerateNullableAnnotationOnWriteOnlyNullableTypes(boolean generateNullableAnnotationOnWriteOnlyNullableTypes) {
this.generateNullableAnnotationOnWriteOnlyNullableTypes = generateNullableAnnotationOnWriteOnlyNullableTypes;
}
@Override
public String generatedNullableAnnotationType() {
return generatedNullableAnnotationType;

View File

@ -771,6 +771,8 @@ public class GenerationTool {
generator.setGeneratedNonnullAnnotationType(g.getGenerate().getNonnullAnnotationType());
if (g.getGenerate().isNullableAnnotation() != null)
generator.setGenerateNullableAnnotation(g.getGenerate().isNullableAnnotation());
if (g.getGenerate().isNullableAnnotationOnWriteOnlyNullableTypes() != null)
generator.setGenerateNullableAnnotationOnWriteOnlyNullableTypes(g.getGenerate().isNullableAnnotationOnWriteOnlyNullableTypes());
if (g.getGenerate().getNullableAnnotationType() != null)
generator.setGeneratedNullableAnnotationType(g.getGenerate().getNullableAnnotationType());
if (g.getGenerate().isConstructorPropertiesAnnotation() != null)

View File

@ -319,6 +319,26 @@ public interface Generator {
*/
void setGenerateNullableAnnotation(boolean generateNullableAnnotation);
/**
* Whether Nullable annotations should be generated on write-only nullable
* types (e.g. defaulted, non-null).
* <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 generateNullableAnnotationOnWriteOnlyNullableTypes();
/**
* Whether Nullable annotations should be generated on write-only nullable
* types (e.g. defaulted, non-null).
* <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 setGenerateNullableAnnotationOnWriteOnlyNullableTypes(boolean generateNullableAnnotationOnWriteOnlyNullableTypes);
/**
* Which type of Nullable annotation should be generated.
*/

View File

@ -9276,6 +9276,15 @@ public class JavaGenerator extends AbstractGenerator {
&& !type.isIdentity();
}
private boolean writeOnlyNullable(JavaWriter out, TypedElementDefinition<?> column) {
return writeOnlyNullable(column.getType(resolver(out)));
}
private boolean writeOnlyNullable(DataTypeDefinition type) {
return !type.isNullable()
&& (type.isDefaulted() || type.isIdentity());
}
private static final Pattern P_IS = Pattern.compile("^is[A-Z].*$");
protected void printKotlinSetterAnnotation(JavaWriter out, TypedElementDefinition<?> column, Mode mode) {
@ -9303,16 +9312,29 @@ public class JavaGenerator extends AbstractGenerator {
}
private String nullableOrNonnullAnnotation(JavaWriter out, Definition column) {
return (column instanceof TypedElementDefinition && !effectivelyNotNull(out, (TypedElementDefinition<?>) column))
? nullableAnnotation(out)
: nonnullAnnotation(out);
if (column instanceof TypedElementDefinition<?> t) {
if (!effectivelyNotNull(out, t)) {
if (writeOnlyNullable(out, t) && !generateNullableAnnotationOnWriteOnlyNullableTypes())
return null;
else
return nullableAnnotation(out);
}
}
return nonnullAnnotation(out);
}
private void printNullableOrNonnullAnnotation(JavaWriter out, Definition column) {
if (column instanceof TypedElementDefinition && !effectivelyNotNull(out, (TypedElementDefinition<?>) column))
printNullableAnnotation(out);
else
printNonnullAnnotation(out);
if (column instanceof TypedElementDefinition<?> t) {
if (!effectivelyNotNull(out, t)) {
if (!writeOnlyNullable(out, t) || generateNullableAnnotationOnWriteOnlyNullableTypes())
printNullableAnnotation(out);
return;
}
}
printNonnullAnnotation(out);
}
protected void printNullableAnnotation(JavaWriter out) {

View File

@ -75,6 +75,8 @@ public class Generate implements Serializable, XMLAppendable
protected String nonnullAnnotationType = "javax.annotation.Nonnull";
@XmlElement(defaultValue = "false")
protected Boolean nullableAnnotation = false;
@XmlElement(defaultValue = "false")
protected Boolean nullableAnnotationOnWriteOnlyNullableTypes = false;
@XmlElement(defaultValue = "javax.annotation.Nullable")
@XmlJavaTypeAdapter(StringAdapter.class)
protected String nullableAnnotationType = "javax.annotation.Nullable";
@ -785,6 +787,30 @@ public class Generate implements Serializable, XMLAppendable
this.nullableAnnotation = value;
}
/**
* Whether write-only (e.g. defaulted, non-null) 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 isNullableAnnotationOnWriteOnlyNullableTypes() {
return nullableAnnotationOnWriteOnlyNullableTypes;
}
/**
* Whether write-only (e.g. defaulted, non-null) 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.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setNullableAnnotationOnWriteOnlyNullableTypes(Boolean value) {
this.nullableAnnotationOnWriteOnlyNullableTypes = value;
}
/**
* Specify the qualified annotation name for all nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nullable} type.
*
@ -3311,6 +3337,15 @@ public class Generate implements Serializable, XMLAppendable
return this;
}
/**
* Whether write-only (e.g. defaulted, non-null) 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.
*
*/
public Generate withNullableAnnotationOnWriteOnlyNullableTypes(Boolean value) {
setNullableAnnotationOnWriteOnlyNullableTypes(value);
return this;
}
/**
* Specify the qualified annotation name for all nullable items in generated code, defaulting to the JSR-305 {@link javax.annotation.Nullable} type.
*
@ -4239,6 +4274,7 @@ public class Generate implements Serializable, XMLAppendable
builder.append("nonnullAnnotation", nonnullAnnotation);
builder.append("nonnullAnnotationType", nonnullAnnotationType);
builder.append("nullableAnnotation", nullableAnnotation);
builder.append("nullableAnnotationOnWriteOnlyNullableTypes", nullableAnnotationOnWriteOnlyNullableTypes);
builder.append("nullableAnnotationType", nullableAnnotationType);
builder.append("constructorPropertiesAnnotation", constructorPropertiesAnnotation);
builder.append("constructorPropertiesAnnotationOnPojos", constructorPropertiesAnnotationOnPojos);
@ -4546,6 +4582,15 @@ public class Generate implements Serializable, XMLAppendable
return false;
}
}
if (nullableAnnotationOnWriteOnlyNullableTypes == null) {
if (other.nullableAnnotationOnWriteOnlyNullableTypes!= null) {
return false;
}
} else {
if (!nullableAnnotationOnWriteOnlyNullableTypes.equals(other.nullableAnnotationOnWriteOnlyNullableTypes)) {
return false;
}
}
if (nullableAnnotationType == null) {
if (other.nullableAnnotationType!= null) {
return false;
@ -5447,6 +5492,7 @@ public class Generate implements Serializable, XMLAppendable
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)+((nullableAnnotationOnWriteOnlyNullableTypes == null)? 0 :nullableAnnotationOnWriteOnlyNullableTypes.hashCode()));
result = ((prime*result)+((nullableAnnotationType == null)? 0 :nullableAnnotationType.hashCode()));
result = ((prime*result)+((constructorPropertiesAnnotation == null)? 0 :constructorPropertiesAnnotation.hashCode()));
result = ((prime*result)+((constructorPropertiesAnnotationOnPojos == null)? 0 :constructorPropertiesAnnotationOnPojos.hashCode()));

View File

@ -2489,6 +2489,10 @@ jOOQ version used for source code.]]></jxb:javadoc></jxb:property></appinfo></an
<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="nullableAnnotationOnWriteOnlyNullableTypes" type="boolean" default="false" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether write-only (e.g. defaulted, non-null) 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>