[[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]
----
====