Sebastian
Sebastian

Reputation: 6057

Force mapstruct not to call has* methods

I wrote a mapstruct mapper that uses a mapping like this:

@Mapping(target = "userId", source = "id.userId")

When I looked at the autogenerated mapstruct class I stubled upon that code:

if ( !foobar.hasId() ) {
    return null;
}

This is a problem for me as hasId() does not what mapstruct expects here. Can I force mapstruct somehow to not generate code that uses this method but checks for id != null or something?

I could use a mapping like @Mapping(target = "userId", expression= "java(...)") but I think there should be another way.

Upvotes: 6

Views: 2285

Answers (3)

M. Justin
M. Justin

Reputation: 21094

MapStruct is treating the hasId() method as a source presence checker method, only setting the id value if it returns true.

If conditionExpression is specified, it is used instead of the source presence checker method. By specifying an always-true value for this, the value will always be mapped, rather than conditionally based on the result of hasId().

@Mapping(target = "userId", source = "id.userId", conditionExpression = "java(true)")

This results in the generated code like the following:

if ( true ) {
    target.setUserId( userId );
}

Upvotes: 3

M. Justin
M. Justin

Reputation: 21094

While the answer that suggests providing your own AccessorNamingStrategy explains how to solve this in general, often disabling the source presence checker is overkill. I think your solution of using expression is probably often the right answer in terms of simplicity for a one-off override.

@Mapping(target = "userId", expression="java(source.getId().getUserId())")
MyTargetType map(MySourceType source);

or

@Mapping(target = "userId", source="id")
MyTargetType map(MySourceType source);

default String map(MySourceTypeId id) {
  return id == null ? null : id.getUserId();
}

Upvotes: 1

Filip
Filip

Reputation: 21393

Yes you can force MapStruct not to use those presenceCheckers. You can find more information in source presence checking in the documentation.

Basically the only way to do this is to provide an implementation of the MapStruct AccessorNamingStrategy. You can just extend the DefaultAccessorNamingStrategy and override itsisPresenceCheckMethod.

You have access to the method ExecutableElement and you can check the type of class it is in and other things as well.

MyAccessorNamingStrategy extends DefaultAccessorNamingStrategy {

    @Override
    public boolean isPresenceCheckMethod(ExecutableElement element) {
        //You can do your checks here. You can ignore certain methods, from certain classes

    }

Remember to register your SPI with a file META-INF-/services/com.example.MyAccessorNamingStrategy

There is also the examples where you can find an example for the SPI.

Upvotes: 5

Related Questions