From 9584a81687702b9ff3f6da05ddb0b8eab5eef626 Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Sat, 17 Oct 2009 05:33:04 +0000 Subject: [PATCH] conditional mapping --- .../support/DefaultMappingTargetFactory.java | 10 ++ .../mapping/support/FieldToFieldMapping.java | 8 +- .../support/FieldToMultiFieldMapping.java | 10 +- .../mapping/support/MapperBuilder.java | 84 +++++++++++++++-- .../support/MappingConversionService.java | 2 +- .../mapping/support/MappingConverter.java | 15 +-- .../support/MultiFieldToFieldMapping.java | 9 +- .../mapping/support/SpelMapper.java | 79 ++++++---------- .../mapping/support/SpelMapperBuilder.java | 50 ++++++++-- .../mapping/support/SpelMappingContext.java | 10 +- .../mapping/support/MappingTests.java | 94 +++++++++++++++++++ 11 files changed, 291 insertions(+), 80 deletions(-) diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/DefaultMappingTargetFactory.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/DefaultMappingTargetFactory.java index fd704c77ea8..95fb6bdd304 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/DefaultMappingTargetFactory.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/DefaultMappingTargetFactory.java @@ -26,6 +26,12 @@ import org.springframework.util.ClassUtils; */ final class DefaultMappingTargetFactory implements MappingTargetFactory { + private static final DefaultMappingTargetFactory INSTANCE = new DefaultMappingTargetFactory(); + + private DefaultMappingTargetFactory() { + + } + public boolean supports(TypeDescriptor targetType) { return ClassUtils.hasConstructor(targetType.getType(), null); } @@ -34,4 +40,8 @@ final class DefaultMappingTargetFactory implements MappingTargetFactory { return BeanUtils.instantiate(targetType.getType()); } + public static MappingTargetFactory getInstance() { + return INSTANCE; + } + } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/FieldToFieldMapping.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/FieldToFieldMapping.java index 2ee6bb49dd1..f4c481376f9 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/FieldToFieldMapping.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/FieldToFieldMapping.java @@ -31,10 +31,13 @@ final class FieldToFieldMapping implements SpelMapping { @SuppressWarnings("unchecked") private final Converter converter; - public FieldToFieldMapping(Expression sourceField, Expression targetField, Converter converter) { + private final Expression condition; + + public FieldToFieldMapping(Expression sourceField, Expression targetField, Converter converter, Expression condition) { this.sourceField = sourceField; this.targetField = targetField; this.converter = converter; + this.condition = condition; } public String getSourceField() { @@ -51,6 +54,9 @@ final class FieldToFieldMapping implements SpelMapping { @SuppressWarnings("unchecked") public void map(SpelMappingContext context) { + if (!context.conditionHolds(this.condition)) { + return; + } try { Object value = context.getSourceFieldValue(this.sourceField); if (this.converter != null) { diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/FieldToMultiFieldMapping.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/FieldToMultiFieldMapping.java index 69282a9be87..522d9363b11 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/FieldToMultiFieldMapping.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/FieldToMultiFieldMapping.java @@ -28,10 +28,13 @@ final class FieldToMultiFieldMapping implements SpelMapping { @SuppressWarnings("unchecked") private final Mapper targetFieldMapper; - - public FieldToMultiFieldMapping(Expression sourceField, Mapper targetFieldMapper) { + + private final Expression condition; + + public FieldToMultiFieldMapping(Expression sourceField, Mapper targetFieldMapper, Expression condition) { this.sourceField = sourceField; this.targetFieldMapper = targetFieldMapper; + this.condition = condition; } public String getSourceField() { @@ -44,6 +47,9 @@ final class FieldToMultiFieldMapping implements SpelMapping { @SuppressWarnings("unchecked") public void map(SpelMappingContext context) { + if (!context.conditionHolds(this.condition)) { + return; + } try { Object value = context.getSourceFieldValue(this.sourceField); this.targetFieldMapper.map(value, context.getTarget()); diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/MapperBuilder.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/MapperBuilder.java index 16503ef81c4..356810c9a55 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/MapperBuilder.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/MapperBuilder.java @@ -50,7 +50,7 @@ public interface MapperBuilder { * The source and target field names will be the same value. * For example, calling addMapping("order") will register a mapping that maps between the order field on the source and the order field on the target. * This is a convenience method for calling {@link #addMapping(String, String)} with the same source and target value.. - * @param fieldExpression the field mapping expression + * @param field the field mapping expression * @return this, for configuring additional field mapping options fluently */ MapperBuilder addMapping(String field); @@ -60,7 +60,7 @@ public interface MapperBuilder { * The source and target field expressions will be the same value. * For example, calling addMapping("order") will register a mapping that maps between the order field on the source and the order field on the target. * This is a convenience method for calling {@link #addMapping(String, String, Converter)} with the same source and target value.. - * @param fieldExpression the field mapping expression + * @param field the field mapping expression * @param converter the converter that will convert the source field value before mapping the value to the target field * @return this, for configuring additional field mapping options fluently */ @@ -81,8 +81,8 @@ public interface MapperBuilder { * Register a mapping between a source field and a target field. * Use this method when the name of the source field and the name of the target field are different. * For example, calling addMapping("order", "primaryOrder") will register a mapping that maps between the order field on the source and the primaryOrder field on the target. - * @param sourceFieldExpression the source field mapping expression - * @param targetFieldExpression the target field mapping expression + * @param sourceField the source field mapping expression + * @param targetField the target field mapping expression * @return this, for configuring additional field mapping options fluently */ MapperBuilder addMapping(String sourceField, String targetField); @@ -91,8 +91,8 @@ public interface MapperBuilder { * Register a mapping between a source field and a target field that first converts the source field value using the provided Converter. * Use this method when the name of the source field and the name of the target field are different. * For example, calling addMapping("order", "primaryOrder") will register a mapping that maps between the order field on the source and the primaryOrder field on the target. - * @param sourceFieldExpression the source field mapping expression - * @param targetFieldExpression the target field mapping expression + * @param sourceField the source field mapping expression + * @param targetField the target field mapping expression * @return this, for configuring additional field mapping options fluently */ MapperBuilder addMapping(String sourceField, String targetField, Converter converter); @@ -107,6 +107,71 @@ public interface MapperBuilder { */ MapperBuilder addMapping(String[] fields, Mapper mapper); + /** + * Register a conditional mapping between a source field and a target field. + * The source and target field names will be the same value. + * @param field the field mapping expression + * @param condition the boolean expression that determines if this mapping executes + * @return this, for configuring additional field mapping options fluently + */ + MapperBuilder addConditionalMapping(String field, String condition); + + /** + * Register a condition mapping between a source field and a target field that first converts the source field value using the provided Converter. + * The source and target field expressions will be the same value. + * @param field the field mapping expression + * @param converter the converter that converts the source field value before mapping + * @param condition the boolean expression that determines if this mapping executes + * @return this, for configuring additional field mapping options fluently + */ + MapperBuilder addConditionalMapping(String field, Converter converter, String condition); + + /** + * Register a conditional mapping between a source field and multiple target fields. + * Use this method when you need to map a single source field value to multiple fields on the target. + * For example, calling addMapping("name", firstAndLastNameMapper) might register a mapping that maps the name field on the source to the firstName and lastName fields on the target. + * The target field {@link Mapper} will be passed the value of the source field for its source and the target object T for its target. + * @param field the source field expression + * @param mapper the mapper of the target fields + * @param condition the boolean expression that determines if this mapping executes + * @return this, for configuring additional field mapping options fluently + */ + MapperBuilder addConditionalMapping(String field, Mapper mapper, String condition); + + /** + * Register a conditional mapping between a source field and a target field. + * Use this method when the name of the source field and the name of the target field are different. + * For example, calling addMapping("order", "primaryOrder") will register a mapping that maps between the order field on the source and the primaryOrder field on the target. + * @param sourceField the source field mapping expression + * @param targetField the target field mapping expression + * @param condition the boolean expression that determines if this mapping executes + * @return this, for configuring additional field mapping options fluently + */ + MapperBuilder addConditionalMapping(String sourceField, String targetField, String condition); + + /** + * Register a conditional mapping between a source field and a target field that first converts the source field value using the provided Converter. + * Use this method when the name of the source field and the name of the target field are different. + * For example, calling addMapping("order", "primaryOrder") will register a mapping that maps between the order field on the source and the primaryOrder field on the target. + * @param sourceField the source field mapping expression + * @param targetField the target field mapping expression + * @param converter the converter that converts the source field value before mapping + * @param condition the boolean expression that determines if this mapping executes + * @return this, for configuring additional field mapping options fluently + */ + MapperBuilder addConditionalMapping(String sourceField, String targetField, Converter converter, String condition); + + /** + * Register a conditional mapping between multiple source fields and a single target field. + * For example, calling addMapping(dateAndTimeFieldsToDateTimeFieldMapper) might register a mapping that maps the date and time fields on the source to the dateTime field on the target. + * The provided {@link Mapper} will be passed the source object S for its source and the target object T for its target. + * @param fields the source field mapping expressions + * @param mapper the fields to field mapper + * @param condition the boolean expression that determines if this mapping executes + * @return this, for configuring additional field mapping options fluently + */ + MapperBuilder addMapping(String[] fields, Mapper mapper, String condition); + /** * Register a Mapper that will be used to map between nested source and target fields of a specific sourceType/targetType pair. * The source and target field types are determined by introspecting the parameterized types on the Mapper generic interface. @@ -130,11 +195,18 @@ public interface MapperBuilder { * Register a custom type converter to use to convert between two mapped types. * The Converter may convert between simple types, such as Strings to Dates. * Alternatively, it may convert between complex types and initiate a recursive mapping operation between two object fields. + * @return this, for configuring additional field mapping options fluently * @see Converter * @see MappingConverter */ MapperBuilder addConverter(Converter converter); + /** + * Set the source fields to exclude from mapping. + * @param fields the source fields as var args + */ + MapperBuilder setExcludedFields(String... fields); + /** * Get the Mapper produced by this builder. * Call this method after instructing the builder. diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/MappingConversionService.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/MappingConversionService.java index 76f79fcedb2..95741f58cf6 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/MappingConversionService.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/MappingConversionService.java @@ -23,7 +23,7 @@ final class MappingConversionService extends DefaultConversionService { @Override protected GenericConverter getDefaultConverter(TypeDescriptor sourceType, TypeDescriptor targetType) { - return new MappingConverter(new SpelMapper()); + return new MappingConverter(new SpelMapper(), null); } } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/MappingConverter.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/MappingConverter.java index d6eae0c4e3c..c553fc8ac17 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/MappingConverter.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/MappingConverter.java @@ -33,15 +33,6 @@ final class MappingConverter implements GenericConverter { private final MappingTargetFactory mappingTargetFactory; - /** - * Creates a new Converter that delegates to the mapper to complete the type conversion process. - * Uses a {@link DefaultMappingTargetFactory} to create the target object to map and return. - * @param mapper the mapper - */ - public MappingConverter(Mapper mapper) { - this(mapper, new DefaultMappingTargetFactory()); - } - /** * Creates a new Converter that delegates to the mapper to complete the type conversion process. * Uses the specified MappingTargetFactory to create the target object to map and return. @@ -49,7 +40,11 @@ final class MappingConverter implements GenericConverter { */ public MappingConverter(Mapper mapper, MappingTargetFactory mappingTargetFactory) { this.mapper = mapper; - this.mappingTargetFactory = mappingTargetFactory; + if (mappingTargetFactory != null) { + this.mappingTargetFactory = mappingTargetFactory; + } else { + this.mappingTargetFactory = DefaultMappingTargetFactory.getInstance(); + } } public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/MultiFieldToFieldMapping.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/MultiFieldToFieldMapping.java index 136430f126a..b6847c08ad9 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/MultiFieldToFieldMapping.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/MultiFieldToFieldMapping.java @@ -16,6 +16,7 @@ package org.springframework.mapping.support; import org.springframework.core.style.StylerUtils; +import org.springframework.expression.Expression; import org.springframework.mapping.Mapper; /** @@ -29,9 +30,12 @@ final class MultiFieldToFieldMapping implements SpelMapping { @SuppressWarnings("unchecked") private final Mapper multiFieldMapper; - public MultiFieldToFieldMapping(String[] fields, Mapper multiFieldMapper) { + private Expression condition; + + public MultiFieldToFieldMapping(String[] fields, Mapper multiFieldMapper, Expression condition) { this.fields = fields; this.multiFieldMapper = multiFieldMapper; + this.condition = condition; } public String[] getSourceFields() { @@ -49,6 +53,9 @@ final class MultiFieldToFieldMapping implements SpelMapping { @SuppressWarnings("unchecked") public void map(SpelMappingContext context) { + if (!context.conditionHolds(this.condition)) { + return; + } try { this.multiFieldMapper.map(context.getSource(), context.getTarget()); } catch (Exception e) { diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMapper.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMapper.java index 8eddad39ca2..1c1d5813a7b 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMapper.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMapper.java @@ -71,64 +71,32 @@ final class SpelMapper implements Mapper { this.mappableTypeFactory = mappableTypeFactory; } - public void addMapping(String sourceFieldExpression, String targetFieldExpression, Converter converter) { + public void setExcludedFields(String[] fields) { + // TODO + } + + public void addMapping(String sourceFieldExpression, String targetFieldExpression, Converter converter, + String condition) { Expression sourceField = parseSourceField(sourceFieldExpression); Expression targetField = parseTargetField(targetFieldExpression); - FieldToFieldMapping mapping = new FieldToFieldMapping(sourceField, targetField, converter); + FieldToFieldMapping mapping = new FieldToFieldMapping(sourceField, targetField, converter, + parseCondition(condition)); this.mappings.add(mapping); } - public void addMapping(String field, Mapper mapper) { - this.mappings.add(new FieldToMultiFieldMapping(parseSourceField(field), mapper)); + public void addMapping(String field, Mapper mapper, String condition) { + this.mappings.add(new FieldToMultiFieldMapping(parseSourceField(field), mapper, parseCondition(condition))); } - public void addMapping(String[] fields, Mapper mapper) { - this.mappings.add(new MultiFieldToFieldMapping(fields, mapper)); + public void addMapping(String[] fields, Mapper mapper, String condition) { + this.mappings.add(new MultiFieldToFieldMapping(fields, mapper, parseCondition(condition))); } - /** - * Adds a Mapper that will map the fields of a nested sourceType/targetType pair. - * The source and target field types are determined by introspecting the parameterized types on the implementation's Mapper generic interface. - * The target instance that is mapped is constructed by a {@link DefaultMappingTargetFactory}. - * This method is a convenience method for {@link #addNestedMapper(Class, Class, Mapper)}. - * @param nestedMapper the nested mapper - */ - public void addNestedMapper(Mapper nestedMapper) { - Class[] typeInfo = getRequiredTypeInfo(nestedMapper); - addNestedMapper(typeInfo[0], typeInfo[1], nestedMapper); - } - - /** - * Adds a Mapper that will map the fields of a nested sourceType/targetType pair. - * The source and target field types are determined by introspecting the parameterized types on the implementation's Mapper generic interface. - * The target instance that is mapped is constructed by the provided {@link MappingTargetFactory}. - * This method is a convenience method for {@link #addNestedMapper(Class, Class, Mapper, MappingTargetFactory)}. - * @param nestedMapper the nested mapper - * @param targetFactory the nested mapper's target factory - */ public void addNestedMapper(Mapper nestedMapper, MappingTargetFactory targetFactory) { Class[] typeInfo = getRequiredTypeInfo(nestedMapper); addNestedMapper(typeInfo[0], typeInfo[1], nestedMapper, targetFactory); } - /** - * Adds a Mapper that will map the fields of a nested sourceType/targetType pair. - * The target instance that is mapped is constructed by a {@link DefaultMappingTargetFactory}. - * @param sourceType the source nested object property type - * @param targetType the target nested object property type - * @param nestedMapper the nested mapper - */ - public void addNestedMapper(Class sourceType, Class targetType, Mapper nestedMapper) { - this.conversionService.addGenericConverter(sourceType, targetType, new MappingConverter(nestedMapper)); - } - - /** - * Adds a Mapper that will map the fields of a nested sourceType/targetType pair. - * @param sourceType the source nested object property type - * @param targetType the target nested object property type - * @param nestedMapper the nested mapper - * @param targetFactory the nested mapper's target factory - */ public void addNestedMapper(Class sourceType, Class targetType, Mapper nestedMapper, MappingTargetFactory targetFactory) { this.conversionService.addGenericConverter(sourceType, targetType, new MappingConverter(nestedMapper, @@ -170,25 +138,33 @@ final class SpelMapper implements Mapper { // internal helpers private Expression parseSourceField(String sourceFieldExpression) { - Expression sourceExp; try { - sourceExp = sourceExpressionParser.parseExpression(sourceFieldExpression); + return sourceExpressionParser.parseExpression(sourceFieldExpression); } catch (ParseException e) { throw new IllegalArgumentException("The mapping source '" + sourceFieldExpression + "' is not a parseable value expression", e); } - return sourceExp; + } + + private Expression parseCondition(String condition) { + if (condition == null) { + return null; + } + try { + return sourceExpressionParser.parseExpression(condition); + } catch (ParseException e) { + throw new IllegalArgumentException("The mapping condition '" + condition + + "' is not a parseable value expression", e); + } } private Expression parseTargetField(String targetFieldExpression) { - Expression targetExp; try { - targetExp = targetExpressionParser.parseExpression(targetFieldExpression); + return targetExpressionParser.parseExpression(targetFieldExpression); } catch (ParseException e) { throw new IllegalArgumentException("The mapping target '" + targetFieldExpression + "' is not a parseable property expression", e); } - return targetExp; } private Class[] getRequiredTypeInfo(Mapper mapper) { @@ -221,7 +197,7 @@ final class SpelMapper implements Mapper { } try { if (targetExpression.isWritable(targetContext)) { - autoMappings.add(new FieldToFieldMapping(sourceExpression, targetExpression, null)); + autoMappings.add(new FieldToFieldMapping(sourceExpression, targetExpression, null, null)); } } catch (EvaluationException e) { @@ -246,4 +222,5 @@ final class SpelMapper implements Mapper { } return false; } + } diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMapperBuilder.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMapperBuilder.java index 22d3fbaeb8d..cb4f5f84101 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMapperBuilder.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMapperBuilder.java @@ -40,37 +40,68 @@ final class SpelMapperBuilder implements MapperBuilder { } public MapperBuilder addMapping(String field) { - this.mapper.addMapping(field, field, null); + this.mapper.addMapping(field, field, null, null); return this; } public MapperBuilder addMapping(String field, Converter converter) { - this.mapper.addMapping(field, field, converter); + this.mapper.addMapping(field, field, converter, null); return this; } public MapperBuilder addMapping(String field, Mapper mapper) { - this.mapper.addMapping(field, mapper); + this.mapper.addMapping(field, mapper, null); return this; } public MapperBuilder addMapping(String sourceField, String targetField) { - this.mapper.addMapping(sourceField, targetField, null); + this.mapper.addMapping(sourceField, targetField, null, null); return this; } public MapperBuilder addMapping(String sourceField, String targetField, Converter converter) { - this.mapper.addMapping(sourceField, targetField, converter); + this.mapper.addMapping(sourceField, targetField, converter, null); return this; } public MapperBuilder addMapping(String[] fields, Mapper mapper) { - this.mapper.addMapping(fields, mapper); + this.mapper.addMapping(fields, mapper, null); + return this; + } + + public MapperBuilder addConditionalMapping(String field, String condition) { + this.mapper.addMapping(field, field, null, condition); + return this; + } + + public MapperBuilder addConditionalMapping(String field, Converter converter, String condition) { + this.mapper.addMapping(field, field, converter, condition); + return this; + } + + public MapperBuilder addConditionalMapping(String field, Mapper mapper, String condition) { + this.mapper.addMapping(field, mapper, condition); + return this; + } + + public MapperBuilder addConditionalMapping(String sourceField, String targetField, String condition) { + this.mapper.addMapping(sourceField, targetField, null, condition); + return this; + } + + public MapperBuilder addConditionalMapping(String sourceField, String targetField, Converter converter, + String condition) { + this.mapper.addMapping(sourceField, targetField, converter, condition); + return this; + } + + public MapperBuilder addMapping(String[] fields, Mapper mapper, String condition) { + this.mapper.addMapping(fields, mapper, condition); return this; } public MapperBuilder addNestedMapper(Mapper nestedMapper) { - this.mapper.addNestedMapper(nestedMapper); + this.mapper.addNestedMapper(nestedMapper, null); return this; } @@ -83,6 +114,11 @@ final class SpelMapperBuilder implements MapperBuilder { this.mapper.getConverterRegistry().addConverter(converter); return this; } + + public MapperBuilder setExcludedFields(String... fields) { + this.mapper.setExcludedFields(fields); + return this; + } @SuppressWarnings("unchecked") public Mapper getMapper() { diff --git a/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMappingContext.java b/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMappingContext.java index 538b94348a2..be4a5614a44 100644 --- a/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMappingContext.java +++ b/org.springframework.context/src/main/java/org/springframework/mapping/support/SpelMappingContext.java @@ -43,7 +43,14 @@ final class SpelMappingContext { public Object getTarget() { return this.targetEvaluationContext.getRootObject().getValue(); } - + + public boolean conditionHolds(Expression condition) { + if (condition == null) { + return true; + } + return Boolean.TRUE.equals(condition.getValue(this.sourceEvaluationContext)); + } + public Object getSourceFieldValue(Expression sourceField) { return sourceField.getValue(this.sourceEvaluationContext); } @@ -61,4 +68,5 @@ final class SpelMappingContext { throw new MappingException(this.failures); } } + } diff --git a/org.springframework.context/src/test/java/org/springframework/mapping/support/MappingTests.java b/org.springframework.context/src/test/java/org/springframework/mapping/support/MappingTests.java index f7de9dae0bf..3085002b4de 100644 --- a/org.springframework.context/src/test/java/org/springframework/mapping/support/MappingTests.java +++ b/org.springframework.context/src/test/java/org/springframework/mapping/support/MappingTests.java @@ -317,6 +317,45 @@ public class MappingTests { .getActivationDateTime()); } + @Test + public void conditionalMapping() { + Map domestic = new HashMap(); + domestic.put("international", "false"); + domestic.put("areaCode", "205"); + domestic.put("prefix", "339"); + domestic.put("line", "1234"); + domestic.put("countryCode", "whatever"); + domestic.put("cityCode", "whatever"); + + Mapper mapper = MapperFactory.mapperBuilder(Map.class, PhoneNumber.class) + .addConditionalMapping("countryCode", "international == 'true'") + .addConditionalMapping("cityCode", "international == 'true'") + .getMapper(); + + PhoneNumber number = mapper.map(domestic, new PhoneNumber()); + assertEquals("205", number.getAreaCode()); + assertEquals("339", number.getPrefix()); + assertEquals("1234", number.getLine()); + assertNull(number.getCountryCode()); + assertNull(number.getCityCode()); + + Map international = new HashMap(); + international.put("international", "true"); + international.put("areaCode", "205"); + international.put("prefix", "339"); + international.put("line", "1234"); + international.put("countryCode", "1"); + international.put("cityCode", "2"); + + PhoneNumber number2 = mapper.map(international, new PhoneNumber()); + + assertEquals("205", number2.getAreaCode()); + assertEquals("339", number2.getPrefix()); + assertEquals("1234", number2.getLine()); + assertEquals("1", number2.getCountryCode()); + assertEquals("2", number2.getCityCode()); + } + @Test public void mapList() { PersonDto source = new PersonDto(); @@ -876,4 +915,59 @@ public class MappingTests { } } + + public static class PhoneNumber { + + private String areaCode; + + private String prefix; + + private String line; + + private String countryCode; + + private String cityCode; + + public String getAreaCode() { + return areaCode; + } + + public void setAreaCode(String areaCode) { + this.areaCode = areaCode; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String getLine() { + return line; + } + + public void setLine(String line) { + this.line = line; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public String getCityCode() { + return cityCode; + } + + public void setCityCode(String cityCode) { + this.cityCode = cityCode; + } + + } + }