From 7f40af9f6b3a7e0d8da64a152d737204793b4ccc Mon Sep 17 00:00:00 2001
From: vkovtun <viktor.kovtun@id.ethz.ch>
Date: Mon, 3 Apr 2023 19:33:47 +0200
Subject: [PATCH] SSDM-13256: Fixing a corner case when exporting a property
 type which is absent in the type of the exported sample.

---
 .../helper/AbstractXLSEntityExportHelper.java | 22 +++++++-------
 .../export/helper/XLSDataSetExportHelper.java | 14 ++++++---
 .../helper/XLSExperimentExportHelper.java     | 18 +++++++----
 .../export/helper/XLSProjectExportHelper.java | 18 +++++++----
 .../export/helper/XLSSampleExportHelper.java  | 14 ++++++---
 .../server/xls/export/XLSExportData.java      | 30 +++++++++++++++++++
 6 files changed, 88 insertions(+), 28 deletions(-)

diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/AbstractXLSEntityExportHelper.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/AbstractXLSEntityExportHelper.java
index 5a7d6c5d6ab..a8d11335f75 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/AbstractXLSEntityExportHelper.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/AbstractXLSEntityExportHelper.java
@@ -123,22 +123,22 @@ public abstract class AbstractXLSEntityExportHelper<ENTITY extends IPermIdHolder
 
                 final String[] selectedFieldHeaders = selectedExportFields.stream()
                         .filter(field -> isFieldAcceptable(possibleAttributeNameSet, field))
