Expected behavior
Summary
The processor test suite (mapstruct/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time) contains tests that fail intermittently due to non-deterministic behavior in the code generation process. These issues were discovered using the NonDex tool. The root causes are related to iterating over collections with no guaranteed order, such as method lists from the compiler and HashSets.
Root Cause Analysis
Unstable Field Order: The MapperRetrievalProcessor iterates through each ExecutableElement from elementUtils.getAllEnclosedExecutableElements() to add method into List. However, getAllEnclosedExecutableElements is implemented using a HashSet which the order is not guaranteed to be stable. The processor then discovers and creates the required DateTimeFormatter fields in this unstable order, leading to a non-deterministic layout in the final generated file.
Potential Fix
- I will open a pull request for modification of the comparing logic in JavaFileAssert.java by sorting the fields in both files to make the comparison more robust.
- A more fundamental and valuable alternative would be to make the code generation itself predictable. It can be fixed by sorting the list of methods right after they are retrieved from the compiler, before any processing happens.
Actual behavior
Unstable Field Order in Generated Mappers
The order of helper fields (specifically DateTimeFormatter fields) in the generated mapper implementation classes is not consistent across builds.
Steps to reproduce the problem
This non-deterministic behavior can be reliably reproduced by running the NonDex Maven plugin on the processor module.
- Navigate to the root of the MapStruct project.
- Run the following command:
mvn -pl processor edu.illinois:nondex-maven-plugin:2.2.1:nondex
- Observe that the build will fail intermittently on tests like
Java8CustomPatternDateTimeFormatterGeneratedTesteach
MapStruct Version
MapStruct 1.7.0-SNAPSHOT
Expected behavior
Summary
The processor test suite (mapstruct/processor/src/test/java/org/mapstruct/ap/test/conversion/java8time) contains tests that fail intermittently due to non-deterministic behavior in the code generation process. These issues were discovered using the NonDex tool. The root causes are related to iterating over collections with no guaranteed order, such as method lists from the compiler and
HashSets.Root Cause Analysis
Unstable Field Order: The
MapperRetrievalProcessoriterates through each ExecutableElement from elementUtils.getAllEnclosedExecutableElements() to add method into List. However, getAllEnclosedExecutableElements is implemented using a HashSet which the order is not guaranteed to be stable. The processor then discovers and creates the requiredDateTimeFormatterfields in this unstable order, leading to a non-deterministic layout in the final generated file.Potential Fix
Actual behavior
Unstable Field Order in Generated Mappers
The order of helper fields (specifically
DateTimeFormatterfields) in the generated mapper implementation classes is not consistent across builds.Run 1 Output:
Internal Field Order (from debug print):
Run 2 Output:
Internal Field Order (from debug print):
Steps to reproduce the problem
This non-deterministic behavior can be reliably reproduced by running the NonDex Maven plugin on the
processormodule.Java8CustomPatternDateTimeFormatterGeneratedTesteachMapStruct Version
MapStruct 1.7.0-SNAPSHOT