mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
This commit is contained in:
parent
735a5bef6a
commit
72e6b1feb5
@ -218,6 +218,10 @@ public @interface Mapping {
|
|||||||
* </li>
|
* </li>
|
||||||
* </ol>
|
* </ol>
|
||||||
* <p>
|
* <p>
|
||||||
|
* You can use {@link #qualifiedBy()} or {@link #qualifiedByName()} to force the use of a conversion method
|
||||||
|
* even when one would not apply. (e.g. {@code String} to {@code String})
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
* This attribute can not be used together with {@link #source()}, {@link #defaultValue()},
|
* This attribute can not be used together with {@link #source()}, {@link #defaultValue()},
|
||||||
* {@link #defaultExpression()} or {@link #expression()}.
|
* {@link #defaultExpression()} or {@link #expression()}.
|
||||||
*
|
*
|
||||||
@ -295,6 +299,8 @@ public @interface Mapping {
|
|||||||
* A qualifier can be specified to aid the selection process of a suitable mapper. This is useful in case multiple
|
* A qualifier can be specified to aid the selection process of a suitable mapper. This is useful in case multiple
|
||||||
* mapping methods (hand written or generated) qualify and thus would result in an 'Ambiguous mapping methods found'
|
* mapping methods (hand written or generated) qualify and thus would result in an 'Ambiguous mapping methods found'
|
||||||
* error. A qualifier is a custom annotation and can be placed on a hand written mapper class or a method.
|
* error. A qualifier is a custom annotation and can be placed on a hand written mapper class or a method.
|
||||||
|
* <p>
|
||||||
|
* Note that {@link #defaultValue()} usage will also be converted using this qualifier.
|
||||||
*
|
*
|
||||||
* @return the qualifiers
|
* @return the qualifiers
|
||||||
* @see Qualifier
|
* @see Qualifier
|
||||||
@ -309,6 +315,8 @@ public @interface Mapping {
|
|||||||
* Note that annotation-based qualifiers are generally preferable as they allow more easily to find references and
|
* Note that annotation-based qualifiers are generally preferable as they allow more easily to find references and
|
||||||
* are safe for refactorings, but name-based qualifiers can be a less verbose alternative when requiring a large
|
* are safe for refactorings, but name-based qualifiers can be a less verbose alternative when requiring a large
|
||||||
* number of qualifiers as no custom annotation types are needed.
|
* number of qualifiers as no custom annotation types are needed.
|
||||||
|
* <p>
|
||||||
|
* Note that {@link #defaultValue()} usage will also be converted using this qualifier.
|
||||||
*
|
*
|
||||||
* @return One or more qualifier name(s)
|
* @return One or more qualifier name(s)
|
||||||
* @see #qualifiedBy()
|
* @see #qualifiedBy()
|
||||||
|
@ -703,3 +703,73 @@ public interface MovieMapper {
|
|||||||
====
|
====
|
||||||
Although the used mechanism is the same, the user has to be a bit more careful. Refactoring the name of a defined qualifier in an IDE will neatly refactor all other occurrences as well. This is obviously not the case for changing a name.
|
Although the used mechanism is the same, the user has to be a bit more careful. Refactoring the name of a defined qualifier in an IDE will neatly refactor all other occurrences as well. This is obviously not the case for changing a name.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
=== Combining qualifiers with defaults
|
||||||
|
Please note that the `Mapping#defaultValue` is in essence a `String`, which needs to be converted to the `Mapping#target`. Providing a `Mapping#qualifiedByName` or `Mapping#qualifiedBy` will force MapStruct to use that method. If you want different behavior for the `Mapping#defaultValue`, then please provide an appropriate mapping method. This mapping method needs to transforms a `String` into the desired type of `Mapping#target` and also be annotated so that it can be found by the `Mapping#qualifiedByName` or `Mapping#qualifiedBy`.
|
||||||
|
|
||||||
|
.Mapper using defaultValue
|
||||||
|
====
|
||||||
|
[source, java, linenums]
|
||||||
|
[subs="verbatim,attributes"]
|
||||||
|
----
|
||||||
|
@Mapper
|
||||||
|
public interface MovieMapper {
|
||||||
|
|
||||||
|
@Mapping( target = "category", qualifiedByName = "CategoryToString", defaultValue = "DEFAULT" )
|
||||||
|
GermanRelease toGerman( OriginalRelease movies );
|
||||||
|
|
||||||
|
@Named("CategoryToString")
|
||||||
|
default String defaultValueForQualifier(Category cat) {
|
||||||
|
// some mapping logic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
In the above example in case that category is null, the method `CategoryToString( Enum.valueOf( Category.class, "DEFAULT" ) )` will be called and the result will be set to the category field.
|
||||||
|
|
||||||
|
.Mapper using defaultValue and default method.
|
||||||
|
====
|
||||||
|
[source, java, linenums]
|
||||||
|
[subs="verbatim,attributes"]
|
||||||
|
----
|
||||||
|
@Mapper
|
||||||
|
public interface MovieMapper {
|
||||||
|
|
||||||
|
@Mapping( target = "category", qualifiedByName = "CategoryToString", defaultValue = "Unknown" )
|
||||||
|
GermanRelease toGerman( OriginalRelease movies );
|
||||||
|
|
||||||
|
@Named("CategoryToString")
|
||||||
|
default String defaultValueForQualifier(Category cat) {
|
||||||
|
// some mapping logic
|
||||||
|
}
|
||||||
|
|
||||||
|
@Named("CategoryToString")
|
||||||
|
default String defaultValueForQualifier(String value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
In the above example in case that category is null, the method `defaultValueForQualifier( "Unknown" )` will be called and the result will be set to the category field.
|
||||||
|
|
||||||
|
If the above mentioned methods do not work there is the option to use `defaultExpression` to set the default value.
|
||||||
|
|
||||||
|
.Mapper using defaultExpression
|
||||||
|
====
|
||||||
|
[source, java, linenums]
|
||||||
|
[subs="verbatim,attributes"]
|
||||||
|
----
|
||||||
|
@Mapper
|
||||||
|
public interface MovieMapper {
|
||||||
|
|
||||||
|
@Mapping( target = "category", qualifiedByName = "CategoryToString", defaultExpression = "java(\"Unknown\")" )
|
||||||
|
GermanRelease toGerman( OriginalRelease movies );
|
||||||
|
|
||||||
|
@Named("CategoryToString")
|
||||||
|
default String defaultValueForQualifier(Category cat) {
|
||||||
|
// some mapping logic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.selection.qualifier.defaults;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.Named;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface DefaultExpressionUsageMapper {
|
||||||
|
@Mapping( source = "folder.ancestor.id", target = "parent",
|
||||||
|
defaultExpression = "java(\"#\")", qualifiedByName = "uuidToString" )
|
||||||
|
DirectoryNode convert(Folder folder);
|
||||||
|
|
||||||
|
@Named( "uuidToString" )
|
||||||
|
default String uuidToString(UUID id) {
|
||||||
|
return id.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.selection.qualifier.defaults;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.Named;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface DefaultValueUsageMapper {
|
||||||
|
@Mapping( source = "folder.ancestor.id", target = "parent",
|
||||||
|
defaultValue = "00000000-0000-4000-0000-000000000000", qualifiedByName = "uuidToString" )
|
||||||
|
DirectoryNode convert(Folder folder);
|
||||||
|
|
||||||
|
@Named( "uuidToString" )
|
||||||
|
default String uuidToString(UUID id) {
|
||||||
|
return id.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.selection.qualifier.defaults;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
class DirectoryNode {
|
||||||
|
private String parent;
|
||||||
|
|
||||||
|
public void setParent(String parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.selection.qualifier.defaults;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.Named;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface FaultyDefaultValueUsageMapper {
|
||||||
|
@Mapping( source = "folder.ancestor.id", target = "parent", defaultValue = "#", qualifiedByName = "uuidToString" )
|
||||||
|
DirectoryNode convert(Folder folder);
|
||||||
|
|
||||||
|
@Named( "uuidToString" )
|
||||||
|
default String uuidToString(UUID id) {
|
||||||
|
return id.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.selection.qualifier.defaults;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
class Folder {
|
||||||
|
private UUID id;
|
||||||
|
private Folder ancestor;
|
||||||
|
|
||||||
|
Folder(UUID id, Folder ancestor) {
|
||||||
|
this.id = id;
|
||||||
|
this.ancestor = ancestor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Folder getAncestor() {
|
||||||
|
return ancestor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright MapStruct Authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.selection.qualifier.defaults;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ben Zegveld
|
||||||
|
*/
|
||||||
|
@WithClasses( { DirectoryNode.class, Folder.class } )
|
||||||
|
public class QualifierWithDefaultsTest {
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
@WithClasses( FaultyDefaultValueUsageMapper.class )
|
||||||
|
void defaultValueHasInvalidValue() {
|
||||||
|
Folder rootFolder = new Folder( UUID.randomUUID(), null );
|
||||||
|
FaultyDefaultValueUsageMapper faultyMapper = Mappers.getMapper( FaultyDefaultValueUsageMapper.class );
|
||||||
|
|
||||||
|
Assertions
|
||||||
|
.assertThatThrownBy( () -> faultyMapper.convert( rootFolder ) )
|
||||||
|
.isInstanceOf( IllegalArgumentException.class ); // UUID.valueOf should throw this.
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
@WithClasses( DefaultValueUsageMapper.class )
|
||||||
|
void defaultValuehasUsableValue() {
|
||||||
|
Folder rootFolder = new Folder( UUID.randomUUID(), null );
|
||||||
|
|
||||||
|
DirectoryNode node = Mappers.getMapper( DefaultValueUsageMapper.class ).convert( rootFolder );
|
||||||
|
|
||||||
|
Assertions.assertThat( node.getParent() ).isEqualTo( "00000000-0000-4000-0000-000000000000" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProcessorTest
|
||||||
|
@WithClasses( DefaultExpressionUsageMapper.class )
|
||||||
|
void defaultExpressionDoesNotGetConverted() {
|
||||||
|
Folder rootFolder = new Folder( UUID.randomUUID(), null );
|
||||||
|
|
||||||
|
DirectoryNode node = Mappers.getMapper( DefaultExpressionUsageMapper.class ).convert( rootFolder );
|
||||||
|
|
||||||
|
Assertions.assertThat( node.getParent() ).isEqualTo( "#" );
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user