Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Filip Hrisafov
    @filiphr
    One small note, remember that when upgrading Spring Boot you are also upgrading some of your other dependencies. In this case Lombok got upgraded to at least 1.18.16. That version has a breaking change for MapStruct users (have a look at https://projectlombok.org/changelog) and you need to add the lombok-mapstruct-binding for this to work
    Daniel Lindberg
    @dan-lind
    Are there some examples available on how to inject a spring bean into a mapper? I guess it can be done somehow?
    3 replies
    javanerd
    @javanerd
    Hi. Ho. Someone an idea about my question on stackoverflow? If it wouldn’t be urgent as we want this feature to use it in production environment I wouldn’t ask here. Sorry. https://stackoverflow.com/questions/66177352/mapstruct-1-4-x-iterable-to-nonit-sample-works-strange-with-target-dot-operat
    Simone Di Cola
    @dicolasi

    Hi all, I am a bit new with mapstruct. Got the following situation:
    Source:

    public class OutcodeStats {
         double avgPrice;
         double avgPricePsf;
         double avgRent;
         double avgYield;
         double growth1y;
         double growth3y;
         double growth5y;
         String outcode;
         int salesPerMonth;
         int turnover;
         long effectiveDate;
    }

    target:

    public class GrowthStats {
        public String status;
        public String postcode;
        public String postcode_type;
        public String url;
        public List<List<Object>> data;
        public String process_time;
    }

    Basically, I only need to map growth1y, growth3y and growth5y to the list datain target. How do I achieve that?

    44 replies
    mxhc
    @mxhc
    Any recomendations on how to unit test mappers with jpa repositories injected via uses. Implementations use field injection. I created mini test context (configuration class) for this, but I would like to mock it somehow.
    6 replies
    Jonas Dittrich
    @ditscheridou_gitlab
    Hi guys, where would i use the mapstruct-spring-extensions in spring? Would it be used in a Rest Mvc Controller to automatically convert from a json/xml to a domain entity object?
    3 replies
    the examples make it not really clear where you would insert this
    Daniel Lindberg
    @dan-lind

    I have a situation where two target fields are depenging on the same source field, something like this

        @Mapping(target = "data.targetA", source = "sourceA")
        @Mapping(target = "data.targetB", source = "sourceA")
        TargetModel jiraResponseToFmModel(SourceModel sourceModel);

    targetA and targetB are both objects that hold different data based on sourceA. They also hold a UUID, which I need to generate, i.e. it does not come with sourceA. And the UUID needs to be the same for both targetA and targetB.

    Normally I would look to use a custom function, but I'm not sure how I can preserve/reuse the UUID I generate from targetA to targetB or vice versa. Was thinking about @AfterMapping perhaps, would that work? Are there other options?

    2 replies
    Daniel Lindberg
    @dan-lind
    Also wondering if there is any way to add list entries to a single target from multiple sources, or would I need @AfterMapping for that aswell?
    4 replies
    javanerd
    @javanerd
    Hi everyone. I updated my question pointing to the “.” operator on stackoverflow: https://stackoverflow.com/questions/66177352/mapstruct-1-4-x-iterable-to-nonit-sample-works-strange-with-target-dot-operat
    Dennis Melzer
    @MelleD
    Hi @all, Is there an easy way to insert a test method for each string. I would like to call a check for a specific character set before mapping.
    Filip Hrisafov
    @filiphr
    @MelleD I think that you are looking for mapstruct/mapstruct#2051
    Sergio
    @sergiopanico
    Hi everyone, maybe this is already asked (sorry if it is), I'm just wondering if is planned some Vscode plugin for mapstruct. Something similar to that for Eclipse or Idea would be very very useful in vscode.
    dattamberj96
    @dattamberj96

    Hi, IDEA often shows a compiler error in one particular Mapping file - which always disappears as soon as I open the file in the editor. Does that sound familiar to anyone?

    The error message / stacktrace I see in the problem view is as follows:

    /Users/marcel/Git/recommenders/universal/platform/modules/universal-commons-worker/src/main/java/com/jetbrains/recommenders/universal/commons/workers/ArtifactsMapper.java
    Error:(16, 8) java: Internal error in the mapping processor: java.lang.RuntimeException: javax.annotation.processing.FilerException: Attempt to recreate a file for type com.jetbrains.recommenders.universal.commons.workers.ArtifactsMapperGenerated at org.mapstruct.ap.internal.processor.MapperRenderingProcessor.createSourceFile(MapperRenderingProcessor.java:59) at org.mapstruct.ap.internal.processor.MapperRenderingProcessor.writeToSourceFile(MapperRenderingProcessor.java:39) at org.mapstruct.ap.internal.processor.MapperRenderingProcessor.process(MapperRenderingProcessor.java:29) at org.mapstruct.ap.internal.processor.MapperRenderingProcessor.process(MapperRenderingProcessor.java:24) at org.mapstruct.ap.MappingProcessor.process(MappingProcessor.java:283) at org.mapstruct.ap.MappingProcessor.processMapperTypeElement(MappingProcessor.java:263) at ...

    Caused by: javax.annotation.processing.FilerException: Attempt to recreate a file for type com.jetbrains.recommenders.universal.commons.workers.ArtifactsMapperGenerated at jdk.compiler/com.sun.tools.javac.processing.JavacFiler.checkNameAndExistence(JavacFiler.java:725) at jdk.compiler/com.sun.tools.javac.processing.JavacFiler.createSourceOrClassFile(JavacFiler.java:490) at jdk.compiler/com.sun.tools.javac.processing.JavacFiler.createSourceFile(JavacFiler.java:427) at org.mapstruct.ap.internal.processor.MapperRenderingProcessor.createSourceFile(MapperRenderingProcessor.java:56)

    any solution for this ? facing similar issue

    Zane XiaoYe
    @Zane-XY
    hi , can I compile the mapper to 1.7 target? and use the mapper in 1.7 jdk? My compiler JDK is Java 11.
    Filip Hrisafov
    @filiphr
    @Zane-XY we do not officially support this. However, I think that the generated code will be compatible with Java 7
    It is important to use at least Java 8 for the compilation though, as MapStruct uses Java 8 features, such as Stream, Function, Optional, etc.
    Zane XiaoYe
    @Zane-XY
    Yeah, but it still complains the minor version issue, I can compile the generated mapper to 1.7. Does the @Mapper annotation get interpreted at runtime?
    I guess the classloader would still load the Mapper annotation because it’s imported in the code, and found the byte code version is above 7 and throws the error.
    Filip Hrisafov
    @filiphr
    Who is complaining?
    Zane XiaoYe
    @Zane-XY
    the user of the mapper, running on JDK 1.7
    Filip Hrisafov
    @filiphr
    The @Mapper annotation has CLASS retention, so it is only there in the byte code
    Does the user have some kind of an error?
    What is their complain?
    Zane XiaoYe
    @Zane-XY
    java.lang.UnsupportedClassVersionError: org/mapstruct/factory/Mappers : Unsupported major.minor version 52.0 (unable to load class org.mapstruct.factory.Mappers)\n\tat org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:3111)
    @filiphr
    5 replies
    Christian
    @anno1985
    Hi! I've got an @Named("myMethod") mapping method in @Named("myMapper") Mapper C that I want to use in both mappers A and B. I've annotated them with @Mapper(uses = { C.class }) and the corresponding mapping methods in A and B are annotated with @Mapping(target = "...", source = "..." qualifiedByName = {"myMapper", "myMethod" }). From the docs' sections 5.5 and 5.9 (link) I think this is how it should work (although I might be missing something, because I don't fully understand some parts, e.g. 5.6 - like, where is BaseEntity coming from?). Anyway, my AImpl gets C injected (I use the constructor injection strategy, so can see that) - but it's not used. What am I doing wrong; how do I use a named method in C from A and B?
    6 replies
    Rawi01
    @Rawi01

    Hi,
    according to the reference guide mapstruct always use the most specific mapper but it seems like this does not work properly if I use generics. Example:

    @Mapper
    public abstract class TestMapper {
        public abstract void map(Source source, @MappingTarget Target target);
    
        public <T> T mapField(Field<T> s) {
            return s.getA();
        }
    
        public String mapSpecialField(SpecialField s) {
            return s.getB();
        }
    
        @Data
        public static class Source {
            private Field<String> field1;
            private SpecialField field2;
        }
    
        @Data
        public static class Field<T> {
            private T a;
        }
    
        @Data
        public static class SpecialField extends Field<String> {
            private String b;
        }
    
        @Data
        public static class Target {
            private String field1;
            private String field2;
        }
    }

    Result:

    @Generated(
        value = "org.mapstruct.ap.MappingProcessor",
        date = "2021-03-05T10:26:53+0100",
        comments = "version: 1.4.2.Final, compiler: Eclipse JDT (IDE) 1.3.1100.v20200828-0941, environment: Java 14 (AdoptOpenJDK)"
    )
    @ApplicationScoped
    public class TestMapperImpl extends TestMapper {
    
        @Override
        public void map(Source source, Target target) {
            if ( source == null ) {
                return;
            }
    
            target.setField1( mapField( source.getField1() ) );
            target.setField2( mapField( source.getField2() ) );
        }
    }

    Expected result:
    field2 gets mapped using mapSpecialField.

    I can add @Named to select the right method but I thought that it should pick up that mapper automatically. Is there something I have missed or is this a bug?

    Filip Hrisafov
    @filiphr
    I think that this is a bug and that it will work once the work of @sjaakd in mapstruct/mapstruct#2320 is done. Perhaps this mapper can be used as a test case there as well
    Rawi01
    @Rawi01
    Thanks
    jcbodnar
    @jcbodnar

    Is there a reason why MapStruct won't convert a UUID to a String by default? IE, if I have FooEntity.pledgeId which is a UUID and FooAPI.pledgeId which is a String I have to add:

    default String mapUUIDToString(UUID source) {
      return source.toString();
    }

    to my mapper interface. Seems like this would be a fairly common mapping.

    7 replies
    tivrfoa
    @tivrfoa_twitter

    Hi folks!

    Is it possible to ignore just one source field?

        @Mapper( unmappedSourcePolicy = ReportingPolicy.ERROR,
                unmappedTargetPolicy = ReportingPolicy.ERROR)
        static public interface PojoMapper {
            PojoMapper INSTANCE = Mappers.getMapper( PojoMapper.class );
    
            @Mappings({
                @Mapping(source = "x", target = "z"),
                @Mapping(source = "a", target = "t"),
                @Mapping(source = "listaItem", target = "listaItem2"),
                @Mapping(source = "b", ignore = true) // ------------>>> this does not work. :(
            })
            Pojo2 pojo1ToPojo2(Pojo pojo1);
        }
    I changed the source policy to WARN, then everything is fine.
    But maybe would this be a good feature?
    1 reply
    Cassius Vinicius
    @cviniciusm_gitlab

    Hello,

    I'm learning/training MapStruct

    Please, why @AfterMapping code is not working?

    Project repository: https://gitlab.com/cviniciusm/mapstructdemo2.git

    MyEntity.java:

    package br.eti.cvm.mapstructdemo2;
    
    import lombok.*;
    
    import java.time.LocalDate;
    
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class MyEntity {
    
        private String name;
    
        private LocalDate birthday;
    
    }

    MyDto.java:

    package br.eti.cvm.mapstructdemo2;
    
    import lombok.*;
    
    import java.util.Date;
    
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class MyDto {
    
        private String name;
    
        private Date birthday;
    
        private Integer age;
    
    }

    MyMapper.java:

    package br.eti.cvm.mapstructdemo2;
    
    import org.mapstruct.AfterMapping;
    import org.mapstruct.Mapper;
    import org.mapstruct.MappingTarget;
    
    import java.time.LocalDate;
    import java.time.Period;
    
    @Mapper
    public interface MyMapper {
    
        MyEntity toEntity(MyDto dto);
    
        MyDto toDto(MyEntity entity);
    
        @AfterMapping
        default void updateAge(MyEntity entity, @MappingTarget MyDto dto) {
            Period age = Period.between(entity.getBirthday(), LocalDate.now());
    
            dto.setAge(age.getYears());
        }
    
    }

    The generated MyMapperImpl.java:

    package br.eti.cvm.mapstructdemo2;
    
    import br.eti.cvm.mapstructdemo2.MyDto.MyDtoBuilder;
    import br.eti.cvm.mapstructdemo2.MyEntity.MyEntityBuilder;
    import java.time.LocalDateTime;
    import java.time.ZoneOffset;
    import java.util.Date;
    import javax.annotation.Generated;
    import org.springframework.stereotype.Component;
    
    @Generated(
        value = "org.mapstruct.ap.MappingProcessor",
        date = "2021-03-10T18:35:44-0300",
        comments = "version: 1.4.2.Final, compiler: javac, environment: Java 1.8.0_275 (AdoptOpenJDK)"
    )
    @Component
    public class MyMapperImpl implements MyMapper {
    
        @Override
        public MyEntity toEntity(MyDto dto) {
            if ( dto == null ) {
                return null;
            }
    
            MyEntityBuilder myEntity = MyEntity.builder();
    
            myEntity.name( dto.getName() );
            if ( dto.getBirthday() != null ) {
                myEntity.birthday( LocalDateTime.ofInstant( dto.getBirthday().toInstant(), ZoneOffset.UTC ).toLocalDate() );
            }
    
            return myEntity.build();
        }
    
        @Override
        public MyDto toDto(MyEntity entity) {
            if ( entity == null ) {
                return null;
            }
    
            MyDtoBuilder myDto = MyDto.builder();
    
            myDto.name( entity.getName() );
            if ( entity.getBirthday() != null ) {
                myDto.birthday( Date.from( entity.getBirthday().atStartOfDay( ZoneOffset.UTC ).toInstant() ) );
            }
    
            return myDto.build();
        }
    }
    Ivan Franchin
    @ivangfr

    Hi @filiphr ,

    I have a Quarkus app that uses Mapstruct.

    Recently, I've updated Quarkus to version 1.12.2.Final and Mapstruct to 1.4.2.Final.

    Since then, I started facing, sometimes, problems when packaging the app using Maven.

    Questions:

    • Do we need to create something like

       @MapperConfig(componentModel = "cdi")
       interface QuarkusMappingConfig {}

      And then, use it like

       @Mapper(config = QuarkusMappingConfig.class)
       public interface BookMapper {
           ...
       }

    OR

    • We could do something more direct like
       @Mapper(componentModel = "cdi")
       public interface BookMapper {
           ...
       }

    Thanks!

    11 replies
    Filip Hrisafov
    @filiphr
    @cviniciusm_gitlab there is a known problem with Lombok builders when running in the same compilation round
    Cassius Vinicius
    @cviniciusm_gitlab
    @filiphr Thanks. I added lombok-mapstruct-binding coordinate/artifact/dependency already.
    Carlos Bouzón García
    @bougar
    Hello all!!!!
    Zane XiaoYe
    @Zane-XY
    hi, how can I conditionally control when a property should be copied by MapStruct?
    I have a source class, I want to only copy some attributes if some conditions are met.
    13 replies
    Mehmet
    @mehmetcc
    I have several fields in my Entity and I would like to map a Dto with a List containing said fields, for example for a String a and b inside the Entity and a List of Strings inside the Dto
    5 replies
    Can I map the Dto into the Entity, and if so, how?
    Filip Hrisafov
    @filiphr
    @cviniciusm_gitlab this is a known limitation. Check mapstruct/mapstruct#1454
    Anton Vovk
    @antonvovk_gitlab

    Hi there!
    So now I am dealing with a legacy codebase which uses mapstruct 1.2.0.Final and I am trying to upgrade it to 1.4.2.Final. So with the 1.4.2.Final I am having the problem that generated mapper for AddressDto extends wrong class.

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder(toBuilder = true)
    public class CountryDto {
        String name;
        String code;
    
        @Mapper
        @Component
        public interface Converter {
            CountryDto convert(Country from);
    
            default List<CountryDto> convert(List<Country> from) {
                if (from == null) {
                    return null;
                }
                return from.map(this::convert);
            }
    
            default List<Country> reverseConvert(List<CountryDto> from) {
                if (from == null) {
                    return null;
                }
                return from.map(this::reverseConvert);
            }
    
            default Country reverseConvert(CountryDto from) {
                if (from == null) {
                    return null;
                }
                return Country.builder()
                        .name(from.getName())
                        .code(from.getCode())
                        .build();
            }
        }
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder(toBuilder = true)
    public class AddressDto {
        CountryDto country;
        String zipCode;
        String city;
        String street;
        String houseNumber;
        String apartmentNumber;
    
        @Component
        @Mapper(uses = CountryDto.Converter.class)
        public static abstract class Converter {
    
            @Autowired
            private CountryDto.Converter countryMapper;
    
            public Address reverseConvert(AddressDto from) {
                if (from == null) {
                    return null;
                }
                return Address.builder()
                        .country(null)
                        .zipCode(from.zipCode)
                        .city(from.city)
                        .street(from.street)
                        .houseNumber(from.houseNumber)
                        .apartmentNumber(from.apartmentNumber)
                        .country(countryMapper.reverseConvert(from.country))
                        .build();
            }
    
            public abstract AddressDto convert(Address address);
        }
    }

    So here is the generated mapper for AddressDto and as you can see it extends CountryDto.Converter but it should extend AddressDto.Converter. So what do think will be the best approach to resolve this issue? Maybe there can be done some configuration for mapstruct?

    import vlo.domain.rest.controller.products.common.dto.CountryDto.Converter;
    
    @Generated(
        value = "org.mapstruct.ap.MappingProcessor"
    )
    @Component
    public class AddressDto$ConverterImpl extends Converter {
    
        @Autowired
        private Converter converter;
    
        @Override
        public AddressDto convert(Address address) {
            if ( address == null ) {
                return null;
            }
    
            AddressDto addressDto = new AddressDto();
    
            addressDto.setCountry( converter.convert( address.getCountry() ) );
            addressDto.setZipCode( address.getZipCode() );
            addressDto.setCity( address.getCity() );
            addressDto.setStreet( address.getStreet() );
            addressDto.setHouseNumber( address.getHouseNumber() );
            addressDto.setApartmentNumber( address.getApartmentNumber() );
    
            return addressDto;
        }
    }
    2 replies
    Sean Burke
    @seanburke-wf
    I haven't been able to find reference to it, but I have a situation like the following and I'm wondering if there's some way that I can declare these mappings such that the foo -> foo2 and bar -> baz mappings only need to be specified once and the only thing that needs to change is the mapping for prop:
    @Mapper()
    public interface StuffMapper {
      StuffMapper INSTANCE = Mappers.getMapper(StuffMapper.class);
    
      @Mapping(source = "foo", target = "foo2")
      @Mapping(source = "bar", target = "baz")
      @Mapping(target = "prop", expression = "java(null)")
      Stuff thingToStuff(Thing thing);
    
      @Mapping(source = "thing.foo", target = "foo2")
      @Mapping(source = "thing.bar", target = "baz")
      @Mapping(source = "prop", target = "prop")
      Stuff thingToStuff(Thing thing, String prop);
    }
    Or do I just write out a method body for thingToStuff(Thing thing) to call thingToStuff(thing, null)?
    (Could of thought of that before I came here...)
    Filip Hrisafov
    @filiphr
    I would do option 2
    Write a default method delegating to the method with 2 parameters
    japhy
    @JaphyFan
    WeChatWorkScreenshot_4540fb0c-17f7-4dce-98e7-ff732e0f133d.png
    I am using maptsruct in the submodule web-base. when i run this module, there will generate a extra folder in top module. how can i put this in its own module
    1 reply