From 160bdb2e86367cdbaffae49e16378d60ce0f16c3 Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Sun, 22 Jun 2014 12:22:18 +0200 Subject: [PATCH] #207 JavaDoc improvements; Joining singularization methods --- .../mapstruct/CollectionMappingStrategy.java | 40 ++++++++++------ .../src/main/java/org/mapstruct/Mapper.java | 10 ++-- .../main/java/org/mapstruct/MapperConfig.java | 7 +-- .../org/mapstruct/ap/model/common/Type.java | 24 ++++------ .../ap/processor/MapperCreationProcessor.java | 10 ++-- .../org/mapstruct/ap/util/Executables.java | 19 +------- .../org/mapstruct/ap/util/MapperConfig.java | 15 +++--- .../java/org/mapstruct/ap/util/Nouns.java | 48 ++++++++----------- .../test/collection/adder/CatException.java | 5 +- .../test/collection/adder/DogException.java | 5 +- .../collection/adder/target/IndoorPet.java | 3 -- 11 files changed, 86 insertions(+), 100 deletions(-) diff --git a/core-common/src/main/java/org/mapstruct/CollectionMappingStrategy.java b/core-common/src/main/java/org/mapstruct/CollectionMappingStrategy.java index 8ec484cde..9903406cb 100644 --- a/core-common/src/main/java/org/mapstruct/CollectionMappingStrategy.java +++ b/core-common/src/main/java/org/mapstruct/CollectionMappingStrategy.java @@ -19,34 +19,44 @@ package org.mapstruct; /** - * Strategy for mapping of collections. + * Strategy for propagating the value of collection-typed properties from source to target. + * * @author Sjaak Derksen */ public enum CollectionMappingStrategy { /** - * MapStruct will consider setter methods as target as way to access the target. - * - * Note: If no setter is available a getter will be used under the assumption it has been initialized. + * The setter of the target property will be used to propagate the value: + * {@code orderDto.setOrderLines( order.getOrderLines )}. + *

