Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable non-null check option on @AfterMapping with @MappingTarget #3544

Open
WalronGabor opened this issue Mar 4, 2024 · 1 comment
Open

Comments

@WalronGabor
Copy link

WalronGabor commented Mar 4, 2024

Use case

I use Map class to create XML messages, and I need a check if the created XML element is only an empty element. If empty then return null will do the trick.
This all thing is needed when I map a multi level XML tag, like::
@Mapping(target = "account.equationShortAccountNumber.branchCode", source = "branchCode")
Now the MapStruct only could check at the lowest level if the Map contains the branchCode element, and it will crate empty XML tags (now the Account and EquationShortAccountNumber tag).

Now there could be a good WorkAround with https://mapstruct.org/documentation/dev/reference/html/#customizing-mappings-with-before-and-after Example 110. Mapper with @AfterMapping hook that returns a non-null value if I could turn off the non-null check. I created a common @AfterMapping method which could return null if it's just an empty tag, but because the null check I couldn't use it.

Generated Code that would be great

@Mapper
public abstract class VehicleMapper {

    @PersistenceContext
    private EntityManager entityManager;

    @AfterMapping(nullCheck = false) // Default true
    protected <T> T attachEntity(@MappingTarget T entity) {
        return entityManager.merge(entity);
    }

    public abstract CarDto toCarDto(Car car);
}
// Generates something like this:
public class VehicleMapperImpl extends VehicleMapper {

    public CarDto toCarDto(Car car) {
        if ( car == null ) {
            return null;
        }

        CarDto carDto = new CarDto();
        // attributes mapping ...

        carDto = attachEntity( carDto );

        return carDto ;
    }
}

Possible workarounds at the moment

I created a very complicate method with reflections to handle this, but it slows the interfaces. So I started to create manually a lot of AfterMapping method which are check if the XML tag's children are empty tags if yes the set that tag to null. Like:

        @AfterMapping
        default void removeEmptyTags(@MappingTarget AccountRqType result) {
            if (new EquationShortAccountNumberTypeV2().equals(result.getEquationShortAccountNumber())) {
                result.setEquationShortAccountNumber(null);
            }
        }

MapStruct Version

1.5.5.Final

@filiphr
Copy link
Member

filiphr commented Mar 24, 2024

@WalronGabor wouldn't something like in #2610 solve your problems? Basically you can check if the source object has something that should be mapped or not, and it it doesn't we just return null.

So the VehicleMapper will look something like

@Mapper
public abstract class VehicleMapper {

    public abstract CarDto toCarDto(Car car);

    @SourceCondition
    protected boolean isPresent(Car car) {
        return car != null; // You can do other more complex checks here as well
    }
}

The generated code then looks like:

// Generates something like this:
public class VehicleMapperImpl extends VehicleMapper {

    public CarDto toCarDto(Car car) {
        if ( !isPresent( car ) ) {
            return null;
        }

        CarDto carDto = new CarDto();
        // attributes mapping ...

        return carDto ;
    }
}

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

No branches or pull requests

2 participants