From 95478da8a75fdeac21bb0263880524f0efd1e8f2 Mon Sep 17 00:00:00 2001 From: Damien D'ARRAS Date: Mon, 9 Feb 2026 15:46:17 +0100 Subject: [PATCH] feat(core): crude implementation of presentrequired attribute constraint --- .../java/fr/ign/validator/data/Header.java | 8 ++--- .../ign/validator/error/CoreErrorCodes.java | 4 +-- .../validator/model/AttributeConstraints.java | 31 +++++++++++++++++++ .../fr/ign/validator/model/DocumentModel.java | 2 +- .../AttributeReferenceValidator.java | 2 +- .../src/main/resources/error-code.json | 8 ++--- .../validator/model/AttributeTypeTest.java | 2 +- .../AttributeReferenceValidatorTest.java | 1 + .../ign/validator/cnig/data/CnigHeader.java | 14 +++++---- .../validator/cnig/error/CnigErrorCodes.java | 4 +-- .../regress/CnigValidatorRegressTest.java | 15 ++++----- 11 files changed, 63 insertions(+), 28 deletions(-) rename validator-core/src/main/java/fr/ign/validator/validation/{database => attribute}/AttributeReferenceValidator.java (99%) diff --git a/validator-core/src/main/java/fr/ign/validator/data/Header.java b/validator-core/src/main/java/fr/ign/validator/data/Header.java index 31fd6069..22033c7d 100644 --- a/validator-core/src/main/java/fr/ign/validator/data/Header.java +++ b/validator-core/src/main/java/fr/ign/validator/data/Header.java @@ -73,8 +73,8 @@ public void validate(Context context) { context.createError(CoreErrorCodes.TABLE_MISSING_GEOMETRY) .setMessageParam("FILEPATH", relativePath) ); - } else if (!missingAttribute.getConstraints().isRequired()) { - this.reportTableMissingNullableAttribute(missingAttribute, context); + } else if (!missingAttribute.getConstraints().isPresenceRequired()) { + this.reportTableMissingPresenceOptionalAttribute(missingAttribute, context); } else { context.report( context.createError(CoreErrorCodes.TABLE_MISSING_ATTRIBUTE) @@ -94,9 +94,9 @@ public void validate(Context context) { * @param missingAttribute * @param context */ - public void reportTableMissingNullableAttribute(AttributeType missingAttribute, Context context) { + public void reportTableMissingPresenceOptionalAttribute(AttributeType missingAttribute, Context context) { context.report( - context.createError(CoreErrorCodes.TABLE_MISSING_NULLABLE_ATTRIBUTE) + context.createError(CoreErrorCodes.TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE) .setMessageParam("ATTRIBUTE_NAME", missingAttribute.getName()) .setMessageParam("FILEPATH", relativePath) ); diff --git a/validator-core/src/main/java/fr/ign/validator/error/CoreErrorCodes.java b/validator-core/src/main/java/fr/ign/validator/error/CoreErrorCodes.java index 1c2b7e5a..1ed8fee4 100644 --- a/validator-core/src/main/java/fr/ign/validator/error/CoreErrorCodes.java +++ b/validator-core/src/main/java/fr/ign/validator/error/CoreErrorCodes.java @@ -179,8 +179,8 @@ public class CoreErrorCodes { * ErrorCode for error in Table (FileModel) */ public static final ErrorCode TABLE_MISSING_ATTRIBUTE = ErrorCode.valueOf("TABLE_MISSING_ATTRIBUTE"); - public static final ErrorCode TABLE_MISSING_NULLABLE_ATTRIBUTE = ErrorCode.valueOf( - "TABLE_MISSING_NULLABLE_ATTRIBUTE" + public static final ErrorCode TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE = ErrorCode.valueOf( + "TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE" ); public static final ErrorCode TABLE_UNEXPECTED_ATTRIBUTE = ErrorCode.valueOf("TABLE_UNEXPECTED_ATTRIBUTE"); public static final ErrorCode TABLE_UNEXPECTED_ENCODING = ErrorCode.valueOf("TABLE_UNEXPECTED_ENCODING"); diff --git a/validator-core/src/main/java/fr/ign/validator/model/AttributeConstraints.java b/validator-core/src/main/java/fr/ign/validator/model/AttributeConstraints.java index 0f8bb37c..4a21e76f 100644 --- a/validator-core/src/main/java/fr/ign/validator/model/AttributeConstraints.java +++ b/validator-core/src/main/java/fr/ign/validator/model/AttributeConstraints.java @@ -24,6 +24,15 @@ public class AttributeConstraints { */ private boolean required; + /** + * Indicates if attribute has to be present + * + * + * @see fr.ign.validator.validation.data.Header + * @see fr.ign.validator.error.CoreErrorCodes#TABLE_MISSING_ATTRIBUTE + */ + private boolean presenceRequired; + /** * Indicates if the value is unique in the table * @@ -79,17 +88,35 @@ public class AttributeConstraints { */ private String reference; + // checks wheter presenceRequired has been modified + private boolean presenceRequiredModified; + public AttributeConstraints() { this.required = true; + this.presenceRequired = true; + this.presenceRequiredModified = false; this.unique = false; } + public boolean isPresenceRequired() { + return presenceRequired; + } + + // Must be called after setRequired + public void setPresenceRequired(boolean presenceRequired) { + this.presenceRequired = presenceRequired; + this.presenceRequiredModified = true; + } + public boolean isRequired() { return required; } public void setRequired(boolean required) { this.required = required; + if (!this.presenceRequiredModified) { + this.presenceRequired = required; + } } public boolean isUnique() { @@ -150,4 +177,8 @@ public void setReference(String reference) { this.reference = reference; } + public boolean isPresenceRequiredModified() { + return this.presenceRequiredModified; + } + } \ No newline at end of file diff --git a/validator-core/src/main/java/fr/ign/validator/model/DocumentModel.java b/validator-core/src/main/java/fr/ign/validator/model/DocumentModel.java index 773e1621..9d884c9c 100644 --- a/validator-core/src/main/java/fr/ign/validator/model/DocumentModel.java +++ b/validator-core/src/main/java/fr/ign/validator/model/DocumentModel.java @@ -15,7 +15,7 @@ import fr.ign.validator.data.Document; import fr.ign.validator.database.Database; import fr.ign.validator.validation.Validator; -import fr.ign.validator.validation.database.AttributeReferenceValidator; +import fr.ign.validator.validation.attribute.AttributeReferenceValidator; import fr.ign.validator.validation.database.AttributeUniqueValidator; import fr.ign.validator.validation.database.FeatureTypeConditionsValidator; import fr.ign.validator.validation.database.ForeignKeyValidator; diff --git a/validator-core/src/main/java/fr/ign/validator/validation/database/AttributeReferenceValidator.java b/validator-core/src/main/java/fr/ign/validator/validation/attribute/AttributeReferenceValidator.java similarity index 99% rename from validator-core/src/main/java/fr/ign/validator/validation/database/AttributeReferenceValidator.java rename to validator-core/src/main/java/fr/ign/validator/validation/attribute/AttributeReferenceValidator.java index 24000045..ed32d2d7 100644 --- a/validator-core/src/main/java/fr/ign/validator/validation/database/AttributeReferenceValidator.java +++ b/validator-core/src/main/java/fr/ign/validator/validation/attribute/AttributeReferenceValidator.java @@ -1,4 +1,4 @@ -package fr.ign.validator.validation.database; +package fr.ign.validator.validation.attribute; import java.io.IOException; import java.sql.SQLException; diff --git a/validator-core/src/main/resources/error-code.json b/validator-core/src/main/resources/error-code.json index 490ae22a..0556f41d 100644 --- a/validator-core/src/main/resources/error-code.json +++ b/validator-core/src/main/resources/error-code.json @@ -90,13 +90,13 @@ { "name": "TABLE_MISSING_ATTRIBUTE", "level": "ERROR", - "message": "L'attribut obligatoire '{ATTRIBUTE_NAME}' n'est pas présent ou toujours vide dans le fichier '{FILEPATH}'.", + "message": "L'attribut obligatoire '{ATTRIBUTE_NAME}' n'est pas présent dans le fichier '{FILEPATH}'.", "documentation": "Cette erreur se produit lorsqu'un champ spécifié dans le modèle n'est pas présent dans la table" }, { - "name": "TABLE_MISSING_NULLABLE_ATTRIBUTE", + "name": "TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE", "level": "INFO", - "message": "L'attribut optionnel '{ATTRIBUTE_NAME}' n'est pas présent ou toujours vide dans le fichier '{FILEPATH}'.", + "message": "L'attribut optionnel '{ATTRIBUTE_NAME}' n'est pas présent dans le fichier '{FILEPATH}'.", "documentation": "Cette erreur se produit lorsqu'un champ spécifié comme nullable dans le modèle n'est pas présent dans la table" }, { @@ -568,7 +568,7 @@ "documentation": "" }, { - "name": "CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE", + "name": "CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE", "level": "ERROR", "message": "L'attribut optionnel '{ATTRIBUTE_NAME}' est absent du fichier {FILEPATH}. L'ajouter, même si il est toujours vide.", "documentation": "Cette erreur se produit lorsqu'un attribut marqué comme mandatory=WARNING est absent dans le cadre d'une validation CNIG." diff --git a/validator-core/src/test/java/fr/ign/validator/model/AttributeTypeTest.java b/validator-core/src/test/java/fr/ign/validator/model/AttributeTypeTest.java index 0fe9d9ad..73007ebd 100644 --- a/validator-core/src/test/java/fr/ign/validator/model/AttributeTypeTest.java +++ b/validator-core/src/test/java/fr/ign/validator/model/AttributeTypeTest.java @@ -49,7 +49,7 @@ public void testJsonIO() throws IOException { ObjectMapper mapper = ObjectMapperFactory.createObjectMapper(); String result = mapper.writeValueAsString(attribute); assertEquals( - "{\"type\":\"String\",\"name\":\"TEST\",\"description\":\"Test description\",\"constraints\":{\"required\":true,\"unique\":false}}", + "{\"type\":\"String\",\"name\":\"TEST\",\"description\":\"Test description\",\"constraints\":{\"required\":true,\"presenceRequired\":true,\"unique\":false,\"presenceRequiredModified\":false}}", result ); diff --git a/validator-core/src/test/java/fr/ign/validator/validation/database/AttributeReferenceValidatorTest.java b/validator-core/src/test/java/fr/ign/validator/validation/database/AttributeReferenceValidatorTest.java index 2eb57b3c..2b57a4ec 100644 --- a/validator-core/src/test/java/fr/ign/validator/validation/database/AttributeReferenceValidatorTest.java +++ b/validator-core/src/test/java/fr/ign/validator/validation/database/AttributeReferenceValidatorTest.java @@ -23,6 +23,7 @@ import fr.ign.validator.model.file.SingleTableModel; import fr.ign.validator.model.type.StringType; import fr.ign.validator.report.InMemoryReportBuilder; +import fr.ign.validator.validation.attribute.AttributeReferenceValidator; public class AttributeReferenceValidatorTest { diff --git a/validator-plugin-cnig/src/main/java/fr/ign/validator/cnig/data/CnigHeader.java b/validator-plugin-cnig/src/main/java/fr/ign/validator/cnig/data/CnigHeader.java index fb02ea19..be78337b 100644 --- a/validator-plugin-cnig/src/main/java/fr/ign/validator/cnig/data/CnigHeader.java +++ b/validator-plugin-cnig/src/main/java/fr/ign/validator/cnig/data/CnigHeader.java @@ -17,11 +17,13 @@ public CnigHeader(String relativePath, FeatureTypeMapper mapping) { } @Override - public void reportTableMissingNullableAttribute(AttributeType missingAttribute, Context context) { - context.report( - context.createError(CnigErrorCodes.CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE) - .setMessageParam("ATTRIBUTE_NAME", missingAttribute.getName()) - .setMessageParam("FILEPATH", this.getRelativePath()) - ); + public void reportTableMissingPresenceOptionalAttribute(AttributeType missingAttribute, Context context) { + if (!missingAttribute.getConstraints().isPresenceRequiredModified()) { + context.report( + context.createError(CnigErrorCodes.CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE) + .setMessageParam("ATTRIBUTE_NAME", missingAttribute.getName()) + .setMessageParam("FILEPATH", this.getRelativePath()) + ); + } } } \ No newline at end of file diff --git a/validator-plugin-cnig/src/main/java/fr/ign/validator/cnig/error/CnigErrorCodes.java b/validator-plugin-cnig/src/main/java/fr/ign/validator/cnig/error/CnigErrorCodes.java index b64c6bd1..0a198d9e 100644 --- a/validator-plugin-cnig/src/main/java/fr/ign/validator/cnig/error/CnigErrorCodes.java +++ b/validator-plugin-cnig/src/main/java/fr/ign/validator/cnig/error/CnigErrorCodes.java @@ -20,8 +20,8 @@ public class CnigErrorCodes { /** * Overrides CORE_TABLE_MISSING_NULLABLE_ATTRIBUTE */ - public static final ErrorCode CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE = ErrorCode.valueOf( - "CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE" + public static final ErrorCode CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE = ErrorCode.valueOf( + "CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE" ); /** diff --git a/validator-plugin-cnig/src/test/java/fr/ign/validator/cnig/regress/CnigValidatorRegressTest.java b/validator-plugin-cnig/src/test/java/fr/ign/validator/cnig/regress/CnigValidatorRegressTest.java index ffea807a..9856e2ca 100644 --- a/validator-plugin-cnig/src/test/java/fr/ign/validator/cnig/regress/CnigValidatorRegressTest.java +++ b/validator-plugin-cnig/src/test/java/fr/ign/validator/cnig/regress/CnigValidatorRegressTest.java @@ -210,7 +210,7 @@ public void test50545_CC_20130902() throws Exception { */ ReportAssert.assertCount(1, CnigErrorCodes.CNIG_METADATA_SPECIFICATION_NOT_FOUND, report); ReportAssert.assertCount(1, CnigErrorCodes.CNIG_METADATA_REFERENCESYSTEMIDENTIFIER_URI_NOT_FOUND, report); - ReportAssert.assertCount(1, CnigErrorCodes.CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE, report); + ReportAssert.assertCount(1, CnigErrorCodes.CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE, report); ReportAssert.assertCount(1 + 1 + 1, ErrorLevel.ERROR, report); /* @@ -223,10 +223,11 @@ public void test50545_CC_20130902() throws Exception { /* * check some infos */ - ReportAssert.assertCount(0, CoreErrorCodes.TABLE_MISSING_NULLABLE_ATTRIBUTE, report); - ReportAssert.assertCount(1, CnigErrorCodes.CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE, report); + ReportAssert.assertCount(0, CoreErrorCodes.TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE, report); + ReportAssert.assertCount(1, CnigErrorCodes.CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE, report); { - ValidatorError error = report.getErrorsByCode(CnigErrorCodes.CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE).get(0); + ValidatorError error = report.getErrorsByCode(CnigErrorCodes.CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE) + .get(0); assertEquals("DATECOG", error.getAttribute()); } @@ -327,7 +328,7 @@ public void test19182_CC_20150517() throws Exception { ReportAssert.assertCount(2, CoreErrorCodes.ATTRIBUTE_GEOMETRY_INVALID, report); ReportAssert.assertCount(19, CoreErrorCodes.ATTRIBUTE_UNEXPECTED_VALUE, report); ReportAssert.assertCount(1, CnigErrorCodes.CNIG_GEOMETRY_COMPLEXITY_ERROR, report); - ReportAssert.assertCount(1, CnigErrorCodes.CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE, report); + ReportAssert.assertCount(1, CnigErrorCodes.CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE, report); ReportAssert.assertCount(1 + 2 + 2 + 19 + 1 + 1, ErrorLevel.ERROR, report); /* @@ -763,7 +764,7 @@ public void test30014_PLU_20171013() throws Exception { ReportAssert.assertCount(0, CoreErrorCodes.DATABASE_CONSTRAINT_MISMATCH, report); ReportAssert.assertCount(1, CoreErrorCodes.TABLE_FOREIGN_KEY_NOT_FOUND, report); ReportAssert.assertCount(2, CnigErrorCodes.CNIG_PIECE_ECRITE_ONLY_PDF, report); - ReportAssert.assertCount(6, CnigErrorCodes.CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE, report); + ReportAssert.assertCount(6, CnigErrorCodes.CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE, report); ReportAssert.assertCount(1, CoreErrorCodes.ATTRIBUTE_UNEXPECTED_VALUE, report); ReportAssert.assertCount(1, CoreErrorCodes.ATTRIBUTE_FILE_NOT_FOUND, report); ReportAssert.assertCount(18 + 0 + 1 + 2 + 6 + 1 + 1, ErrorLevel.ERROR, report); @@ -881,7 +882,7 @@ public void test200011781_PLUi_20180101() throws Exception { */ ReportAssert.assertCount(4, CoreErrorCodes.ATTRIBUTE_GEOMETRY_INVALID, report); ReportAssert.assertCount(1, CoreErrorCodes.ATTRIBUTE_INVALID_REGEXP, report); - ReportAssert.assertCount(1, CnigErrorCodes.CNIG_TABLE_MISSING_NULLABLE_ATTRIBUTE, report); + ReportAssert.assertCount(1, CnigErrorCodes.CNIG_TABLE_MISSING_PRESENCE_OPTIONAL_ATTRIBUTE, report); ReportAssert.assertCount(4 + 1 + 1, ErrorLevel.ERROR, report); /*