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>
|
||||
* </ol>
|
||||
* <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()},
|
||||
* {@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
|
||||
* 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.
|
||||
* <p>
|
||||
* Note that {@link #defaultValue()} usage will also be converted using this qualifier.
|
||||
*
|
||||
* @return the qualifiers
|
||||
* @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
|
||||
* 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.
|
||||
* <p>
|
||||
* Note that {@link #defaultValue()} usage will also be converted using this qualifier.
|
||||
*
|
||||
* @return One or more qualifier name(s)
|
||||
* @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.
|
||||
====
|
||||
|
||||
=== 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