mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1417 Add documentation about the builder support
This commit is contained in:
parent
5834368b15
commit
43a9419c33
@ -5,6 +5,8 @@
|
|||||||
:Author: Gunnar Morling, Andreas Gudian, Sjaak Derksen, Filip Hrisafov and the MapStruct community
|
:Author: Gunnar Morling, Andreas Gudian, Sjaak Derksen, Filip Hrisafov and the MapStruct community
|
||||||
:processor-dir: ../../../../processor
|
:processor-dir: ../../../../processor
|
||||||
:processor-ap-test: {processor-dir}/src/test/java/org/mapstruct/ap/test
|
:processor-ap-test: {processor-dir}/src/test/java/org/mapstruct/ap/test
|
||||||
|
:integration-tests-dir: ../../../../integrationtest
|
||||||
|
:immutables-builder-test: {integration-tests-dir}/src/test/resources/immutablesBuilderTest
|
||||||
|
|
||||||
[[Preface]]
|
[[Preface]]
|
||||||
== Preface
|
== Preface
|
||||||
@ -310,6 +312,21 @@ In the generated method implementations all readable properties from the source
|
|||||||
The property name as defined in the http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html[JavaBeans specification] must be specified in the `@Mapping` annotation, e.g. _seatCount_ for a property with the accessor methods `getSeatCount()` and `setSeatCount()`.
|
The property name as defined in the http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html[JavaBeans specification] must be specified in the `@Mapping` annotation, e.g. _seatCount_ for a property with the accessor methods `getSeatCount()` and `setSeatCount()`.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
Fluent setters are also supported.
|
||||||
|
Fluent setters are setters that return the same type as the type being modified.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
public Builder seatCount(int seatCount) {
|
||||||
|
this.seatCount = seatCount;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
====
|
||||||
|
|
||||||
[TIP]
|
[TIP]
|
||||||
====
|
====
|
||||||
When using Java 8 or later, you can omit the `@Mappings` wrapper annotation and directly specify several `@Mapping` annotations on one method.
|
When using Java 8 or later, you can omit the `@Mappings` wrapper annotation and directly specify several `@Mapping` annotations on one method.
|
||||||
@ -594,6 +611,113 @@ You can find the complete example in the
|
|||||||
https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-field-mapping[mapstruct-examples-field-mapping]
|
https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-field-mapping[mapstruct-examples-field-mapping]
|
||||||
project on GitHub.
|
project on GitHub.
|
||||||
|
|
||||||
|
[[mapping-with-builders]]
|
||||||
|
=== Using builders
|
||||||
|
|
||||||
|
MapStruct also supports mapping of immutable types via builders.
|
||||||
|
When performing a mapping MapStruct checks if there is a builder for the type being mapped.
|
||||||
|
This is done via the `BuilderProvider` SPI.
|
||||||
|
If a Builder exists for a certain type, than that builder will be used for the mappings.
|
||||||
|
|
||||||
|
The default implementation of the `BuilderProvider` assumes the following:
|
||||||
|
|
||||||
|
* The type has a parameterless public static builder creation method that returns a builder.
|
||||||
|
So for example `Person` has a public static method that returns `PersonBuilder`.
|
||||||
|
* The builder type has a parameterless public method (build method) that returns the type being build
|
||||||
|
In our example `PersonBuilder` has a method returning `Person`.
|
||||||
|
|
||||||
|
If such type is found then MapStruct will use that type to perform the mapping to (i.e. it will look for setters into that type).
|
||||||
|
To finish the mapping MapStruct generates code that will invoke the build method of the builder.
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
======
|
||||||
|
The <<object-factories>> are also considered for the builder type.
|
||||||
|
E.g. If an object factory exists for our `PersonBuilder` than this factory would be used instead of the builder creation method.
|
||||||
|
======
|
||||||
|
|
||||||
|
.Person with Builder example
|
||||||
|
====
|
||||||
|
[source, java, linenums]
|
||||||
|
[subs="verbatim,attributes"]
|
||||||
|
----
|
||||||
|
public class Person {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
protected Person(Person.Builder builder) {
|
||||||
|
this.name = builder.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Person.Builder builder() {
|
||||||
|
return new Person.Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Builder name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Person create() {
|
||||||
|
return new Person( this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
.Person Mapper definition
|
||||||
|
====
|
||||||
|
[source, java, linenums]
|
||||||
|
[subs="verbatim,attributes"]
|
||||||
|
----
|
||||||
|
public interface PersonMapper {
|
||||||
|
|
||||||
|
Person map(PersonDto dto);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
.Generated mapper with builder
|
||||||
|
====
|
||||||
|
[source, java, linenums]
|
||||||
|
[subs="verbatim,attributes"]
|
||||||
|
----
|
||||||
|
// GENERATED CODE
|
||||||
|
public class PersonMapperImpl implements PersonMapper {
|
||||||
|
|
||||||
|
public Person map(PersonDto dto) {
|
||||||
|
if (dto == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Person.Builder builder = Person.builder();
|
||||||
|
|
||||||
|
builder.name( dto.getName() );
|
||||||
|
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
Supported builder frameworks:
|
||||||
|
|
||||||
|
* https://projectlombok.org/[Lombok] - requires having the Lombok classes in a separate module. See for more information https://github.com/rzwitserloot/lombok/issues/1538[rzwitserloot/lombok#1538]
|
||||||
|
* https://github.com/google/auto/blob/master/value/userguide/index.md[AutoValue]
|
||||||
|
* https://immutables.github.io/[Immutables] - requires using a custom `AccessorNamingStrategy` and a custom `BuilderProvider` (see example in integration tests)
|
||||||
|
* https://github.com/google/FreeBuilder[FreeBuilder]
|
||||||
|
* It also works for custom builders (handwritten ones) if the implementation supports the defined rules for the default `BuilderProvider`.
|
||||||
|
Otherwise, you would need to write a custom `BuilderProvider`
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
In case you want to disable using builders then you can use the `NoOpBuilderProvider` by creating a `org.mapstruct.ap.spi.BuilderProvider` file in the `META-INF/services` directory with `org.mapstruct.ap.spi.NoOpBuilderProvider` as it's content.
|
||||||
|
====
|
||||||
|
|
||||||
[[retrieving-mapper]]
|
[[retrieving-mapper]]
|
||||||
== Retrieving a mapper
|
== Retrieving a mapper
|
||||||
|
|
||||||
@ -2671,3 +2795,19 @@ together with the file `META-INF/services/org.mapstruct.ap.spi.MappingExclusionP
|
|||||||
(e.g. `org.mapstruct.example.CustomMappingExclusionProvider`).
|
(e.g. `org.mapstruct.example.CustomMappingExclusionProvider`).
|
||||||
This JAR file needs to be added to the annotation processor classpath
|
This JAR file needs to be added to the annotation processor classpath
|
||||||
(i.e. add it next to the place where you added the mapstruct-processor jar).
|
(i.e. add it next to the place where you added the mapstruct-processor jar).
|
||||||
|
|
||||||
|
|
||||||
|
[[custom-builder-provider]]
|
||||||
|
=== Custom Builder Provider
|
||||||
|
|
||||||
|
MapStruct offers the possibility to override the `DefaultProvider` via the Service Provider Interface (SPI).
|
||||||
|
A nice example is to provide support for a custom builder strategy.
|
||||||
|
|
||||||
|
.Custom Builder Provider for Immutables
|
||||||
|
====
|
||||||
|
[source, java, linenums]
|
||||||
|
[subs="verbatim,attributes"]
|
||||||
|
----
|
||||||
|
include::{immutables-builder-test}/extras/src/main/java/org/mapstruct/itest/immutables/extras/ImmutablesBuilderProvider.java[tag=documentation]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.itest.immutables.extras;
|
package org.mapstruct.itest.immutables.extras;
|
||||||
|
|
||||||
|
// tag::documentation[]
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
@ -32,9 +34,12 @@ import org.mapstruct.ap.spi.BuilderInfo;
|
|||||||
import org.mapstruct.ap.spi.DefaultBuilderProvider;
|
import org.mapstruct.ap.spi.DefaultBuilderProvider;
|
||||||
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
|
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
|
||||||
|
|
||||||
|
// end::documentation[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Filip Hrisafov
|
* @author Filip Hrisafov
|
||||||
*/
|
*/
|
||||||
|
// tag::documentation[]
|
||||||
public class ImmutablesBuilderProvider extends DefaultBuilderProvider {
|
public class ImmutablesBuilderProvider extends DefaultBuilderProvider {
|
||||||
|
|
||||||
private static final Pattern JAVA_JAVAX_PACKAGE = Pattern.compile( "^javax?\\..*" );
|
private static final Pattern JAVA_JAVAX_PACKAGE = Pattern.compile( "^javax?\\..*" );
|
||||||
@ -70,6 +75,7 @@ public class ImmutablesBuilderProvider extends DefaultBuilderProvider {
|
|||||||
return super.findBuilderInfo( immutableElement, elements, types );
|
return super.findBuilderInfo( immutableElement, elements, types );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Immutables processor has not run yet. Trigger a postpone to the next round for MapStruct
|
||||||
throw new TypeHierarchyErroneousException( typeElement );
|
throw new TypeHierarchyErroneousException( typeElement );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,3 +101,4 @@ public class ImmutablesBuilderProvider extends DefaultBuilderProvider {
|
|||||||
return elements.getTypeElement( builderQualifiedName );
|
return elements.getTypeElement( builderQualifiedName );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// end::documentation[]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user