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

Add option to map Collections to Immutable Lists #3334

Open
holistic-developer opened this issue Jul 18, 2023 · 6 comments · May be fixed by #3356
Open

Add option to map Collections to Immutable Lists #3334

holistic-developer opened this issue Jul 18, 2023 · 6 comments · May be fixed by #3356
Labels
Milestone

Comments

@holistic-developer
Copy link

Use case

By default, when generating a mapping method using an interface, the following would lead to generated code returning an ArrayList.

public List<Abc> convertToAbcList(List<AbcDto> abcs);

generates:

public List<Abc> convertToAbcList(List<AbcDto> abcs) {
        if (abcs == null) {
            return null;
        } else {
            List<Abc> list = new ArrayList(abcs.size());
            Iterator var3 = abcs.iterator();

            while(var3.hasNext()) {
                AbcDto abcDto = (AbcDto)var3.next();
                list.add(this.convertToAbc(abcDto));
            }

            return list;
        }
    }

(convertToAbc is also defined in the same interface)

There could be an option in the @mapping annotation to control whether or not an immutable collection is returned from the mapping function.

Generated Code

public List<Abc> convertToAbcList(List<AbcDto> abcs) {
        if (abcs == null) {
            return null;
        } else {
            List<Abc> list = new ArrayList(abcs.size());
            Iterator var3 = abcs.iterator();

            while(var3.hasNext()) {
                AbcDto abcDto = (AbcDto)var3.next();
                list.add(this.convertToAbc(abcDto));
            }

            return List.copyOf(list);
        }
    }

List.copyOf(list) wraps the existing collection into an unmodifiable version.

Alternatively the following would also be possible:

public List<Abc> convertToAbcList(List<AbcDto> abcs) {
        if (abcs == null) {
            return null;
        } else {
            return abcs.stream().map(convertToAbc).toList();
        }
    }

Possible workarounds

My current workaround is to override these mapping functions by providing a default implementation that does the mapping using a stream and the toList collector.

default public List<Abc> convertToAbcList(List<AbcDto> abcs) {
    return abcs.stream().map(this::convertToAbc).toList();
}

MapStruct Version

1.5.5.Final

@filiphr
Copy link
Member

filiphr commented Jul 29, 2023

Thanks for the detailed request @holistic-developer. We'll have this into consideration. Currently, we are focused on the 1.6 release, so we can start looking into this maybe after that. If someone is interested in contributing this, feel free to let us know

j-be added a commit to j-be/mapstruct that referenced this issue Aug 6, 2023
j-be added a commit to j-be/mapstruct that referenced this issue Aug 6, 2023
@j-be
Copy link

j-be commented Aug 6, 2023

I got bored on a rainy Sunday afternoon, so I gave it a go. See #3356.

I tried to be as little invasive as possible.

My draft introduces a new annotation, @Unmodifiable, which can be added to methods returning Collections (and supported subclasses) Maps, so it would read:

public interface SomeMapper {

    Target map(Source source);    

    @Unmodifiable List<Target> map(List<Source> sources);
}

Let me know what you think 😄

j-be added a commit to j-be/mapstruct that referenced this issue Aug 6, 2023
@j-be
Copy link

j-be commented Oct 18, 2023

Sorry for spamming, but are there any news about this?

@filiphr
Copy link
Member

filiphr commented Nov 26, 2023

Sorry @j-be, we've been busy with other things. I'll try to carve out some time to review this. I am not sure if going with a new annotation for this is the right approach, I would prefer something via @IterableMapping for this to be honest.

j-be added a commit to j-be/mapstruct that referenced this issue Dec 3, 2023
j-be added a commit to j-be/mapstruct that referenced this issue Dec 3, 2023
@j-be
Copy link

j-be commented Dec 3, 2023

@filiphr I've rewritten it to take the parameter via IterableMapping and MapMapping respectively.

@filiphr filiphr added this to the 1.6.0.Beta2 milestone Dec 15, 2023
@filiphr
Copy link
Member

filiphr commented Dec 15, 2023

Thanks @j-be. I've put this on 1.6.0.Beta2 and will try to review it soon.

@filiphr filiphr modified the milestones: 1.6.0.Beta2, 1.7.0 Mar 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants