Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Kiran S
    @kirans9731
    I do see an open un-addressed issue mapstruct/mapstruct#1818
    Any help would be much appreciated. Thanks
    Sjaak Derksen
    @sjaakd
    Seems that mapstruct tries to recreate a file. I'm not too familiar with gradle, but I guess there's a something like a clean compile / install too. Have you tried that?
    Kiran S
    @kirans9731
    Yes doesn't really help. Sometimes Invalidating IntelliJ Cache and Restarting or reimporting the project after deleting '.idea' works but I start getting this error again after few builds. I have not been able to identify the root cause.
    Sjaak Derksen
    @sjaakd
    Was it, by any chance introduced by an intellij update? It did you update mapstruct recently?
    Abraham Menacherry
    @menacher

    Hi, I am new to mapstruct and have a question on mapping a field on a nested object.

    Source is
    class SourceA {
    String field1;
    SourceB fieldB;
    }
    class SourceB {
    String field1;
    String field2;
    String field3;
    }

    Target class structure is somewhat similar to source, however, it has a fieldX in class TargetB which requires special mapping.
    class TargetA {
    String field1;
    TargetB fieldB;
    }
    class TargetB {
    String field1;
    String field2;
    String field3;
    String fieldX; // X's value is a based on some if/else conditions on field1, 2 etc.
    }

    When I do a mapping, how can i specify that fieldX needs to be mapped using some special hand coded logic?

    @Mapper
    MyMapper {

    TargetA sourceAToTargetA(SourceA source)
    
    @Mapping(source = "<what do i put here to invoke special logic just for fieldX>", target = "fieldX")
    TargetB sourceBToTargetB(SourceB source)

    }

    Raimund Klein
    @Chessray
    @menacher Specify the whole object and use a custom method: http://mapstruct.org/documentation/stable/reference/html/#adding-custom-methods
    If necessary, you can aid MapStruct by use of the @Named annotation: http://mapstruct.org/documentation/stable/reference/html/#selection-based-on-qualifiers
    Abraham Menacherry
    @menacher
    @Chessray But, I wouldn't be able to make use of the default setters for all similarly named fields right? I would have to hand code all the mapping in that scenario. For e.g. it would be great if field1,2,3 is automatically set and only for field x, this special logic needs to be done.
    Right now i used a decorator to get this behavior, but i was wondering if there was something easier than that.
    Also, another question i had was whether @Named methods could be passed context objects and @MappingTarget objects since the logic involved requires access to the existing object.
    Adis Bajric
    @abajric1
    I'm not sure how efficient this is , but I solved this in way that you put logic outside of mapper (service layer) and than pass calculated objects(source fields) into mapper method together with source. Than when you can make @Mapping , method parameters have advantage over source fields. Rest of fields will be mapped by default (ie. source object fields will be mapped to target object fields with same name). Hope this help you.
    Adis Bajric
    @abajric1
    @menacher @Mapping(source="fieldX",target="fieldX")
    TargetB sourceBToTargetB(SourceB source, String fieldX) ,
    Abraham Menacherry
    @menacher
    Ah! That seems a good idea indeed. Thank you!
    Josh Fermin
    @joshfermin
    Hi all I'm trying to create a shared base class to map UUID to String via a qualifier, but the moment I try to inherit from multiple classes I get an ambiguous mapping method error:
    @Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, uses = [RoleMapper::class])
    abstract class EmployeeMapper : UuidMapper() {
        @Mappings(
                Mapping(source = "employee.id", target = "employee.id", qualifiedByName = ["uuidToString"])
        )
        abstract fun employeeResponseToGrpcEmployeeResponse(resp: GetEmployeeResponse): GetOneEmployeeResponse
    }
    
    @Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
    abstract class RoleMapper : UuidMapper() {
        @Mappings(
                Mapping(source = "locationId", target = "locationId", qualifiedByName=["uuidToString"])
        )
        abstract fun roleResponseToGrpcRole(resp: RoleResponse): Role
    }
    
    abstract class UuidMapper {
        @Named("uuidToString")
        fun uuidToString(uuid: UUID): String {
            return uuid.toString()
        }
    }
    Abraham Menacherry
    @menacher
    How does mapstruct guarantee order of mapping. I would like the parent objects mapped first, then the child objects. I provided the @Mappings order with parent mapping first and then child, but the generated code has child first
    Abraham Menacherry
    @menacher
    ok, just saw the dependsOn attribute on Mapper
    Filip Hrisafov
    @filiphr
    @joshfermin the reason why you see that is because you are extending from UuidMapper and thus have the same method twice for UUID to String. I would suggest that you define your own class / interface with a static method and then use it via Mapper#uses both in RoleMapper and EmployeeMapper
    Sjaak Derksen
    @sjaakd
    @menacher .. very recently I refactored the code so that to start with, the order in which you specify mappings is input to the order. It was arbitrary before. Next depensOn kicks in. So perhaps you can experiment with that as well
    Tumanov
    @TumanovViktor
    Hello, MapStruct is perfect, thank you! I just have one question: I have a project with lots of modules and I want to have one BaseConfig, where I will define all Mappers I want to use across my app and one more mapper config in some module, where I will create mappings for base classes. So I would expect, that if I try smth like @MapperConfig(uses = { all my mappers }) BaseConfig and @MapperConfig SomeConfig extends BaseConfig, this child mapper config will be able to see "uses" from parent config, but it doesn't. Do I have any other way to define all my mappers in one place so I don't need to rewrite it in each child mapper? I hope I explained it well, I will be happy for any help! Thank you.
    Actually I wrote it wrong. I don't see Mappers from "uses" of BaseConfig from @Mapper(config = SomeConfig.class) class.
    Sjaak Derksen
    @sjaakd
    It's more the other way around. The interface (it must be an interface) annotated with @MapperConfig is the central configuration. It can be used by a Mapper (@Mapper annotated abstract class or interface) via @Mapper#config=
    A config method cannot inherit.. but a mapper can inherit the mappings from a config method (or reverse)
    Robert
    @robertvb

    Hey guys, quick question: is it possible to map one target property to multiple source properties? I get the following error: "Error:(17, 17) java: Target property "countryOfResidence" must not be mapped more than once."

    What I am trying to do:

    @Mapping(source = "CountryOfResidence", target = "countryOfResidence")
    @Mapping(source = "Nationality", target = "countryOfResidence")
    UserNatural mapToMangoPayUser(UserModel user);

    Raimund Klein
    @Chessray
    @robertvb No, that is not possible. A target property can only ever have one source, the logic being that it is always completely overwritten. What are you trying to do that you feel you require two source properties for one target?
    Robert
    @robertvb
    Hi @Chessray first of all thank you for your quick response. Yes, The thing is: I am trying to integrate to an external system that differentiates country of residence and nationality as two fields. In my system, there are just one field for both concepts. So I have 1 target property that I want to map to 2 source properties. Does it make sense for you? :)
    Raimund Klein
    @Chessray
    So what's the intended logic for this? Say, the source "CountryOfResidence" says "United Kingdom", and the source "Nationality" says "Germany", what's the intended value for the target "countryOfResidence"?
    Robert
    @robertvb
    Absolutely, You are totally right, It was a typo, I just put the source field in the target and vice-versa. What I really want to do is map one source property to two target properties. Sorry and thanks for that
    and it is working perfectly. thanks
    Raimund Klein
    @Chessray
    Happens to the best of us. :-) Glad I was able to help.
    Tumanov
    @TumanovViktor
    Hello guys, one more question :-) I want to define one mapping method as default in interface annotated @MapperConfig, so this method is used in @Mapper, that uses this config. But when I am compiling this, I get compilation error: Error:(28, 23) java: Can't map property "A" to "B". Consider to declare/implement a mapping method: "B map(A value)". So I guess my mapper doesn't see my default method from config. Any other way to do what I want?
    I don't want to move this default method to Mapper, because this config is used in multiple mappers, so after I will need to copy this method in each mapper...
    So basically it is just a common mapping method for every mapper, which uses this config.
    Raimund Klein
    @Chessray
    That's not the intended use for a @MapperConfig. However, you can define a separate @Mapper with only this method and let other @Mappers use it.
    Tumanov
    @TumanovViktor
    @Chessray OK, thank you.
    Raimund Klein
    @Chessray
    Or (I think) the @MapperConfig can use that @Mapper as well if you don't want to add both into every single use.
    Filip Hrisafov
    @filiphr
    Keep in mind that the classes in Mapper#uses doesn't have to be annotated with @Mapper
    You can have any class with or without static methods
    Darren
    @Darreny_gitlab

    Hi all - I've got a question about mapping collections -- I am trying to map a java.util.List<T> to a custom collection CustomList<R>. The CustomList is used in a wide variety of places for different types, and the contents of the List need to also be mapped before being put into a CustomList.

    I want to define the mappings from T to R, but not need to define the mappings from one list to another. Is there a good way to do this generically?

    Sjaak Derksen
    @sjaakd
    Does CustomList implement List?
    Darren
    @Darreny_gitlab
    it doens't unfortunately
    Sjaak Derksen
    @sjaakd
    You can write your own implementation. Within the mapper as default method (when mapper in an interface), method (when mapper is abstract) or even in a utility class as used mapper). Mapstruct will select that method whenever it encounters a need for it.
    Tumanov
    @TumanovViktor
    Hello, guys! Maybe you know the way how to invert boolean value? I have such mapping: @Mapping(source = "alive", target = "!dead") (just an example). I need this because my frontend field is opposite to Database.
    I can use expression of course, but I don't really want to...
    Raimund Klein
    @Chessray
    Expression would have been my first suggestion.
    Why don't you "really want to"?
    Tumanov
    @TumanovViktor
    I hoped this case is done "out-of-the-box", expressions are very common, but it is ok. I will use expressions :) Thank you.
    Darren
    @Darreny_gitlab
    @sjaakd Is there a way in a custom mapping to defer the mapping of the child-objects in the lists back to mapstruct? As it is a generic collection, I was hoping I could define the mappings of the types with mapstruct and not need to have explicit instanceofs to explicitly select the mapping functions for each child object
    Sjaak Derksen
    @sjaakd
    @Darreny_gitlab . If you implement such method as default method (@Mapper interface) or non-abstract-method (@Mapper abstract class) you can call this from the method body to do the callback. If you implement it in a used mapper you probably need the mechanism proposed in #1637
    Sjaak Derksen
    @sjaakd

    @TumanovViktor you can also implement a mapping method

        @Qualifier
        @Target(ElementType.METHOD)
        @Retention(RetentionPolicy.CLASS)
        public @interface Invert {
      }
    @Invert
    default boolean invert( boolean arg ) { return !arg }

    to trigger this method only in this scenario you use the qualifier:

    @Mapping(source = "alive", target = "dead", qualifiedBy=Invert.class)