Transform a list into an object

6,475 views
Skip to first unread message

Marvin Froeder

unread,
Oct 8, 2014, 12:53:58 PM10/8/14
to mapstru...@googlegroups.com
Hi,

First, excellent job on mapstruct.  Works very well, and compile time check works like a charm!

Te question I have is: Can I turn a List of something into a Object?

Lets say:

public class Source {
    private List<Something> complexInformation;
   //getter & setter
}


public class Target {
    private int informationCount;
    private double infomationAverage;
    private String mostRelevantInformation;
   //getters & setters
}

Then I would map like:

    @Mapping(source = "complexInformation", target = "informationCount")
    Target count(List<Source> source);

    @Mapping(source = "complexInformation", target = "mostRelevantInformation")
    Target relevant(List<Source> source);

    @Mapping(source = "complexInformation", target = "infomationAverage")
    Target averate(List<Source> source);


It would be more like a map->reduce scenario.

Is there anything on mapstruct ready for that?
If not, is this something you guys would like to get (I can make and submit a pull request)?


Thanks.

Gunnar Morling

unread,
Oct 9, 2014, 2:47:19 AM10/9/14
to Marvin Froeder, mapstru...@googlegroups.com
Hi Marvin,

2014-10-08 18:53 GMT+02:00 Marvin Froeder <vel...@gmail.com>:


First, excellent job on mapstruct.  Works very well, and compile time check works like a charm!

Thanks for the nice feedback, glad to hear that MapStruct is helpful to you! 

Te question I have is: Can I turn a List of something into a Object?

    @Mapping(source = "complexInformation", target = "informationCount")
    Target count(List<Source> source);

    @Mapping(source = "complexInformation", target = "mostRelevantInformation")
    Target relevant(List<Source> source);

    @Mapping(source = "complexInformation", target = "infomationAverage")
    Target averate(List<Source> source);


It would be more like a map->reduce scenario.

Is there anything on mapstruct ready for that?

Atm. that's not possible, I think there is even an check for detecting methods which convert from List to Object and raise an error.

This might be an interesting use case for the new expression feature though (depending on whether your "reduce" logic can be expressed in a single expression usable in a variable assignment:

    @Mapping(target = "informationCount", expression="java(source.size())")
    Target count(List<Source> source);
  
If not, is this something you guys would like to get (I can make and submit a pull request)?

Any help with the project is welcome :) Do you have any specific idea how such feature would look API-wise? I.e. in which way would the reduce logic be specified? I think as a first step it'd be helpful to relax the check mentioned above and allow for such methods if an expression is given.

--Gunnar

Marvin Froeder

unread,
Oct 9, 2014, 6:57:29 AM10/9/14
to mapstru...@googlegroups.com, vel...@gmail.com

Any help with the project is welcome :) Do you have any specific idea how such feature would look API-wise? I.e. in which way would the reduce logic be specified? I think as a first step it'd be helpful to relax the check mentioned above and allow for such methods if an expression is given.


I had something like this in mind: 

    @Mappings( {
        @Mapping(source = "collection", target = "count", transformation = CountTransformer.class),
        @Mapping(source = "collection", target = "average", transformation = AverageTransformer.class),
        @Mapping(source = "collection", target = "mostRelevant", transformation = MostRelevantTransformer.class)
    } )
    Target convert(Source source);


CountTransformer would implement Transformer<List<String>, Long>
AverageTransformer implements Transformer<List<String>, Double>
MostRelevantTransformer implements Transformer<List<String>, String>


When using @Inject would allow way more complex transformations (if need of course)....

Does it make any sense?

Gunnar Morling

unread,
Oct 9, 2014, 5:59:12 PM10/9/14
to Marvin Froeder, mapstru...@googlegroups.com
2014-10-09 12:57 GMT+02:00 Marvin Froeder <vel...@gmail.com>:

Any help with the project is welcome :) Do you have any specific idea how such feature would look API-wise? I.e. in which way would the reduce logic be specified? I think as a first step it'd be helpful to relax the check mentioned above and allow for such methods if an expression is given.


I had something like this in mind: 

    @Mappings( {
        @Mapping(source = "collection", target = "count", transformation = CountTransformer.class),
        @Mapping(source = "collection", target = "average", transformation = AverageTransformer.class),
        @Mapping(source = "collection", target = "mostRelevant", transformation = MostRelevantTransformer.class)
    } )
    Target convert(Source source);


CountTransformer would implement Transformer<List<String>, Long>
AverageTransformer implements Transformer<List<String>, Double>
MostRelevantTransformer implements Transformer<List<String>, String>

I'm wondering in which way such a transformer would be different from another mapping method which is invoked (see http://mapstruct.org/documentation/#section-05-03)?

You can register other (generated or hand-written) mappers via @Mapper#uses(). Their methods will then be candidates for mapping properties with different source and target types. So you could e.g. have the following:

    // manually implemented
    public class InformationMapper {
        public int countInformation(List<Information> information) { return information.size(); }
        public double getAverage(List<Information> information) { ... }
    }

    // mapper interface
    @Mapper(uses=InformationMapper.class) 
    public interface MyMapper {
        
        @Mappings( {
            @Mapping(source = "collection", target = "count"), // InformationMapper#countInformation() will be invoked as it matches source and target type
            @Mapping(source = "collection", target = "average"), //InformationMapper#getAverage() will be invoked 
            @Mapping(source = "collection", target = "mostRelevant") // ...
        } )
        Target convert(Source source);
    }

Would that work?

Note that the upcoming Beta3 release brings a concept of "qualifiers" which will allow to select amongst several potential mapping methods which would suit for one given property mapping.

--Gunnar

When using @Inject would allow way more complex transformations (if need of course)....

Does it make any sense?

--
You received this message because you are subscribed to the Google Groups "mapstruct-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mapstruct-use...@googlegroups.com.
To post to this group, send email to mapstru...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Marvin Froeder

unread,
Oct 9, 2014, 7:03:58 PM10/9/14
to Gunnar Morling, mapstru...@googlegroups.com
I guess only the @Inject ....

That would open a ton of possibilities....

When using @Mapper all is static right?!

Gunnar Morling

unread,
Oct 10, 2014, 2:23:22 AM10/10/14
to Marvin Froeder, mapstru...@googlegroups.com
2014-10-10 1:03 GMT+02:00 Marvin Froeder <vel...@gmail.com>:
I guess only the @Inject ....

That would open a ton of possibilities....

When using @Mapper all is static right?!

MapStruct can integrate with dependency injection APIs such as CDI or Spring (see http://mapstruct.org/documentation/#section-04-02). Just define the component model to use within the @Mapper annotation:

    @Mapper(componentModel="cdi")
    public interface MyMapper { ... }

 You can then retrieve that mapper via dependency injection. Also all other mapper it references itself will be obtained via DI, e.g. via @Inject in the case of CDI.

Is that what you're after?

--Gunnar

 

Sjaak Derksen

unread,
Dec 1, 2014, 4:56:03 PM12/1/14
to mapstru...@googlegroups.com
Hi,

I posted an example on how to do this by means of qualifiers in bet3.. Here's the link; https://github.com/mapstruct/mapstruct-examples/tree/master/maptruct-iterable-to-non-iterable

Best regards,
Sjaak
Reply all
Reply to author
Forward
0 new messages