Coder Social home page Coder Social logo

mapstruct.org's Introduction

MapStruct - Java bean mappings, the easy way!

Latest Stable Version Latest Version License

Build Status Coverage Status Gitter Code Quality: Java Total Alerts

What is MapStruct?

MapStruct is a Java annotation processor for the generation of type-safe and performant mappers for Java bean classes. It saves you from writing mapping code by hand, which is a tedious and error-prone task. The generator comes with sensible defaults and many built-in type conversions, but it steps out of your way when it comes to configuring or implementing special behavior.

Compared to mapping frameworks working at runtime, MapStruct offers the following advantages:

  • Fast execution by using plain method invocations instead of reflection
  • Compile-time type safety. Only objects and attributes mapping to each other can be mapped, so there's no accidental mapping of an order entity into a customer DTO, etc.
  • Self-contained code—no runtime dependencies
  • Clear error reports at build time if:
    • mappings are incomplete (not all target properties are mapped)
    • mappings are incorrect (cannot find a proper mapping method or type conversion)
  • Easily debuggable mapping code (or editable by hand—e.g. in case of a bug in the generator)

To create a mapping between two types, declare a mapper interface like this:

@Mapper
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    @Mapping(target = "seatCount", source = "numberOfSeats")
    CarDto carToCarDto(Car car);
}

At compile time MapStruct will generate an implementation of this interface. The generated implementation uses plain Java method invocations for mapping between source and target objects, i.e. no reflection is involved. By default, properties are mapped if they have the same name in source and target, but you can control this and many other aspects using @Mapping and a handful of other annotations.

Requirements

MapStruct requires Java 1.8 or later.

Using MapStruct

MapStruct works in command line builds (plain javac, via Maven, Gradle, Ant, etc.) and IDEs.