+ * If no setter is available but a getter method, this will be used, under the assumption it has been initialized: + * {@code orderDto.getOrderLines().addAll( order.getOrderLines )}. */ - SETTER_ONLY, + ACCESSOR_ONLY, + /** - * MapStruct will consider setter methods as preferred way to access the target. - * - * If no setter is available, MapStruct will first look for an adder method before resorting to a getter. + * If present, the setter of the target property will be used to propagate the value: + * {@code orderDto.setOrderLines( order.getOrderLines )}. + *

+ * If no setter but and adder method is present, that adder will be invoked for each element of the source + * collection: {@code order.addOrderLine( orderLine() )}. + *

+ * If neither a setter nor an adder method but a getter for the target property is present, that getter will be + * used, assuming it returns an initialized collection: If no setter is available, MapStruct will first look for an + * adder method before resorting to a getter. */ SETTER_PREFERRED, + /** - * MapStruct will consider adder methods as preferred way to access the target. - * - * If no adder is available, MapStruct will first look for a setter method before resorting to a getter. + * Identical to {@link #SETTER_PREFERRED}, only that adder methods will be preferred over setter methods, if both + * are present for a given collection-typed property. */ ADDER_PREFERRED, + /** - * The default option is: {@link CollectionMappingStrategy#SETTER_ONLY}. - * - * The default options forces deliberate setting in {@link Mapper#collectionMappingStrategy() }, in order - * to override a setting in {@link MapperConfig#collectionMappingStrategy() } + * If given via {@link Mapper#collectionMappingStrategy()}, causes the setting specified via + * {@link MapperConfig#collectionMappingStrategy()} to be applied, if present. Otherwise causes + * {@link #ACCESSOR_ONLY} to be applied. */ DEFAULT; } diff --git a/core-common/src/main/java/org/mapstruct/Mapper.java b/core-common/src/main/java/org/mapstruct/Mapper.java index b1d164fd1..f6c7b503e 100644 --- a/core-common/src/main/java/org/mapstruct/Mapper.java +++ b/core-common/src/main/java/org/mapstruct/Mapper.java @@ -84,10 +84,14 @@ public @interface Mapper { Class config() default void.class; /** - * When a the target is a collection, look for a suitable adder. If the property is defined as plural, (so - * getItems(), the adder will assumed to be the singular form: addItem() + * The strategy to be applied when propagating the value of collection-typed properties. By default, only JavaBeans + * accessor methods (setters or getters) will be used, but it is also possible to invoke a corresponding adder + * method for each element of the source collection (e.g. {@code orderDto.addOrderLine()}). + *

+ * Any setting given for this attribute will take precedence over {@link MapperConfig#collectionMappingStrategy()}, + * if present. * - * @return true if the adder should be used. + * @return The strategy applied when propagating the value of collection-typed properties. */ CollectionMappingStrategy collectionMappingStrategy() default CollectionMappingStrategy.DEFAULT; diff --git a/core-common/src/main/java/org/mapstruct/MapperConfig.java b/core-common/src/main/java/org/mapstruct/MapperConfig.java index 98a413a58..a84f52cdc 100644 --- a/core-common/src/main/java/org/mapstruct/MapperConfig.java +++ b/core-common/src/main/java/org/mapstruct/MapperConfig.java @@ -74,10 +74,11 @@ public @interface MapperConfig { String componentModel() default "default"; /** - * When a the target is a collection, look for a suitable adder. If the property is defined as plural, (so - * getItems(), the adder will assumed to be the singular form: addItem() + * The strategy to be applied when propagating the value of collection-typed properties. By default, only JavaBeans + * accessor methods (setters or getters) will be used, but it is also possible to invoke a corresponding adder + * method for each element of the source collection (e.g. {@code orderDto.addOrderLine()}). * - * @return true if the adder should be used. + * @return The strategy applied when propagating the value of collection-typed properties. */ CollectionMappingStrategy collectionMappingStrategy() default CollectionMappingStrategy.DEFAULT; } diff --git a/processor/src/main/java/org/mapstruct/ap/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/model/common/Type.java index 32ed1060c..9bce2eac3 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/common/Type.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; + import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; @@ -35,6 +36,7 @@ import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; + import org.mapstruct.ap.util.Executables; import org.mapstruct.ap.util.Filters; import org.mapstruct.ap.util.Nouns; @@ -280,13 +282,13 @@ public class Type extends ModelElement implements Comparable { * Tries to find an addMethod in this type for given collection property in this type. * * Matching occurs on: - *

+ * * * @param collectionProperty property type (assumed collection) to find the adder method for * @param pluralPropertyName the property name (assumed plural) @@ -321,17 +323,9 @@ public class Type extends ModelElement implements Comparable { return candidates.get( 0 ); } else { - // try to match according human rules for (ExecutableElement candidate : candidates) { - String adderName = Executables.getElementNameForAdder( candidate ); - if (adderName.equals( Nouns.singularizeHuman( pluralPropertyName ) ) ) { - return candidate; - } - } - // try to match according dali rules - for (ExecutableElement candidate : candidates) { - String adderName = Executables.getElementNameForAdder( candidate ); - if (adderName.equals( Nouns.singularizeDali( pluralPropertyName ) ) ) { + String elementName = Executables.getElementNameForAdder( candidate ); + if (elementName.equals( Nouns.singularize( pluralPropertyName ) ) ) { return candidate; } } diff --git a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java index ec846c13e..4f59720e4 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java @@ -498,23 +498,23 @@ public class MapperCreationProcessor implements ModelElementProcessor getChildren()} , then the adder name is supposedly named: {@code addChild(Child v)}, - * element name = 'Child' - * - * getter = {@code List getBikes()} , then the adder name is supposedly named: {@code addBike(Bike v)}, - * element name = 'Bike' - * - * getter = {@code List getGeese()} , then the adder name is supposedly named: {@code addGoose(Goose v)}, - * element name = 'Goose' - * - * @param adderMethod - * - * @return the element name + * Returns the 'element name' to which an adder method applies. If. e.g. an adder method is named + * {@code addChild(Child v)}, the element name would be 'Child'. */ public static String getElementNameForAdder(ExecutableElement adderMethod) { if ( isAdderMethod( adderMethod ) ) { diff --git a/processor/src/main/java/org/mapstruct/ap/util/MapperConfig.java b/processor/src/main/java/org/mapstruct/ap/util/MapperConfig.java index 0ead503c0..414bcef22 100644 --- a/processor/src/main/java/org/mapstruct/ap/util/MapperConfig.java +++ b/processor/src/main/java/org/mapstruct/ap/util/MapperConfig.java @@ -18,22 +18,23 @@ */ package org.mapstruct.ap.util; +import static org.mapstruct.CollectionMappingStrategy.valueOf; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; + import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; + import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.ap.option.ReportingPolicy; import org.mapstruct.ap.prism.MapperConfigPrism; import org.mapstruct.ap.prism.MapperPrism; -import static org.mapstruct.CollectionMappingStrategy.DEFAULT; -import static org.mapstruct.CollectionMappingStrategy.SETTER_ONLY; -import static org.mapstruct.CollectionMappingStrategy.valueOf; /** * Class decorating the {@link MapperPrism} with the 'default' configuration. * @@ -95,20 +96,20 @@ public class MapperConfig { public CollectionMappingStrategy getCollectionMappingStrategy() { CollectionMappingStrategy mapperPolicy = valueOf( mapperPrism.collectionMappingStrategy() ); - if ( !mapperPolicy.equals( DEFAULT ) ) { + if ( !mapperPolicy.equals( CollectionMappingStrategy.DEFAULT ) ) { // it is not the default mapper configuration, so return the mapper configured value return mapperPolicy; } else if ( mapperConfigPrism != null ) { // try the config mapper configuration CollectionMappingStrategy configPolicy = valueOf( mapperConfigPrism.collectionMappingStrategy() ); - if ( !configPolicy.equals( DEFAULT ) ) { + if ( !configPolicy.equals( CollectionMappingStrategy.DEFAULT ) ) { // its not the default configuration, so return the mapper config configured value return configPolicy; } } - // when nothing specified, return SETTER_ONLY (default option) - return SETTER_ONLY; + // when nothing specified, return ACCESSOR_ONLY (default option) + return CollectionMappingStrategy.ACCESSOR_ONLY; } public String componentModel() { diff --git a/processor/src/main/java/org/mapstruct/ap/util/Nouns.java b/processor/src/main/java/org/mapstruct/ap/util/Nouns.java index 5fceb9fe6..e68322eab 100644 --- a/processor/src/main/java/org/mapstruct/ap/util/Nouns.java +++ b/processor/src/main/java/org/mapstruct/ap/util/Nouns.java @@ -32,7 +32,7 @@ public class Nouns { private Nouns() { } - private static final List SINGULAR_HUMAN_RULES = Arrays.asList( + private static final List SINGULAR_RULES = Arrays.asList( new ReplaceRule( "(equipment|information|rice|money|species|series|fish|sheep)$", "$1" ), new ReplaceRule( "(f)eet$", "$1oot" ), new ReplaceRule( "(t)eeth$", "$1ooth" ), @@ -74,48 +74,36 @@ public class Nouns { new ReplaceRule( "s$", "" ) ); + /** + * Replacement rules based on the routine applied by the Dali + * project. Applied as a fallback if the other rules didn't yield a match. + */ private static final List SINGULAR_DALI_RULES = Arrays.asList( new ReplaceRule( "(us|ss)$", "$1" ), new ReplaceRule( "(ch|s)es$", "$1" ), - new ReplaceRule( "([^aeiouy])ies$", "$1y" ), - new ReplaceRule( "s$", "" ) + new ReplaceRule( "([^aeiouy])ies$", "$1y" ) ); - /** - * Converts given in into a singular form as much as possible according human form. This will always be a best - * attempt. The rules are language context dependent and - * - * @param in String to singularize - * @return singularize form of in + /** + * Converts given pluralized noun into the singular form. If no singular form could be determined, the given word + * itself is returned. */ - public static String singularizeHuman( String in ) { - for ( ReplaceRule replaceRule : SINGULAR_HUMAN_RULES ) { - String match = replaceRule.apply( in ); + public static String singularize( String plural ) { + for ( ReplaceRule replaceRule : SINGULAR_RULES ) { + String match = replaceRule.apply( plural ); if ( match != null ) { return match; } } - return in; - } - /** - * Converts given in into a singular form according dali - * @see rules - * - * These rules are assumed to be incomplete and give wrong conversions from plural to singular that should - * be taken into account as well. - * - * @param in String to singularize - * @return singularize form of in - */ - public static String singularizeDali( String in ) { for ( ReplaceRule replaceRule : SINGULAR_DALI_RULES ) { - String match = replaceRule.apply( in ); + String match = replaceRule.apply( plural ); if ( match != null ) { return match; } } - return in; + + return plural; } private static final class ReplaceRule { @@ -124,7 +112,7 @@ public class Nouns { private final String replacement; private final Pattern pattern; - private ReplaceRule( String regexp, String replacement ) { + private ReplaceRule( String regexp, String replacement ) { this.regexp = regexp; this.replacement = replacement; this.pattern = Pattern.compile( this.regexp, Pattern.CASE_INSENSITIVE ); @@ -139,5 +127,9 @@ public class Nouns { return result; } + @Override + public String toString() { + return "'" + regexp + "' -> '" + replacement; + } } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/adder/CatException.java b/processor/src/test/java/org/mapstruct/ap/test/collection/adder/CatException.java index fb84834ba..a6174a6cf 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/adder/CatException.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/adder/CatException.java @@ -19,15 +19,16 @@ package org.mapstruct.ap.test.collection.adder; /** - * * @author Sjaak Derksen */ public class CatException extends Exception { + private static final long serialVersionUID = 1L; + public CatException() { } - public CatException( String msg ) { + public CatException(String msg) { super( msg ); } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/adder/DogException.java b/processor/src/test/java/org/mapstruct/ap/test/collection/adder/DogException.java index 22c068cf6..a501c6008 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/adder/DogException.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/adder/DogException.java @@ -19,15 +19,16 @@ package org.mapstruct.ap.test.collection.adder; /** - * * @author Sjaak Derksen */ public class DogException extends Exception { + private static final long serialVersionUID = 1L; + public DogException() { } - public DogException( String msg ) { + public DogException(String msg) { super( msg ); } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/adder/target/IndoorPet.java b/processor/src/test/java/org/mapstruct/ap/test/collection/adder/target/IndoorPet.java index cde9b2ad7..0cd413a33 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/adder/target/IndoorPet.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/adder/target/IndoorPet.java @@ -37,7 +37,4 @@ public class IndoorPet extends Pet { public void setValue( Long value ) { this.value = value; } - - - }