-                        .map(field ->
+                        .flatMap(field ->
                         {
                             final String fieldId = field.get(FIELD_ID_KEY);
                             switch (FieldType.valueOf(field.get(FIELD_TYPE_KEY)))
                             {
                                 case ATTRIBUTE:
                                 {
-                                    return Attribute.valueOf(fieldId).getName();
+                                    return Stream.of(Attribute.valueOf(fieldId).getName());
                                 }
                                 case PROPERTY:
                                 {
                                     return propertyTypes.stream()
                                             .filter(propertyType -> Objects.equals(propertyType.getCode(), fieldId))
                                             .findFirst()
-                                            .orElseThrow(() -> new IllegalArgumentException("Property type not found for id: " + fieldId))
-                                            .getLabel();
+                                            .stream()
+                                            .map(PropertyType::getLabel);
                                 }
                                 default:
                                 {
@@ -157,10 +157,10 @@ public abstract class AbstractXLSEntityExportHelper<ENTITY extends IPermIdHolder
                         ? Arrays.stream(requiredForImportAttributes).filter(attribute -> !selectedAttributes.contains(attribute))
                         .map(Attribute::getName)
                         : Stream.empty();
-                final String[] allFieldNames = Stream.concat(Arrays.stream(selectedFieldHeaders), requiredForImportAttributeNameStream)
+                final String[] allFieldHeaders = Stream.concat(Arrays.stream(selectedFieldHeaders), requiredForImportAttributeNameStream)
                         .toArray(String[]::new);
 
-                warnings.addAll(addRow(rowNumber++, true, typeExportableKind, typePermId, allFieldNames));
+                warnings.addAll(addRow(rowNumber++, true, typeExportableKind, typePermId, allFieldHeaders));
 
                 // Values
                 final Set<Map<String, String>> selectedExportFieldSet = new HashSet<>(selectedExportFields);
@@ -178,19 +178,21 @@ public abstract class AbstractXLSEntityExportHelper<ENTITY extends IPermIdHolder
                     final String[] entityValues = Stream.concat(selectedExportFields.stream(),
                                     extraExportFields.stream())
                             .filter(field -> isFieldAcceptable(possibleAttributeNameSet, field))
-                            .map(field ->
+                            .flatMap(field ->
                             {
                                 final String fieldId = field.get(FIELD_ID_KEY);
                                 switch (FieldType.valueOf(field.get(FIELD_TYPE_KEY)))
                                 {
                                     case ATTRIBUTE:
                                     {
-                                        return getAttributeValue(entity, Attribute.valueOf(fieldId));
+                                        return Stream.of(getAttributeValue(entity, Attribute.valueOf(fieldId)));
                                     }
                                     case PROPERTY:
                                     {
-                                        return getPropertiesMappingFunction(textFormatting, entity.getProperties())
-                                                .apply(codeToPropertyTypeMap.get(fieldId));
+                                        final PropertyType propertyType = codeToPropertyTypeMap.get(fieldId);
+                                        return propertyType != null
+                                                ? Stream.of(getPropertiesMappingFunction(textFormatting, entity.getProperties()).apply(propertyType))
+                                                : Stream.of();
                                     }
                                     default:
                                     {
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSDataSetExportHelper.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSDataSetExportHelper.java
index 4f543acea01..061d0428aa1 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSDataSetExportHelper.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSDataSetExportHelper.java
@@ -30,6 +30,7 @@ import static ch.ethz.sis.openbis.generic.server.xls.export.Attribute.SAMPLE;
 import static ch.ethz.sis.openbis.generic.server.xls.export.Attribute.STORAGE_CONFIRMATION;
 
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Function;
@@ -43,6 +44,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetType;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person;
 import ch.ethz.sis.openbis.generic.server.xls.export.Attribute;
 import ch.ethz.sis.openbis.generic.server.xls.export.ExportableKind;
 import ch.ethz.sis.openbis.generic.server.xls.export.XLSExport;
@@ -153,19 +155,23 @@ public class XLSDataSetExportHelper extends AbstractXLSEntityExportHelper<DataSe
             }
             case REGISTRATOR:
             {
-                return dataSet.getRegistrator().getUserId();
+                final Person registrator = dataSet.getRegistrator();
+                return registrator != null ? registrator.getUserId() : null;
             }
             case REGISTRATION_DATE:
             {
-                return DATE_FORMAT.format(dataSet.getRegistrationDate());
+                final Date registrationDate = dataSet.getRegistrationDate();
+                return registrationDate != null ? DATE_FORMAT.format(registrationDate) : null;
             }
             case MODIFIER:
             {
-                return dataSet.getModifier().getUserId();
+                final Person modifier = dataSet.getModifier();
+                return modifier != null ? modifier.getUserId() : null;
             }
             case MODIFICATION_DATE:
             {
-                return DATE_FORMAT.format(dataSet.getModificationDate());
+                final Date modificationDate = dataSet.getModificationDate();
+                return modificationDate != null ? DATE_FORMAT.format(modificationDate) : null;
             }
             case PARENTS:
             {
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSExperimentExportHelper.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSExperimentExportHelper.java
index abeca82887b..bd81f079805 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSExperimentExportHelper.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSExperimentExportHelper.java
@@ -25,6 +25,7 @@ import static ch.ethz.sis.openbis.generic.server.xls.export.Attribute.REGISTRATI
 import static ch.ethz.sis.openbis.generic.server.xls.export.Attribute.REGISTRATOR;
 
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -36,6 +37,8 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.ExperimentType;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project;
 import ch.ethz.sis.openbis.generic.server.xls.export.Attribute;
 import ch.ethz.sis.openbis.generic.server.xls.export.ExportableKind;
 
@@ -102,23 +105,28 @@ public class XLSExperimentExportHelper extends AbstractXLSEntityExportHelper<Exp
             }
             case PROJECT:
             {
-                return experiment.getProject().getIdentifier().getIdentifier();
+                final Project project = experiment.getProject();
+                return project != null ? project.getIdentifier().getIdentifier() : null;
             }
             case REGISTRATOR:
             {
-                return experiment.getRegistrator().getUserId();
+                final Person registrator = experiment.getRegistrator();
+                return registrator != null ? registrator.getUserId() : null;
             }
             case REGISTRATION_DATE:
             {
-                return DATE_FORMAT.format(experiment.getRegistrationDate());
+                final Date registrationDate = experiment.getRegistrationDate();
+                return registrationDate != null ? DATE_FORMAT.format(registrationDate) : null;
             }
             case MODIFIER:
             {
-                return experiment.getModifier().getUserId();
+                final Person modifier = experiment.getModifier();
+                return modifier != null ? modifier.getUserId() : null;
             }
             case MODIFICATION_DATE:
             {
-                return DATE_FORMAT.format(experiment.getModificationDate());
+                final Date modificationDate = experiment.getModificationDate();
+                return modificationDate != null ? DATE_FORMAT.format(modificationDate) : null;
             }
             default:
             {
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSProjectExportHelper.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSProjectExportHelper.java
index adba2a7dcf9..fa57fbc0186 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSProjectExportHelper.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSProjectExportHelper.java
@@ -18,6 +18,7 @@ package ch.ethz.sis.openbis.generic.server.xls.export.helper;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Date;
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.List;
@@ -30,9 +31,11 @@ import org.apache.poi.ss.usermodel.Workbook;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IEntityType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.fetchoptions.ProjectFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.ProjectPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space;
 import ch.ethz.sis.openbis.generic.server.xls.export.Attribute;
 import ch.ethz.sis.openbis.generic.server.xls.export.ExportableKind;
 import ch.ethz.sis.openbis.generic.server.xls.export.FieldType;
@@ -171,23 +174,28 @@ public class XLSProjectExportHelper extends AbstractXLSExportHelper<IEntityType>
             }
             case SPACE:
             {
-                return project.getSpace().getCode();
+                final Space space = project.getSpace();
+                return space != null ? space.getCode() : null;
             }
             case REGISTRATOR:
             {
-                return project.getRegistrator().getUserId();
+                final Person registrator = project.getRegistrator();
+                return registrator != null ? registrator.getUserId() : null;
             }
             case REGISTRATION_DATE:
             {
-                return DATE_FORMAT.format(project.getRegistrationDate());
+                final Date registrationDate = project.getRegistrationDate();
+                return registrationDate != null ? DATE_FORMAT.format(registrationDate) : null;
             }
             case MODIFIER:
             {
-                return project.getModifier().getUserId();
+                final Person modifier = project.getModifier();
+                return modifier != null ? modifier.getUserId() : null;
             }
             case MODIFICATION_DATE:
             {
-                return DATE_FORMAT.format(project.getModificationDate());
+                final Date modificationDate = project.getModificationDate();
+                return modificationDate != null ? DATE_FORMAT.format(modificationDate) : null;
             }
             default:
             {
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSSampleExportHelper.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSSampleExportHelper.java
index 83cab69d25e..a8f5703af83 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSSampleExportHelper.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSSampleExportHelper.java
@@ -31,6 +31,7 @@ import static ch.ethz.sis.openbis.generic.server.xls.export.Attribute.REGISTRATO
 import static ch.ethz.sis.openbis.generic.server.xls.export.Attribute.SPACE;
 
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -38,6 +39,7 @@ import java.util.stream.Collectors;
 import org.apache.poi.ss.usermodel.Workbook;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.SampleType;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleFetchOptions;
@@ -151,19 +153,23 @@ public class XLSSampleExportHelper extends AbstractXLSEntityExportHelper<Sample,
             }
             case REGISTRATOR:
             {
-                return sample.getRegistrator().getUserId();
+                final Person registrator = sample.getRegistrator();
+                return registrator != null ? registrator.getUserId() : null;
             }
             case REGISTRATION_DATE:
             {
-                return DATE_FORMAT.format(sample.getRegistrationDate());
+                final Date registrationDate = sample.getRegistrationDate();
+                return registrationDate != null ?DATE_FORMAT.format(registrationDate) : null;
             }
             case MODIFIER:
             {
-                return sample.getModifier().getUserId();
+                final Person modifier = sample.getModifier();
+                return modifier != null ? modifier.getUserId() : null;
             }
             case MODIFICATION_DATE:
             {
-                return DATE_FORMAT.format(sample.getModificationDate());
+                final Date modificationDate = sample.getModificationDate();
+                return modificationDate != null ? DATE_FORMAT.format(modificationDate) : null;
             }
             case $:
             {
diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/XLSExportData.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/XLSExportData.java
index bb4c246f770..f346bc712f4 100644
--- a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/XLSExportData.java
+++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/XLSExportData.java
@@ -680,6 +680,36 @@ public class XLSExportData
                                     List.of(),
                                     false
                             },
+                            {
+                                    "export-experiment-filtered-fields.xlsx",
+                                    Map.of(),
+                                    ExperimentExpectations.class,
+                                    List.of(
+                                            new ExportablePermId(EXPERIMENT, new ExperimentPermId("200001010000000-0001")),
+                                            new ExportablePermId(EXPERIMENT, new ExperimentPermId("200001010000000-0002")),
+                                            new ExportablePermId(EXPERIMENT, new ExperimentPermId("200001010000000-0003"))
+                                    ),
+                                    true,
+                                    Map.of(
+                                            EXPERIMENT.toString(), Map.of(
+                                                    "COLLECTION", List.of(
+                                                            Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "IDENTIFIER"),
+                                                            Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "PROJECT"),
+                                                            Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), FIELD_ID_KEY,
+                                                                    "$DEFAULT_OBJECT_TYPE"),
+                                                            Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), FIELD_ID_KEY, "FINISHED_FLAG")),
+                                                    "DEFAULT_EXPERIMENT", List.of(
+                                                            Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), FIELD_ID_KEY, "FINISHED_FLAG"),
+                                                            Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "IDENTIFIER"),
+                                                            Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "CODE"),
+                                                            Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), FIELD_ID_KEY,
+                                                                    "$DEFAULT_OBJECT_TYPE"))
+                                            )
+                                    ),
+                                    XLSExport.TextFormatting.PLAIN,
+                                    List.of(),
+                                    false
+                            },
                             {
                                     "export-sample-compatible-with-import.xlsx",
                                     Map.of(),
-- 
GitLab