For Eclipse, a dedicated plug-in is in development (see https://github.com/mapstruct/mapstruct-eclipse). It goes beyond what's possible with an annotation processor, providing content assist for annotation attributes, quick fixes and more.

For IntelliJ the plug-in is available within the IntelliJ marketplace (see https://plugins.jetbrains.com/plugin/10036-mapstruct-support).

Maven

For Maven-based projects, add the following to your POM file in order to use MapStruct (the dependencies are available at Maven Central):

...
<properties>
    <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
</properties>
...
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>
...

Gradle

For Gradle, you need something along the following lines:

plugins {
    ...
    id "com.diffplug.eclipse.apt" version "3.26.0" // Only for Eclipse
}

dependencies {
    ...
    implementation 'org.mapstruct:mapstruct:1.5.5.Final'

    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
    testAnnotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final' // if you are using mapstruct in test code
}
...

If you don't work with a dependency management tool, you can obtain a distribution bundle from Releases page.

Documentation and getting help

To learn more about MapStruct, refer to the project homepage. The reference documentation covers all provided functionality in detail. If you need help please ask it in the Discussions.

Building from Source

MapStruct uses Maven for its build. Java 11 is required for building MapStruct from source. To build the complete project, run

./mvnw clean install

from the root of the project directory. To skip the distribution module, run

./mvnw clean install -DskipDistribution=true

Importing into IDE

MapStruct uses the gem annotation processor to generate mapping gems for its own annotations. Therefore, for seamless integration within an IDE annotation processing needs to be enabled.

IntelliJ

Make sure that you have at least IntelliJ 2018.2.x (needed since support for annotationProcessors from the maven-compiler-plugin is from that version). Enable annotation processing in IntelliJ (Build, Execution, Deployment -> Compiler -> Annotation Processors)

Eclipse

Make sure that you have the m2e_apt plugin installed.

Links

Licensing

MapStruct is licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0.

mapstruct.org's People

Contributors

agudian avatar chessray avatar chris922 avatar chschu avatar filiphr avatar galaxxius avatar gunnarmorling avatar izeye avatar jesjos avatar karuppiah7890 avatar kryger avatar lborloz avatar ldicarlo avatar mokszr avatar ptemplier avatar sjaakd avatar tmussi avatar wonsuc avatar zegveld avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mapstruct.org's Issues

java.lang.RuntimeException: java.lang.ClassNotFoundException: Cannot find implementation

I'm starting afresh with MapStruct version 1.0.0.Final and receive the following error when I attempt to execute the codebase,

java.lang.RuntimeException: java.lang.ClassNotFoundException: Cannot find implementation

My Maven POM has the following added already,

            <plugin>
                <groupId>org.bsc.maven</groupId>
                <artifactId>maven-processor-plugin</artifactId>
                <configuration>
                    <defaultOutputDirectory>
                        ${project.build.directory}/generated-sources/annotations
                    </defaultOutputDirectory>
                    <processors>
                        <processor>org.mapstruct.ap.MappingProcessor</processor>
                    </processors>
                    <options>
                        <mapstruct.suppressGeneratorTimestamp>true</mapstruct.suppressGeneratorTimestamp>
                        <!-- <mapstruct.defaultComponentModel>cdi</mapstruct.defaultComponentModel> -->
                    </options>
                </configuration>
                <executions>
                    <execution>
                        <id>process</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>process</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </dependency>
                </dependencies>
            </plugin>

Please note that I've modified the defaultOutputDirectory to be ${project.build.directory}/generated-sources/annotations (added an extra 'annotations`). If not adding that suffix, I am generating two sets of implementation, one at the generated-sources level and another at ..generated-sources/annotations level and that causes duplicate implementation exists error like below during compilation of the project,

error: duplicate class: a.g.x.h.t.mappers.DMapperImpl

The error is occurring when invoking the Mapper class using the below even though I could very well see the Implementations of the Mapper classes at ...target../generated-sources/annotations directory,

DMapper.INSTANCE.sourceToDestination(source);

  1. On a general note, I'm trying to map fields from a bean which is located at say from a package, a.b.c.Bean to another package x.y.z.Bean with about 100s of elements within it (the destination might have couple elements removed, added and renamed fields) but, I couldn't see any straight forward way of achieving this
  2. There isn't good examples out there to showcase how to achieve this and hence it was really hard to get up and running with this. May be the documentation surrounding the usage could be improvised to help out others
  3. In a Mapper which uses other Mappers and say the 4th occurrence uses one of the other Mapper but, the 3rd occurrence field also uses, this plugin is not intelligent enough to scan the used Mappers but, instead it is requiring to specify the other Mapper in the current file
  4. Another thing about the way to identify any issues, I've already installed the MapStruct Eclipse plug-in but, it not helping out with anything and so, I've to do mvn compile on my project to identify the errors/warnings

qualified method is not used in mapping collections

Hi,

I have noticed interesting befaviour that I don't know if it is intended or not. I will try to explain it with example:

//first mapper
@Mappings({ @Mapping(source = "game.players", target = "players", qualifiedBy = QualifyPlayerMapper.class) })
TargetGame mapGame(Game game);

//second mapper
@Mappings({ @Mapping(source = "player.street", target = "addressStreet")})
TargetPlayer mapPlayer(Player player);

//some mapping method that I wanna use and it is qualiffied
@QualifyPlayerMapper
TargetPlayer mapPlayerMyWay(Player player);

so in the generated class, in the playerCollectionToPlayerCollection method, is used  mapPlayer.
In my opinion it should use the second method - mapPlayerMyWay


Regards,
Natalia

Mapping of Map fields to existing target not working with defensive programming style

Hi,

I'm working with Mapstruct 1.2.0.Final and I'm using a "defensive" programming style for a Map field in a class, for security reasons. I mean the field getter returns a copy of the field mappings, and the setter copies the given mappings into the field. Typically, this is done with such getter/setter in the class:

private Map<String, Object> properties;

public Map<String, Object> getProperties() {
    return new HashMap<>(this.properties);
}

public void setProperties(final Map<String, Object> properties) {
    this.properties.clear();
    this.properties.putAll(properties);
}

Mapping another object to an existing instance of this class doesn't work as I expected, because the field setter in never used in implementations generated by Mapstruct. The code below is actually generated:

target.getProperties().clear();
target.getProperties().putAll(...);

To me, this shall be replaced by the policy below:

final Map<String, Object> properties = target.getProperties();
properties.putAll(...);
target.setProperties(properties);

I attached a test case in this issue:
MappingTest.java.zip

Is this feature implemented?
How can I configure/use Mapstruct for such case?
Thanks in advance for your help.
BR

@Mapping generates compilation errors on Maven/Netbeans

Hi,
I'm using jhipster, which generates mapstruct mappings.
I've errors on certain fields (not all of them), if they have multiple @mapping annotation. Only in the EDI. All building process, by maven, is OK.
The error is : "Incompatible types: int cannot be converted to boolean".
Have you any idea ?
Thanks,
Regards.

Add comment for other annotation processors for the installation

A lot of users are having problems, because they don't quite understand the maven compiler annotationProcessorPaths. @alexis-puska suggested that we extend the installation instructions with something like:

<configuration>
    <source>1.6</source> <!-- or higher, depending on your project -->
    <target>1.6</target> <!-- or higher, depending on your project -->
    <annotationProcessorPaths>
        <path>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>${org.mapstruct.version}</version>
        </path>
        <!-- If you use other annotations processor add them here -->
    </annotationProcessorPaths>
</configuration>

I think that this is a good suggestion and would help other developers in issues when MapStruct and Lombok are not working well together due to wrong setup

final value containers

I have something like following structure:
class PersonDto {
final Value name = new Value();
final Value surname = new Value();
}

class Value {
...
void set(String value) {
...
}
String get() {
...
}
}

class Person() {
String name;
String surname;
}

Any clue how to map it? From PersonDto to Person, it is relatively easy, hot to do it in revered order. Mind the Values are final.

Add an F&Q about @Mapper not found

It seems that there is a problem when both mapstruct and mapstruct-jdk8 are found on the classpath. See longer discussion in mapstruct#841. A known problem is the compile dependency on mapstruct in springfox-swagger. I think having this question and an example how to exclude the mapstruct dependency is good to have.

cannot generate the implementation for eclipse

hi I use eclipse Photon (4.8.0) with lombok-1.16.20 mapstruct-1.2.0.Final m2e-apt 1.5.2
jdk 1.8.0_111
the configuration of pom file is

<m2e.apt.activation>jdt_apt</m2e.apt.activation>

org.mapstruct mapstruct 1.2.0.Final compile org.mapstruct mapstruct-jdk8 -- org.apache.maven.plugins maven-compiler-plugin 1.8 1.8 org.mapstruct mapstruct-processor ${org.mapstruct.version}

when i run maven build with command “compile”
I find that the source folder is created,target\generated-sources\annotations .
but the implementation class is not found. Can you please help me

java.lang.ClassNotFoundException: Cannot find implementation for

I'm using mapstruct along with lomback with versions as follows

Java 1.8
springBootVersion = '1.4.3.RELEASE'
gradle version 3.4
mapstructVersion 1.3.0.Beta2
lombokVersion 1.18.0

Configurtions added

dependencies {
classpath('net.ltgt.gradle:gradle-apt-plugin:0.8')
}

plugins {
id 'net.ltgt.apt' version '0.9'
}
ext {
mapstructVersion = "1.3.0.Beta2"
lombokVersion = "1.18.0"
}
apply plugin: 'net.ltgt.apt'

compile "org.mapstruct:mapstruct:${mapstructVersion}", "org.projectlombok:lombok:${lombokVersion}"
apt "org.mapstruct:mapstruct-processor:${mapstructVersion}", "org.projectlombok:lombok:${lombokVersion}"

sourceSets {
main.java.srcDirs += "build/generated/source/apt/main"
}

Still, I see the implementation class is not found. Can you please suggest

Use latest hugo for website

There were some issues when I used a newer version of hugo. Therefore, until now We were using 0.18. The problem was some new property (disablePathToLower, which by default is false) which caused the paths of the released articles to be lower case. We have fixed this.

In any case we need to add the version of hugo in our publish.sh so we are always using a fix version when doing a publish.

How to Map to Generic Type?

PageInfoDto

public class PageInfoDto<T> implements Serializable {

    private int currentPageNum;

    private int totalPageNum;

    private int perPageNum;

    private int totalItemNum;

    private List<T> list;

}

Page

public class Page<T> implements Serializable {

    private int current;

    private int total;

    private int size;

    private int items;

    private List<T> list;

}

say, i have a school list and a student list.

i want to map Page to PageInfoDto and map Page to PageInfoDto。

this is how my mapper looks like;


@Mapper( config = CentralConfig.class, uses = {StudentMapper.class, SchoolMapper.class}, componentModel = "spring")
public interface PageInfoMapper {

    @Mappings({
            @Mapping(target = "list", source = "pageInfo.records"),
            @Mapping(target = "currentPageNum", source = "pageInfo.current"),
            @Mapping(target = "totalPageNum", source = "pageInfo.pages"),
            @Mapping(target = "perPageNum", source = "pageInfo.size"),
            @Mapping(target = "totalItemNum", source = "pageInfo.total"),
    })
    PageInfoDto<SchoolDto> toPageInfoDto1(Page<School> pageInfo);

    @Mappings({
            @Mapping(target = "list", source = "pageInfo.records"),
            @Mapping(target = "currentPageNum", source = "pageInfo.current"),
            @Mapping(target = "totalPageNum", source = "pageInfo.pages"),
            @Mapping(target = "perPageNum", source = "pageInfo.size"),
            @Mapping(target = "totalItemNum", source = "pageInfo.total"),
    })
    PageInfoDto<StudentDto> toPageInfoDto2(Page<Student> pageInfo);

}

this obviously not a clever way to do . is there a better way to do this?

MapStruct not mapping JAXB beans with @XMLSeeAlso annotation

I have the following Java class structure and it's respective mapstruct mapping. Here source and destination beans in mapping are same. I only need to map specific fields to send to a client based on their requirement.

@XmlSeeAlso({A.class, B.class})
public class C extends D implements Serializable {
  //50 odd properties
 // getters&Setters
}
public class A extends C{
 //properties
//getters&setters
}
public class B  extends C{
//properties
//getters&Setters
}
public class D{
//properties
//getters&Setters
}
@Mapper
public interface CMapper{
 C cToC(C c);
A aToA(A a);
B bToB(B b);
D dToD(D d);
//and remaining requrired mappers here
}
public class CMapperImpl implements CMapper{
public C cToC(C c){
}
//mapping logic

A aToA(A a){
//mapping logic
}

B bToB(B b){
//mapping logic
}

D dToD(D d){
//mapping logic
}

}

Code is being generated for all the defined methods in mapper interface. But methods which are defined for mapping A,B classes into C are not being used/called anywhere in the generated code. So fields of those two classes are not being mapped to resultant bean. This works fine when i use dozer. I had to simply specify bean mapping for both A&B with required fields in config xml file. However, It's not working with mapStruct.
@gunnarmorling @sradi @chschu

Changerequest: EnumNamingStrategy

We had to map a lot of jaxb-types with the default-naming-strategy of jaxb (underscores to triple-underscores, ...) and didnt want to map all the Enum manually by the Mapping-annotation.

So we introduced EnumNamingStrategy, simmilar to AccessorNamingStrategy.

mapstruct-1.0.1-modified.zip

We also fixed a typo.

Clean up dead links

We still have some links pointing to cloudbees for our CI, which actually moved to Travis CI.

Check if there are other dead links.

See also this twitter thread

Add development glossary

I think that it would be nice to have a development glossary on our website in order to ease the contribution process. With this "glossary" we can shortly write what each of our terms mean.

This is just an idea that is open for discussion 😄

Chapter 12: specify @Qualifier import

I think it could be useful to specify that @qualifier import is org.mapstruct.Qualifier
In my project, I made the mistake of importing javax.inject.Qualifier which leads to the error message "Ambiguous mapping method..."

Assign List Attribute without creating a copy of List

Source : {
     someList: ArrayList<SomeObject>
}

Target: {
     someList: ArrayLIst<SomeObject>
}

When I use the mapstruct, it will automatically create a new ArrayList and add the list from source in it. However, I just want to use the usual mapping (I want them to point to the same memory location), is there some attribute in mapper that I can configure so that mapstruct will generate

target.setSomeList(source.getSomeList()) 

?

Thank you very much!

Add 1.2 Beta docs and download to website

I like what Django is doing: https://docs.djangoproject.com/en/1.8/intro/overview/#install-it

  • Have a selector overlay allowing to switch between versions
  • on the main page (http://mapstruct.org/documentation/reference-guide/), there should only be a link to "stable" and "dev", pointing to the current stable and work-in-progress versions
  • on older versions (as reachable through that selector) there should be a red banner of sorts warning about this being not the current version
  • on the dev version (as reachable through that selector and from the main page) there should be a yellow banner warning about this being a future work-in-progress version

A useful resource: http://webmasters.stackexchange.com/questions/99867/how-to-correctly-mark-up-different-versions-of-the-same-document-which-are-non-c

java.lang.ClassNotFoundException: Cannot find implementation(gradle+sts+springBoot)

I am sorry that this error occurred during the use of mapstruct.
Environment used : gradle-4.6 STS 3.9.5 springBoot 2.0.4.RELEASE

plugins {
id 'java'
id 'net.ltgt.apt' version '0.9'
}

dependencies {
compile 'org.mapstruct:mapstruct-jdk8:1.3.0.Beta1'
compile 'org.mapstruct:mapstruct-processor:1.3.0.Beta1'
}

Referring to the official Web example, implementation classes can be generated, but this error always occurs when I use the injected bean.
I guess it's related to the environmental version I use. Friends who want to know can help answer? Thanks!!! @filiphr

Use latest in the link for the reference documentation

Instead of explicitly linking it will be good if we can have a link for the latest reference documentation for MapStruct. For example now we have http://mapstruct.org/documentation/1.1/reference/html/index.html, which can stay the same, but we will also have http://mapstruct.org/documentation/latest/reference/html/index.html that always points to the latest version of the documentation. This could help when linking the documentation to questions and/or blog posts. WDYT?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.