Skip to content

Add nullability to MapStruct model - #4131

Open
hduelme wants to merge 135 commits into
mapstruct:mainfrom
hduelme:add-nullability-to-model
Open

hduelme wants to merge 135 commits into
mapstruct:mainfrom
hduelme:add-nullability-to-model

Conversation

@hduelme

@hduelme hduelme commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Implementation

The PR adds nullability as a state of type instances. It represents whether a return type, parameter or field can be null or whether null can be considered as a value.
How nullability is used by MapStruct:

  1. The new NullabilityResolver is made accessible in DefaultModelElementProcessorContext for all processors. The NullabilityResolver is the main point for determining nullability.
  2. The parameter and return type nullability of the SourceMethods is discovered and stored in MethodRetrievalProcessor.
  3. MapperCreationProcessor creates the mappings according to the nullability values discovered in step 2.
  4. Add the JSpecify annotations if available with the NullabilityAnnotationProcessor. I have decided to always add them if available, to ensure the highest possible compatibility with the checking frameworks. The way they are added is a reverse resolve approach (resolve outside-in). First the nullability scope of the target package is determined. Annotations from the base mapper are then inherited if they do not match the outer nullability scope. Finally @Nullable/@NonNull is added if necessary in its scope. This closes Decide whether or not we should mark generated code with JSpecify annotations #4036 and JSpecify: Propagate nullability annotations to mapper implementation #4076. This is an alternative solution to #4076 Propagate JSpecify nullability annotations to the mapper implementation #4112

In order to match the specified nullability requirements as often as possible, the built-in methods were modified so that they no longer accept and return null as a value.The exceptions are the following, as they can also return null under other conditions:

  • JaxbElemToValue
  • XmlGregorianCalendarToJodaDateTime
  • XmlGregorianCalendarToJodaLocalDate
  • XmlGregorianCalendarToJodaLocalDateTime
  • XmlGregorianCalendarToJodaLocalTime
  • XmlGregorianCalendarToLocalDateTime

In addition the new strict matching of nullability requirements causes some changes:

As mentioned some changes are breaking and should be discussed or at least mentioned in the release notes.

Testing

Some tests are worth mentioning.

For built-in methods I added JspecifyBuildInTest. Here I wanted three types of tests for each conversion. One where the source values are @NonNull, one where the target values are @NonNull and one where both are @NonNull. Instead of tripling the test classes, I decided to move them into a package and use @WithPackageInfo to mark them as nullable or non nullable. While testing this I discovered #4132. That's why I only added fixture comparison tests.

@NullMarked can also be applied at module scope, instead of marking the whole processor tests with @NullMarked I decided to create a dedicated integration test for it.

JSpecifyContainerPropertyTest now checks if collections/maps/streams are null-checked if needed. Thanks to @zanarellidev for finding this. Alternative solution to #4103

In the integration test I found two JDK8 bugs resulting in the exclusion of some JSpecify tests from fullFeatureTest()

DestinationClassNameTest/DestinationPackageNameTest now always run with mapstruct.disableJSpecify. The problem is that eclipse 1.6 has an issue when resolving a non-existing package and creating it afterward.

Other

I left all commits in here for now. If I should squash them, I will do so.

@hduelme
hduelme marked this pull request as draft September 19, 2026 16:13
@hduelme
hduelme requested a review from filiphr September 19, 2026 22:43
@hduelme hduelme changed the title Add nullability to model Add nullability to MapStruct model Sep 19, 2026
@hduelme
hduelme marked this pull request as ready for review September 19, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decide whether or not we should mark generated code with JSpecify annotations

2 participants