mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
200 lines
6.2 KiB
Plaintext
200 lines
6.2 KiB
Plaintext
[[using-spi]]
|
|
== Using the MapStruct SPI
|
|
=== Custom Accessor Naming Strategy
|
|
|
|
MapStruct offers the possibility to override the `AccessorNamingStrategy` via the Service Provide Interface (SPI). A nice example is the use of the fluent API on the source object `GolfPlayer` and `GolfPlayerDto` below.
|
|
|
|
.Source object GolfPlayer with fluent API.
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
public class GolfPlayer {
|
|
|
|
private double handicap;
|
|
private String name;
|
|
|
|
public double handicap() {
|
|
return handicap;
|
|
}
|
|
|
|
public GolfPlayer withHandicap(double handicap) {
|
|
this.handicap = handicap;
|
|
return this;
|
|
}
|
|
|
|
public String name() {
|
|
return name;
|
|
}
|
|
|
|
public GolfPlayer withName(String name) {
|
|
this.name = name;
|
|
return this;
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
.Source object GolfPlayerDto with fluent API.
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
public class GolfPlayerDto {
|
|
|
|
private double handicap;
|
|
private String name;
|
|
|
|
public double handicap() {
|
|
return handicap;
|
|
}
|
|
|
|
public GolfPlayerDto withHandicap(double handicap) {
|
|
this.handicap = handicap;
|
|
return this;
|
|
}
|
|
|
|
public String name() {
|
|
return name;
|
|
}
|
|
|
|
public GolfPlayerDto withName(String name) {
|
|
this.name = name;
|
|
return this
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
We want `GolfPlayer` to be mapped to a target object `GolfPlayerDto` similar like we 'always' do this:
|
|
|
|
.Source object with fluent API.
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
@Mapper
|
|
public interface GolfPlayerMapper {
|
|
|
|
GolfPlayerMapper INSTANCE = Mappers.getMapper( GolfPlayerMapper.class );
|
|
|
|
GolfPlayerDto toDto(GolfPlayer player);
|
|
|
|
GolfPlayer toPlayer(GolfPlayerDto player);
|
|
|
|
}
|
|
----
|
|
====
|
|
|
|
This can be achieved with implementing the SPI `org.mapstruct.ap.spi.AccessorNamingStrategy` as in the following example. Here's an implemented `org.mapstruct.ap.spi.AccessorNamingStrategy`:
|
|
|
|
.CustomAccessorNamingStrategy
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
/**
|
|
* A custom {@link AccessorNamingStrategy} recognizing getters in the form of {@code property()} and setters in the
|
|
* form of {@code withProperty(value)}.
|
|
*/
|
|
public class CustomAccessorNamingStrategy extends DefaultAccessorNamingStrategy {
|
|
|
|
@Override
|
|
public boolean isGetterMethod(ExecutableElement method) {
|
|
String methodName = method.getSimpleName().toString();
|
|
return !methodName.startsWith( "with" ) && method.getReturnType().getKind() != TypeKind.VOID;
|
|
}
|
|
|
|
@Override
|
|
public boolean isSetterMethod(ExecutableElement method) {
|
|
String methodName = method.getSimpleName().toString();
|
|
return methodName.startsWith( "with" ) && methodName.length() > 4;
|
|
}
|
|
|
|
@Override
|
|
public String getPropertyName(ExecutableElement getterOrSetterMethod) {
|
|
String methodName = getterOrSetterMethod.getSimpleName().toString();
|
|
return IntrospectorUtils.decapitalize( methodName.startsWith( "with" ) ? methodName.substring( 4 ) : methodName );
|
|
}
|
|
}
|
|
----
|
|
====
|
|
The `CustomAccessorNamingStrategy` makes use of the `DefaultAccessorNamingStrategy` (also available in mapstruct-processor) and relies on that class to leave most of the default behaviour unchanged.
|
|
|
|
To use a custom SPI implementation, it must be located in a separate JAR file together with the file `META-INF/services/org.mapstruct.ap.spi.AccessorNamingStrategy` with the fully qualified name of your custom implementation as content (e.g. `org.mapstruct.example.CustomAccessorNamingStrategy`). 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).
|
|
|
|
[TIP]
|
|
Fore more details: The example above is present in our examples repository (https://github.com/mapstruct/mapstruct-examples).
|
|
|
|
[mapping-exclusion-provider]
|
|
=== Mapping Exclusion Provider
|
|
|
|
MapStruct offers the possibility to override the `MappingExclusionProvider` via the Service Provider Interface (SPI).
|
|
A nice example is to not allow MapStruct to create an automatic sub-mapping for a certain type,
|
|
i.e. MapStruct will not try to generate an automatic sub-mapping method for an excluded type.
|
|
|
|
[NOTE]
|
|
====
|
|
The `DefaultMappingExclusionProvider` will exclude all types under the `java` or `javax` packages.
|
|
This means that MapStruct will not try to generate an automatic sub-mapping method between some custom type and some type declared in the Java class library.
|
|
====
|
|
|
|
.Source object
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
include::{processor-ap-test}/nestedbeans/exclusions/custom/Source.java[tag=documentation]
|
|
----
|
|
====
|
|
|
|
.Target object
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
include::{processor-ap-test}/nestedbeans/exclusions/custom/Target.java[tag=documentation]
|
|
----
|
|
====
|
|
|
|
.Mapper definition
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
include::{processor-ap-test}/nestedbeans/exclusions/custom/ErroneousCustomExclusionMapper.java[tag=documentation]
|
|
----
|
|
====
|
|
|
|
We want to exclude the `NestedTarget` from the automatic sub-mapping method generation.
|
|
|
|
.CustomMappingExclusionProvider
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
include::{processor-ap-test}/nestedbeans/exclusions/custom/CustomMappingExclusionProvider.java[tag=documentation]
|
|
----
|
|
====
|
|
|
|
To use a custom SPI implementation, it must be located in a separate JAR file
|
|
together with the file `META-INF/services/org.mapstruct.ap.spi.MappingExclusionProvider` with the fully qualified name of your custom implementation as content
|
|
(e.g. `org.mapstruct.example.CustomMappingExclusionProvider`).
|
|
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).
|
|
|
|
|
|
[[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 which disables Builder support
|
|
====
|
|
[source, java, linenums]
|
|
[subs="verbatim,attributes"]
|
|
----
|
|
include::{processor-ap-main}/spi/NoOpBuilderProvider.java[tag=documentation]
|
|
----
|
|
==== |