joniles / mpxj

Primary repository for MPXJ library
http://www.mpxj.org/
GNU Lesser General Public License v2.1
250 stars 104 forks source link

NPE when exporting Project with created UDF to XER #731

Closed smacharacek closed 3 months ago

smacharacek commented 3 months ago

We get NPE when exporting project to P6 XER format. Stacktrace:

Can't write exported solution [projectId=80744159-282d-4021-a977-538ba3ad5ee0]/[solutionId=08e712b9-76ce-45be-9bea-1fe678a24caf] to external project file: Cannot invoke "java.lang.Integer.compareTo(java.lang.Integer)" because "id1" is null java.lang.NullPointerException: Cannot invoke "java.lang.Integer.compareTo(java.lang.Integer)" because "id1" is null
    at net.sf.mpxj.primavera.PrimaveraXERFileWriter.lambda$writeUdfValues$31(PrimaveraXERFileWriter.java:493) ~[mpxj-12.10.2.jar!/:?]
    at java.base/java.util.TimSort.binarySort(Unknown Source) ~[?:?]
    at java.base/java.util.TimSort.sort(Unknown Source) ~[?:?]
    at java.base/java.util.Arrays.sort(Unknown Source) ~[?:?]
    at java.base/java.util.ArrayList.sort(Unknown Source) ~[?:?]
    at net.sf.mpxj.primavera.PrimaveraXERFileWriter.writeUdfValues(PrimaveraXERFileWriter.java:485) ~[mpxj-12.10.2.jar!/:?]
    at net.sf.mpxj.primavera.PrimaveraXERFileWriter.write(PrimaveraXERFileWriter.java:179) ~[mpxj-12.10.2.jar!/:?]
    at net.sf.mpxj.writer.UniversalProjectWriter.write(UniversalProjectWriter.java:71) ~[mpxj-12.10.2.jar!/:?]

(stacktrace is from v 12.10.2. but I run into the issue for fk_id being null also in 13.1.0)

The UDF value for project does not have "fk_id" since this method

   private List<Map<String, Object>> writeUdfAssignments(Set<FieldType> fields, FieldType uniqueID, FieldContainer container)
   {
      Integer projectID = container instanceof Resource ? null : getProjectID(m_file.getProjectProperties().getUniqueID());
      Integer entityId = (Integer) container.get(uniqueID);
      return fields.stream().map(f -> writeUdfAssignment(f, projectID, entityId, container.get(f))).collect(Collectors.toList());
   }

passes entityId value null (It's called from writeProjectUdfValues()) method.

Project UDF is created in our code as follows:

        var udf = new UserDefinedField(
                        projectFile.getObjectSequence(UserDefinedField.class).getNext(),
                        UDF_NAME,
                        UDF_NAME,
                        FieldTypeClass.PROJECT,
                        false,
                        DataType.STRING));
        projectFile.getUserDefinedFields().add(udf);
        projectProperties.set(udf, "value");
joniles commented 3 months ago

Hello! Apologies for the delay in responding, I will look at this when I start work again tomorrow.

joniles commented 3 months ago

I think the issue here is caused by the project you're writing not having an explicit value for its Unique ID (i.e. projectProperties.getUniqueID()). This is handled everywhere else when writing an XER file by supplying a default value, but this wasn't handled when writing UDF value assignments. I've refactored the code to address this, the changes will be in the next release. I think you can work around this for now by manually setting the default value for the project Unique ID (e.g. projectProperties.setUniqueID(1)).

smacharacek commented 3 months ago

Thanks Jon, the provided fix solved the issue.