Skip to content

Generic @AfterMapping does not consider @MappingTarget properly in 1.5 #3036

@Hatzen

Description

@Hatzen

Expected behavior

Recently I tried updating from 1.4.1 to 1.5.2 to use the new cool SubclassMapping feature.
But doing so seems to change the behaviour of AfterMapping with generic target classes.

In 1.4.1 the generated code for (this kotlin snippet)

        @AfterMapping
        fun <T> updateUniqueIdIfNeededWhenClassMatches(source: Object, @MappingTarget target: T) where T : UniqueRealmObject, T : RealmObject {
            if (target.persistenceId == UniqueRealmObject.ID_META_NEWEST_ID) {
                UniqueRealmObject.getNewestIdForEntity(target)
            }
        }

worked out well and just called the method updateUniqueIdIfNeededWhenClassMatches on instances that will be mapped to Classes implementing the two interfaces UniqueRealmObject and RealmObject.

Actual behavior

But after updating mapstruct the generated code runs into an compiler issue, as the method is tried to call for every single Object (so probably now is only considering the source type)

error: method updateUniqueIdIfNeeded in class UniqueRealmObjectMapper cannot be applied to given types;
                uniqueRealmObjectMapper.updateUniqueIdIfNeeded( storeData, deviceDataOnlinePersistence );
                                       ^
          required: Object,T
          found: DeviceDataOnline,DeviceDataOnlinePersistence
          reason: inference variable T has incompatible bounds
            lower bounds: RealmObject,UniqueRealmObject
            lower bounds: DeviceDataOnlinePersistence
          where T is a type-variable:
            T extends RealmObject,UniqueRealmObject declared in method <T>updateUniqueIdIfNeeded(Object,T)

After searching a while within the github issues, documentation and changelog, i could not see that this behaviour were broken on purpose. Although there are some related topics of aftermapping and generic handling.

There is a quite simple workaround (at least for smaller projects)

@AfterMapping
        fun <T> updateUniqueIdIfNeeded(source: Object, @MappingTarget target: Object) {
            if (target is UniqueRealmObject && target is RealmObject) {
                updateUniqueIdIfNeededWhenClassMatches(source, target)
            }
        }

        fun <T> updateUniqueIdIfNeededWhenClassMatches(source: Object, @MappingTarget target: T) where T : UniqueRealmObject, T : RealmObject {
            if (target.persistenceId == UniqueRealmObject.ID_META_NEWEST_ID) {
                UniqueRealmObject.getNewestIdForEntity(target)
            }
        }

But i wondered if this is an intended change as it is a kind of downgrade (at least fo me and this very special case) and looks more like a (small) breaking change version update.

Steps to reproduce the problem

I guess the provided examples above should be sufficient as they are not complex. But i can provide a standalone example if needed.

MapStruct Version

MapStruct 1.5.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions