Skip to content

Commit 0d3fd19

Browse files
committed
Required controlledVocabulary metadata marked as valid while empty
1 parent 6b188a4 commit 0d3fd19

4 files changed

Lines changed: 35 additions & 23 deletions

File tree

src/main/java/edu/harvard/iq/dataverse/DatasetFieldValidator.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,26 @@ public boolean isValid(DatasetField value, ConstraintValidatorContext context) {
5959
}
6060

6161
// if value is not primitive or not empty
62-
if (!dsfType.isPrimitive() || !StringUtils.isBlank(value.getValue())) {
62+
// For controlled vocabulary fields, check that actual CV values are selected,
63+
// not just that datasetFieldValues contains something (which might be an invalid N/A placeholder)
64+
// See https://github.com/IQSS/dataverse/issues/11900
65+
if (!dsfType.isPrimitive()) {
6366
return true;
6467
}
65-
68+
69+
if (dsfType.isControlledVocabulary()) {
70+
// For CV fields, check if there are actual controlled vocabulary values selected
71+
if (value.getControlledVocabularyValues() != null && !value.getControlledVocabularyValues().isEmpty()) {
72+
return true;
73+
}
74+
// If no CV values, fall through to required field check below
75+
} else {
76+
// For non-CV primitive fields, check if value is not blank
77+
if (!StringUtils.isBlank(value.getValue())) {
78+
return true;
79+
}
80+
}
81+
6682
if (value.isRequired()) {
6783
String errorMessage = null;
6884
DatasetFieldCompoundValue parent = value.getParentDatasetFieldCompoundValue();

src/main/java/edu/harvard/iq/dataverse/DatasetPage.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4039,8 +4039,8 @@ public String save() {
40394039
dataset.setOwner(ownerId != null ? dataverseService.find(ownerId) : null);
40404040
}
40414041
// Validate
4042-
Set<ConstraintViolation> constraintViolations = workingVersion.validate();
4043-
if (!constraintViolations.isEmpty()) {
4042+
workingVersion.validate(); // add validation messages to dataset fields
4043+
if (!workingVersion.isValid()) {
40444044
FacesContext.getCurrentInstance().validationFailed();
40454045
return "";
40464046
}
@@ -7005,4 +7005,4 @@ public void setRequestedCSL(String requestedCSL) {
70057005
public void validateEmbargoReason(FacesContext context, UIComponent component, Object value) {
70067006
FileUtil.validateEmbargoReason(context, component, value, removeEmbargo);
70077007
}
7008-
}
7008+
}

src/main/java/edu/harvard/iq/dataverse/api/imports/ImportServiceBean.java

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,7 @@
77

88
import com.google.gson.Gson;
99
import com.google.gson.GsonBuilder;
10-
import edu.harvard.iq.dataverse.Dataset;
11-
import edu.harvard.iq.dataverse.DatasetField;
12-
import edu.harvard.iq.dataverse.DatasetFieldConstant;
13-
import edu.harvard.iq.dataverse.DatasetFieldServiceBean;
14-
import edu.harvard.iq.dataverse.DatasetFieldType;
15-
import edu.harvard.iq.dataverse.DatasetFieldValue;
16-
import edu.harvard.iq.dataverse.DatasetServiceBean;
17-
import edu.harvard.iq.dataverse.DatasetVersion;
18-
import edu.harvard.iq.dataverse.Dataverse;
19-
import edu.harvard.iq.dataverse.DataverseContact;
20-
import edu.harvard.iq.dataverse.DataverseServiceBean;
21-
import edu.harvard.iq.dataverse.EjbDataverseEngine;
22-
import edu.harvard.iq.dataverse.GlobalId;
23-
import edu.harvard.iq.dataverse.MetadataBlockServiceBean;
10+
import edu.harvard.iq.dataverse.*;
2411
import edu.harvard.iq.dataverse.api.dto.DatasetDTO;
2512
import edu.harvard.iq.dataverse.api.imports.ImportUtil.ImportType;
2613
import edu.harvard.iq.dataverse.dataset.DatasetTypeServiceBean;
@@ -762,16 +749,21 @@ private void validateVersionMetadata(DatasetVersion version, PrintWriter log) th
762749
*/
763750
private boolean validateVersionMetadata(DatasetVersion version, boolean sanitize, PrintWriter cleanupLog) throws ImportException {
764751
boolean fixed = false;
752+
boolean allowHarvestingMissingCVV = version.getDataset().getHarvestedFrom() != null ? version.getDataset().getHarvestedFrom().getAllowHarvestingMissingCVV() : false;
765753
Set<ConstraintViolation> invalidViolations = version.validate();
766754
if (!invalidViolations.isEmpty()) {
767755
for (ConstraintViolation v : invalidViolations) {
768756
Object invalid = v.getRootBean();
769757
String msg = "";
770758
if (invalid instanceof DatasetField) {
771-
DatasetField f = (DatasetField) invalid;
772-
773-
msg += "Missing required field: " + f.getDatasetFieldType().getDisplayName() + ";";
759+
DatasetField f = (DatasetField) invalid;
760+
761+
msg += "Missing required field: " + f.getDatasetFieldType().getDisplayName() + ";";
774762
if (sanitize) {
763+
if (allowHarvestingMissingCVV && f.getDatasetFieldType().isControlledVocabulary()) {
764+
ControlledVocabularyValue ccv = new ControlledVocabularyValue(null, DatasetField.NA_VALUE, f.getDatasetFieldType());
765+
f.setControlledVocabularyValues(List.of(ccv));
766+
}
775767
msg += " populated with '" + DatasetField.NA_VALUE + "'";
776768
f.setSingleValue(DatasetField.NA_VALUE);
777769
fixed = true;

src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractDatasetCommand.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,14 @@ protected void validateOrDie(DatasetVersion dsv, Boolean lenient) throws Command
110110
Set<ConstraintViolation> constraintViolations = dsv.validate();
111111
if (!constraintViolations.isEmpty()) {
112112
if (lenient) {
113-
// populate invalid fields with N/A
113+
// populate invalid primitive fields with N/A
114+
// Note: controlled vocabulary fields should NOT get N/A values in datasetfieldvalue,
115+
// as this creates an inconsistent state where the CV field appears valid but is empty.
116+
// See https://github.com/IQSS/dataverse/issues/11900
114117
constraintViolations.stream()
115118
.filter(cv -> cv.getRootBean() instanceof DatasetField)
116119
.map(cv -> ((DatasetField) cv.getRootBean()))
120+
.filter(f -> !f.getDatasetFieldType().isControlledVocabulary())
117121
.forEach(f -> f.setSingleValue(DatasetField.NA_VALUE));
118122

119123
} else {

0 commit comments

Comments
 (0)