From 737af6b50a1641d936c8a5b152bb97bf1f843d18 Mon Sep 17 00:00:00 2001
From: Roman Obolonskyi <65775868+Obolrom@users.noreply.github.com>
Date: Sun, 17 Nov 2024 17:46:59 +0200
Subject: [PATCH] #3628 Add support for locale parameter for numberFormat and
dateFormat
---
.../java/org/mapstruct/IterableMapping.java | 19 +
.../main/java/org/mapstruct/MapMapping.java | 27 +
core/src/main/java/org/mapstruct/Mapping.java | 19 +
.../BigDecimalToStringConversion.java | 20 +-
.../BigIntegerToStringConversion.java | 20 +-
.../internal/conversion/ConversionUtils.java | 12 +
.../conversion/CreateDecimalFormat.java | 37 +-
.../conversion/DateToStringConversion.java | 35 +-
.../PrimitiveToStringConversion.java | 39 +-
.../conversion/WrapperToStringConversion.java | 39 +-
.../model/common/ConversionContext.java | 2 +
.../common/DefaultConversionContext.java | 7 +
.../model/common/FormattingParameters.java | 10 +-
.../model/source/IterableMappingOptions.java | 3 +-
.../model/source/MapMappingOptions.java | 14 +-
.../internal/model/source/MappingOptions.java | 9 +-
.../conversion/CreateDecimalFormat.ftl | 7 +-
.../common/DefaultConversionContextTest.java | 6 +-
.../conversion/date/DateConversionTest.java | 120 ++++
.../conversion/date/SourceTargetMapper.java | 24 +-
.../numbers/NumberFormatConversionTest.java | 126 ++++-
.../numbers/SourceTargetMapper.java | 41 +-
.../numbers/SourceTargetMapperImpl.java | 525 ++++++++++++++++++
.../numbers/SourceTargetMapperImpl.java | 525 ++++++++++++++++++
24 files changed, 1631 insertions(+), 55 deletions(-)
create mode 100644 processor/src/test/resources/fixtures/21/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapperImpl.java
create mode 100644 processor/src/test/resources/fixtures/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapperImpl.java
diff --git a/core/src/main/java/org/mapstruct/IterableMapping.java b/core/src/main/java/org/mapstruct/IterableMapping.java
index 76153127b..d644dfe03 100644
--- a/core/src/main/java/org/mapstruct/IterableMapping.java
+++ b/core/src/main/java/org/mapstruct/IterableMapping.java
@@ -66,19 +66,38 @@ public @interface IterableMapping {
/**
* A format string as processable by {@link SimpleDateFormat} if the annotated method maps from an iterable of
* {@code String} to an iterable {@link Date} or vice-versa. Will be ignored for all other element types.
+ *
+ * If the {@link #locale()} is also specified, the format will consider the specified locale when processing
+ * the date. Otherwise, the system's default locale will be used.
*
* @return A date format string as processable by {@link SimpleDateFormat}.
+ * @see #locale()
*/
String dateFormat() default "";
/**
* A format string as processable by {@link DecimalFormat} if the annotated method maps from a
* {@link Number} to a {@link String} or vice-versa. Will be ignored for all other element types.
+ *
+ * If the {@link #locale()} is also specified, the number format will be applied in the context of the given locale.
+ * Otherwise, the system's default locale will be used to process the number format.
*
* @return A decimal format string as processable by {@link DecimalFormat}.
+ * @see #locale()
*/
String numberFormat() default "";
+ /**
+ * Specifies the locale to be used when processing {@link #dateFormat()} or {@link #numberFormat()}.
+ *
+ * The locale should be a plain tag representing the language, such as "en" for English, "de" for German, etc.
+ *
+ * If no locale is specified, the system's default locale will be used.
+ *
+ * @return A string representing the locale to be used when formatting dates or numbers.
+ */
+ String locale() default "";
+
/**
* A qualifier can be specified to aid the selection process of a suitable mapper. This is useful in case multiple
* mappers (hand written of internal) qualify and result in an 'Ambiguous mapping methods found' error.
diff --git a/core/src/main/java/org/mapstruct/MapMapping.java b/core/src/main/java/org/mapstruct/MapMapping.java
index 271272bb4..093099cf5 100644
--- a/core/src/main/java/org/mapstruct/MapMapping.java
+++ b/core/src/main/java/org/mapstruct/MapMapping.java
@@ -56,8 +56,12 @@ public @interface MapMapping {
/**
* A format string as processable by {@link SimpleDateFormat} if the annotated method maps from a map with key type
* {@code String} to an map with key type {@link Date} or vice-versa. Will be ignored for all other key types.
+ *
+ * If the {@link #locale()} is specified, the format will consider the specified locale when processing the date.
+ * Otherwise, the system's default locale will be used.
*
* @return A date format string as processable by {@link SimpleDateFormat}.
+ * @see #locale()
*/
String keyDateFormat() default "";
@@ -65,27 +69,50 @@ public @interface MapMapping {
* A format string as processable by {@link SimpleDateFormat} if the annotated method maps from a map with value
* type {@code String} to an map with value type {@link Date} or vice-versa. Will be ignored for all other value
* types.
+ *
+ * If the {@link #locale()} is specified, the format will consider the specified locale when processing the date.
+ * Otherwise, the system's default locale will be used.
*
* @return A date format string as processable by {@link SimpleDateFormat}.
+ * @see #locale()
*/
String valueDateFormat() default "";
/**
* A format string as processable by {@link DecimalFormat} if the annotated method maps from a
* {@link Number} to a {@link String} or vice-versa. Will be ignored for all other key types.
+ *
+ * If the {@link #locale()} is specified, the number format will be applied in the context of the given locale.
+ * Otherwise, the system's default locale will be used.
*
* @return A decimal format string as processable by {@link DecimalFormat}.
+ * @see #locale()
*/
String keyNumberFormat() default "";
/**
* A format string as processable by {@link DecimalFormat} if the annotated method maps from a
* {@link Number} to a {@link String} or vice-versa. Will be ignored for all other value types.
+ *
+ * If the {@link #locale()} is specified, the number format will be applied in the context of the given locale.
+ * Otherwise, the system's default locale will be used.
*
* @return A decimal format string as processable by {@link DecimalFormat}.
+ * @see #locale()
*/
String valueNumberFormat() default "";
+ /**
+ * Specifies the locale to be used when processing {@link SimpleDateFormat} or {@link DecimalFormat} for key or
+ * value mappings in maps. The locale should be a plain tag representing the language, such as "en" for English,
+ * "de" for German, etc.
+ *
+ * If no locale is specified, the system's default locale will be used.
+ *
+ * @return A string representing the locale to be used when formatting dates or numbers in maps.
+ */
+ String locale() default "";
+
/**
* A key value qualifier can be specified to aid the selection process of a suitable mapper. This is useful in
* case multiple mappers (hand written of internal) qualify and result in an 'Ambiguous mapping methods found'
diff --git a/core/src/main/java/org/mapstruct/Mapping.java b/core/src/main/java/org/mapstruct/Mapping.java
index 8b0c4adb0..6c95b0db2 100644
--- a/core/src/main/java/org/mapstruct/Mapping.java
+++ b/core/src/main/java/org/mapstruct/Mapping.java
@@ -175,19 +175,38 @@ public @interface Mapping {
/**
* A format string as processable by {@link SimpleDateFormat} if the attribute is mapped from {@code String} to
* {@link Date} or vice-versa. Will be ignored for all other attribute types and when mapping enum constants.
+ *
+ * If the {@link #locale()} is also specified, the format will consider the specified locale when processing
+ * the date. Otherwise, the system's default locale will be used.
*
* @return A date format string as processable by {@link SimpleDateFormat}.
+ * @see #locale()
*/
String dateFormat() default "";
/**
* A format string as processable by {@link DecimalFormat} if the annotated method maps from a
* {@link Number} to a {@link String} or vice-versa. Will be ignored for all other element types.
+ *
+ * If the {@link #locale()} is also specified, the number format will be applied in the context of the given locale.
+ * Otherwise, the system's default locale will be used to process the number format.
*
* @return A decimal format string as processable by {@link DecimalFormat}.
+ * @see #locale()
*/
String numberFormat() default "";
+ /**
+ * Specifies the locale to be used when processing {@link #dateFormat()} or {@link #numberFormat()}.
+ *
+ * The locale should be a plain tag representing the language, such as "en" for English, "de" for German, etc.
+ *
+ * If no locale is specified, the system's default locale will be used.
+ *
+ * @return A string representing the locale to be used when formatting dates or numbers.
+ */
+ String locale() default "";
+
/**
* A constant {@link String} based on which the specified target property is to be set.
*
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/BigDecimalToStringConversion.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/BigDecimalToStringConversion.java
index 92a93e389..384013a7b 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/BigDecimalToStringConversion.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/BigDecimalToStringConversion.java
@@ -14,8 +14,9 @@ import org.mapstruct.ap.internal.model.HelperMethod;
import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Type;
-import static org.mapstruct.ap.internal.util.Collections.asSet;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.bigDecimal;
+import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale;
+import static org.mapstruct.ap.internal.util.Collections.asSet;
/**
* Conversion between {@link BigDecimal} and {@link String}.
@@ -64,18 +65,31 @@ public class BigDecimalToStringConversion extends AbstractNumberToStringConversi
public List getRequiredHelperMethods(ConversionContext conversionContext) {
List helpers = new ArrayList<>();
if ( conversionContext.getNumberFormat() != null ) {
- helpers.add( new CreateDecimalFormat( conversionContext.getTypeFactory() ) );
+ helpers.add( new CreateDecimalFormat(
+ conversionContext.getTypeFactory(),
+ conversionContext.getLocale() != null
+ ) );
}
return helpers;
}
private void appendDecimalFormatter(StringBuilder sb, ConversionContext conversionContext) {
- sb.append( "createDecimalFormat( " );
+ boolean withLocale = conversionContext.getLocale() != null;
+ sb.append( "createDecimalFormat" );
+ if ( withLocale ) {
+ sb.append( "WithLocale" );
+ }
+ sb.append( "( " );
if ( conversionContext.getNumberFormat() != null ) {
sb.append( "\"" );
sb.append( conversionContext.getNumberFormat() );
sb.append( "\"" );
}
+ if ( withLocale ) {
+ sb.append( ", " ).append( locale( conversionContext ) ).append( ".forLanguageTag( \"" );
+ sb.append( conversionContext.getLocale() );
+ sb.append( "\" )" );
+ }
sb.append( " )" );
}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/BigIntegerToStringConversion.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/BigIntegerToStringConversion.java
index df0a48a67..540d89db5 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/BigIntegerToStringConversion.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/BigIntegerToStringConversion.java
@@ -15,9 +15,10 @@ import org.mapstruct.ap.internal.model.HelperMethod;
import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Type;
-import static org.mapstruct.ap.internal.util.Collections.asSet;
+import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.bigDecimal;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.bigInteger;
+import static org.mapstruct.ap.internal.util.Collections.asSet;
/**
* Conversion between {@link BigInteger} and {@link String}.
@@ -72,18 +73,31 @@ public class BigIntegerToStringConversion extends AbstractNumberToStringConversi
public List getRequiredHelperMethods(ConversionContext conversionContext) {
List helpers = new ArrayList<>();
if ( conversionContext.getNumberFormat() != null ) {
- helpers.add( new CreateDecimalFormat( conversionContext.getTypeFactory() ) );
+ helpers.add( new CreateDecimalFormat(
+ conversionContext.getTypeFactory(),
+ conversionContext.getLocale() != null
+ ) );
}
return helpers;
}
private void appendDecimalFormatter(StringBuilder sb, ConversionContext conversionContext) {
- sb.append( "createDecimalFormat( " );
+ boolean withLocale = conversionContext.getLocale() != null;
+ sb.append( "createDecimalFormat" );
+ if ( withLocale ) {
+ sb.append( "WithLocale" );
+ }
+ sb.append( "( " );
if ( conversionContext.getNumberFormat() != null ) {
sb.append( "\"" );
sb.append( conversionContext.getNumberFormat() );
sb.append( "\"" );
}
+ if ( withLocale ) {
+ sb.append( ", " ).append( locale( conversionContext ) ).append( ".forLanguageTag( \"" );
+ sb.append( conversionContext.getLocale() );
+ sb.append( "\" )" );
+ }
sb.append( " )" );
}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java
index aa01a7327..96960c4a1 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java
@@ -11,6 +11,7 @@ import java.net.URL;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -279,4 +280,15 @@ public final class ConversionUtils {
return typeReferenceName( conversionContext, URL.class );
}
+ /**
+ * Name for {@link java.text.DecimalFormatSymbols}.
+ *
+ * @param conversionContext Conversion context
+ *
+ * @return Name or fully-qualified name.
+ */
+ public static String decimalFormatSymbols(ConversionContext conversionContext) {
+ return typeReferenceName( conversionContext, DecimalFormatSymbols.class );
+ }
+
}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/CreateDecimalFormat.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/CreateDecimalFormat.java
index 77c59445a..d1b49cff6 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/CreateDecimalFormat.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/CreateDecimalFormat.java
@@ -5,9 +5,11 @@
*/
package org.mapstruct.ap.internal.conversion;
-import static org.mapstruct.ap.internal.util.Collections.asSet;
-
import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
import java.util.Set;
import org.mapstruct.ap.internal.model.HelperMethod;
@@ -16,6 +18,8 @@ import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.model.source.MappingMethodOptions;
+import static org.mapstruct.ap.internal.util.Collections.asSet;
+
/**
* HelperMethod that creates a {@link java.text.DecimalFormat}
*
@@ -27,13 +31,30 @@ import org.mapstruct.ap.internal.model.source.MappingMethodOptions;
public class CreateDecimalFormat extends HelperMethod {
private final Parameter parameter;
+ private final Parameter localeParameter;
private final Type returnType;
private final Set importTypes;
- public CreateDecimalFormat(TypeFactory typeFactory) {
+ public CreateDecimalFormat(TypeFactory typeFactory, boolean withLocale) {
this.parameter = new Parameter( "numberFormat", typeFactory.getType( String.class ) );
+ this.localeParameter = withLocale ? new Parameter( "locale", typeFactory.getType( Locale.class ) ) : null;
this.returnType = typeFactory.getType( DecimalFormat.class );
- this.importTypes = asSet( parameter.getType(), returnType );
+ if ( withLocale ) {
+ this.importTypes = asSet(
+ parameter.getType(),
+ returnType,
+ typeFactory.getType( DecimalFormatSymbols.class ),
+ typeFactory.getType( Locale.class )
+ );
+ }
+ else {
+ this.importTypes = asSet( parameter.getType(), returnType );
+ }
+ }
+
+ @Override
+ public String getName() {
+ return localeParameter == null ? "createDecimalFormat" : "createDecimalFormatWithLocale";
}
@Override
@@ -60,4 +81,12 @@ public class CreateDecimalFormat extends HelperMethod {
public String describe() {
return null;
}
+
+ @Override
+ public List getParameters() {
+ if ( localeParameter == null ) {
+ return super.getParameters();
+ }
+ return Arrays.asList( getParameter(), localeParameter );
+ }
}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/DateToStringConversion.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/DateToStringConversion.java
index 361ce9d9a..35c7f88d7 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/DateToStringConversion.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/DateToStringConversion.java
@@ -10,15 +10,18 @@ import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Locale;
+import java.util.Set;
import org.mapstruct.ap.internal.model.HelperMethod;
import org.mapstruct.ap.internal.model.TypeConversion;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ConversionContext;
+import org.mapstruct.ap.internal.model.common.Type;
-import static java.util.Arrays.asList;
-import static org.mapstruct.ap.internal.util.Collections.asSet;
+import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.simpleDateFormat;
+import static org.mapstruct.ap.internal.util.Collections.asSet;
/**
* Conversion between {@link String} and {@link Date}.
@@ -29,7 +32,7 @@ public class DateToStringConversion implements ConversionProvider {
@Override
public Assignment to(ConversionContext conversionContext) {
- return new TypeConversion( asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ),
+ return new TypeConversion( getImportTypes( conversionContext ),
Collections.emptyList(),
getConversionExpression( conversionContext, "format" )
);
@@ -37,8 +40,8 @@ public class DateToStringConversion implements ConversionProvider {
@Override
public Assignment from(ConversionContext conversionContext) {
- return new TypeConversion( asSet( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) ),
- asList( conversionContext.getTypeFactory().getType( ParseException.class ) ),
+ return new TypeConversion( getImportTypes( conversionContext ),
+ Collections.singletonList( conversionContext.getTypeFactory().getType( ParseException.class ) ),
getConversionExpression( conversionContext, "parse" )
);
}
@@ -48,6 +51,17 @@ public class DateToStringConversion implements ConversionProvider {
return Collections.emptyList();
}
+ private Set getImportTypes(ConversionContext conversionContext) {
+ if ( conversionContext.getLocale() == null ) {
+ return Collections.singleton( conversionContext.getTypeFactory().getType( SimpleDateFormat.class ) );
+ }
+
+ return asSet(
+ conversionContext.getTypeFactory().getType( SimpleDateFormat.class ),
+ conversionContext.getTypeFactory().getType( Locale.class )
+ );
+ }
+
private String getConversionExpression(ConversionContext conversionContext, String method) {
StringBuilder conversionString = new StringBuilder( "new " );
conversionString.append( simpleDateFormat( conversionContext ) );
@@ -56,7 +70,16 @@ public class DateToStringConversion implements ConversionProvider {
if ( conversionContext.getDateFormat() != null ) {
conversionString.append( " \"" );
conversionString.append( conversionContext.getDateFormat() );
- conversionString.append( "\" " );
+ conversionString.append( "\"" );
+
+ if ( conversionContext.getLocale() != null ) {
+ conversionString.append( ", " ).append( locale( conversionContext ) ).append( ".forLanguageTag( \"" );
+ conversionString.append( conversionContext.getLocale() );
+ conversionString.append( "\" ) " );
+ }
+ else {
+ conversionString.append( " " );
+ }
}
conversionString.append( ")." );
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/PrimitiveToStringConversion.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/PrimitiveToStringConversion.java
index fcc724129..909ce8c0f 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/PrimitiveToStringConversion.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/PrimitiveToStringConversion.java
@@ -6,7 +6,9 @@
package org.mapstruct.ap.internal.conversion;
import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
import java.util.Collections;
+import java.util.Locale;
import java.util.Set;
import org.mapstruct.ap.internal.model.common.ConversionContext;
@@ -15,6 +17,9 @@ import org.mapstruct.ap.internal.util.NativeTypes;
import org.mapstruct.ap.internal.util.Strings;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormat;
+import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormatSymbols;
+import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale;
+import static org.mapstruct.ap.internal.util.Collections.asSet;
/**
* Conversion between primitive types such as {@code byte} or {@code long} and
@@ -53,9 +58,15 @@ public class PrimitiveToStringConversion extends AbstractNumberToStringConversio
@Override
public Set getToConversionImportTypes(ConversionContext conversionContext) {
if ( requiresDecimalFormat( conversionContext ) ) {
- return Collections.singleton(
- conversionContext.getTypeFactory().getType( DecimalFormat.class )
- );
+ if ( conversionContext.getLocale() != null ) {
+ return asSet(
+ conversionContext.getTypeFactory().getType( DecimalFormat.class ),
+ conversionContext.getTypeFactory().getType( DecimalFormatSymbols.class ),
+ conversionContext.getTypeFactory().getType( Locale.class )
+ );
+ }
+
+ return Collections.singleton( conversionContext.getTypeFactory().getType( DecimalFormat.class ) );
}
return Collections.emptySet();
@@ -80,9 +91,15 @@ public class PrimitiveToStringConversion extends AbstractNumberToStringConversio
@Override
protected Set getFromConversionImportTypes(ConversionContext conversionContext) {
if ( requiresDecimalFormat( conversionContext ) ) {
- return Collections.singleton(
- conversionContext.getTypeFactory().getType( DecimalFormat.class )
- );
+ if ( conversionContext.getLocale() != null ) {
+ return asSet(
+ conversionContext.getTypeFactory().getType( DecimalFormat.class ),
+ conversionContext.getTypeFactory().getType( DecimalFormatSymbols.class ),
+ conversionContext.getTypeFactory().getType( Locale.class )
+ );
+ }
+
+ return Collections.singleton( conversionContext.getTypeFactory().getType( DecimalFormat.class ) );
}
return Collections.emptySet();
@@ -97,6 +114,16 @@ public class PrimitiveToStringConversion extends AbstractNumberToStringConversio
sb.append( "\"" );
sb.append( conversionContext.getNumberFormat() );
sb.append( "\"" );
+
+ if ( conversionContext.getLocale() != null ) {
+ sb.append( ", " )
+ .append( decimalFormatSymbols( conversionContext ) )
+ .append( ".getInstance( " )
+ .append( locale( conversionContext ) )
+ .append( ".forLanguageTag( \"" )
+ .append( conversionContext.getLocale() )
+ .append( " \" ) )" );
+ }
}
sb.append( " )" );
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/WrapperToStringConversion.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/WrapperToStringConversion.java
index 300c90121..dd7b6bac8 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/WrapperToStringConversion.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/WrapperToStringConversion.java
@@ -6,7 +6,9 @@
package org.mapstruct.ap.internal.conversion;
import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
import java.util.Collections;
+import java.util.Locale;
import java.util.Set;
import org.mapstruct.ap.internal.model.common.ConversionContext;
@@ -15,6 +17,9 @@ import org.mapstruct.ap.internal.util.NativeTypes;
import org.mapstruct.ap.internal.util.Strings;
import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormat;
+import static org.mapstruct.ap.internal.conversion.ConversionUtils.decimalFormatSymbols;
+import static org.mapstruct.ap.internal.conversion.ConversionUtils.locale;
+import static org.mapstruct.ap.internal.util.Collections.asSet;
/**
* Conversion between wrapper types such as {@link Integer} and {@link String}.
@@ -52,9 +57,15 @@ public class WrapperToStringConversion extends AbstractNumberToStringConversion
@Override
public Set getToConversionImportTypes(ConversionContext conversionContext) {
if ( requiresDecimalFormat( conversionContext ) ) {
- return Collections.singleton(
- conversionContext.getTypeFactory().getType( DecimalFormat.class )
- );
+ if ( conversionContext.getLocale() != null ) {
+ return asSet(
+ conversionContext.getTypeFactory().getType( DecimalFormat.class ),
+ conversionContext.getTypeFactory().getType( DecimalFormatSymbols.class ),
+ conversionContext.getTypeFactory().getType( Locale.class )
+ );
+ }
+
+ return Collections.singleton( conversionContext.getTypeFactory().getType( DecimalFormat.class ) );
}
return Collections.emptySet();
@@ -79,9 +90,15 @@ public class WrapperToStringConversion extends AbstractNumberToStringConversion
@Override
protected Set getFromConversionImportTypes(ConversionContext conversionContext) {
if ( requiresDecimalFormat( conversionContext ) ) {
- return Collections.singleton(
- conversionContext.getTypeFactory().getType( DecimalFormat.class )
- );
+ if ( conversionContext.getLocale() != null ) {
+ return asSet(
+ conversionContext.getTypeFactory().getType( DecimalFormat.class ),
+ conversionContext.getTypeFactory().getType( DecimalFormatSymbols.class ),
+ conversionContext.getTypeFactory().getType( Locale.class )
+ );
+ }
+
+ return Collections.singleton( conversionContext.getTypeFactory().getType( DecimalFormat.class ) );
}
return Collections.emptySet();
@@ -96,6 +113,16 @@ public class WrapperToStringConversion extends AbstractNumberToStringConversion
sb.append( "\"" );
sb.append( conversionContext.getNumberFormat() );
sb.append( "\"" );
+
+ if ( conversionContext.getLocale() != null ) {
+ sb.append( ", " )
+ .append( decimalFormatSymbols( conversionContext ) )
+ .append( ".getInstance( " )
+ .append( locale( conversionContext ) )
+ .append( ".forLanguageTag( \"" )
+ .append( conversionContext.getLocale() )
+ .append( " \" ) )" );
+ }
}
sb.append( " )" );
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/ConversionContext.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/ConversionContext.java
index c2aa73f30..96d3d6fe7 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/ConversionContext.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/ConversionContext.java
@@ -32,6 +32,8 @@ public interface ConversionContext {
String getNumberFormat();
+ String getLocale();
+
TypeFactory getTypeFactory();
}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/DefaultConversionContext.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/DefaultConversionContext.java
index f5a9fcc76..159f1663e 100755
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/DefaultConversionContext.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/DefaultConversionContext.java
@@ -21,6 +21,7 @@ public class DefaultConversionContext implements ConversionContext {
private final FormattingParameters formattingParameters;
private final String dateFormat;
private final String numberFormat;
+ private final String locale;
private final TypeFactory typeFactory;
public DefaultConversionContext(TypeFactory typeFactory, FormattingMessager messager, Type sourceType,
@@ -32,6 +33,7 @@ public class DefaultConversionContext implements ConversionContext {
this.formattingParameters = formattingParameters;
this.dateFormat = this.formattingParameters.getDate();
this.numberFormat = this.formattingParameters.getNumber();
+ this.locale = this.formattingParameters.getLocale();
validateDateFormat();
}
@@ -64,6 +66,11 @@ public class DefaultConversionContext implements ConversionContext {
return numberFormat;
}
+ @Override
+ public String getLocale() {
+ return locale != null ? locale.toString() : null;
+ }
+
@Override
public String getDateFormat() {
return dateFormat;
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/FormattingParameters.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/FormattingParameters.java
index e21f5d74f..48cee4bbe 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/FormattingParameters.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/FormattingParameters.java
@@ -15,21 +15,23 @@ import javax.lang.model.element.Element;
*/
public class FormattingParameters {
- public static final FormattingParameters EMPTY = new FormattingParameters( null, null, null, null, null );
+ public static final FormattingParameters EMPTY = new FormattingParameters( null, null, null, null, null, null );
private final String date;
private final String number;
private final AnnotationMirror mirror;
private final AnnotationValue dateAnnotationValue;
private final Element element;
+ private final String locale;
public FormattingParameters(String date, String number, AnnotationMirror mirror,
- AnnotationValue dateAnnotationValue, Element element) {
+ AnnotationValue dateAnnotationValue, Element element, String locale) {
this.date = date;
this.number = number;
this.mirror = mirror;
this.dateAnnotationValue = dateAnnotationValue;
this.element = element;
+ this.locale = locale;
}
public String getDate() {
@@ -51,4 +53,8 @@ public class FormattingParameters {
public Element getElement() {
return element;
}
+
+ public String getLocale() {
+ return locale;
+ }
}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/IterableMappingOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/IterableMappingOptions.java
index c4770efde..50fca3e4d 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/IterableMappingOptions.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/IterableMappingOptions.java
@@ -55,7 +55,8 @@ public class IterableMappingOptions extends DelegatingOptions {
iterableMapping.numberFormat().get(),
iterableMapping.mirror(),
iterableMapping.dateFormat().getAnnotationValue(),
- method
+ method,
+ iterableMapping.locale().getValue()
);
IterableMappingOptions options =
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapMappingOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapMappingOptions.java
index fd1758d8d..9f3d12faf 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapMappingOptions.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapMappingOptions.java
@@ -8,14 +8,14 @@ package org.mapstruct.ap.internal.model.source;
import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
-import org.mapstruct.ap.internal.util.ElementUtils;
-import org.mapstruct.ap.internal.util.TypeUtils;
-import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.gem.MapMappingGem;
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
+import org.mapstruct.ap.internal.model.common.FormattingParameters;
+import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.FormattingMessager;
import org.mapstruct.ap.internal.util.Message;
+import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.tools.gem.GemValue;
/**
@@ -47,6 +47,8 @@ public class MapMappingOptions extends DelegatingOptions {
return options;
}
+ String locale = mapMapping.locale().getValue();
+
SelectionParameters keySelection = new SelectionParameters(
mapMapping.keyQualifiedBy().get(),
mapMapping.keyQualifiedByName().get(),
@@ -66,7 +68,8 @@ public class MapMappingOptions extends DelegatingOptions {
mapMapping.keyNumberFormat().get(),
mapMapping.mirror(),
mapMapping.keyDateFormat().getAnnotationValue(),
- method
+ method,
+ locale
);
FormattingParameters valueFormatting = new FormattingParameters(
@@ -74,7 +77,8 @@ public class MapMappingOptions extends DelegatingOptions {
mapMapping.valueNumberFormat().get(),
mapMapping.mirror(),
mapMapping.valueDateFormat().getAnnotationValue(),
- method
+ method,
+ locale
);
MapMappingOptions options = new MapMappingOptions(
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java
index 22f9ccdc2..746aca5a3 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java
@@ -18,16 +18,16 @@ import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
-import org.mapstruct.ap.internal.util.ElementUtils;
-import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.gem.MappingGem;
import org.mapstruct.ap.internal.gem.MappingsGem;
import org.mapstruct.ap.internal.gem.NullValueCheckStrategyGem;
import org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
+import org.mapstruct.ap.internal.util.ElementUtils;
import org.mapstruct.ap.internal.util.FormattingMessager;
import org.mapstruct.ap.internal.util.Message;
+import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.tools.gem.GemValue;
/**
@@ -118,6 +118,8 @@ public class MappingOptions extends DelegatingOptions {
String conditionExpression = getConditionExpression( mapping, method, messager );
String dateFormat = mapping.dateFormat().getValue();
String numberFormat = mapping.numberFormat().getValue();
+ String locale = mapping.locale().getValue();
+
String defaultValue = mapping.defaultValue().getValue();
Set dependsOn = mapping.dependsOn().hasValue() ?
@@ -129,7 +131,8 @@ public class MappingOptions extends DelegatingOptions {
numberFormat,
mapping.mirror(),
mapping.dateFormat().getAnnotationValue(),
- method
+ method,
+ locale
);
SelectionParameters selectionParams = new SelectionParameters(
mapping.qualifiedBy().get(),
diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/conversion/CreateDecimalFormat.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/conversion/CreateDecimalFormat.ftl
index ce0f605f1..6753a73d6 100644
--- a/processor/src/main/resources/org/mapstruct/ap/internal/conversion/CreateDecimalFormat.ftl
+++ b/processor/src/main/resources/org/mapstruct/ap/internal/conversion/CreateDecimalFormat.ftl
@@ -5,9 +5,10 @@
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
-->
-private DecimalFormat ${name}( String numberFormat ) {
+<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.SupportingMappingMethod" -->
+private DecimalFormat ${name}( <#list parameters as param><@includeModel object=param/><#if param_has_next>, #if>#list> ) {
- DecimalFormat df = new DecimalFormat( numberFormat );
+ DecimalFormat df = new DecimalFormat( numberFormat<#if parameters.size() > 1>, DecimalFormatSymbols.getInstance( locale )#if> );
df.setParseBigDecimal( true );
return df;
-}
\ No newline at end of file
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/internal/model/common/DefaultConversionContextTest.java b/processor/src/test/java/org/mapstruct/ap/internal/model/common/DefaultConversionContextTest.java
index ce2f895e0..401a6b224 100755
--- a/processor/src/test/java/org/mapstruct/ap/internal/model/common/DefaultConversionContextTest.java
+++ b/processor/src/test/java/org/mapstruct/ap/internal/model/common/DefaultConversionContextTest.java
@@ -70,7 +70,7 @@ public class DefaultConversionContextTest {
statefulMessagerMock,
type,
type,
- new FormattingParameters( "qwertz", null, null, null, null )
+ new FormattingParameters( "qwertz", null, null, null, null, null )
);
assertThat( statefulMessagerMock.getLastKindPrinted() ).isEqualTo( Diagnostic.Kind.ERROR );
}
@@ -84,7 +84,7 @@ public class DefaultConversionContextTest {
statefulMessagerMock,
type,
type,
- new FormattingParameters( null, null, null, null, null )
+ new FormattingParameters( null, null, null, null, null, null )
);
assertThat( statefulMessagerMock.getLastKindPrinted() ).isNull();
}
@@ -97,7 +97,7 @@ public class DefaultConversionContextTest {
statefulMessagerMock,
type,
type,
- new FormattingParameters( "qwertz", null, null, null, null )
+ new FormattingParameters( "qwertz", null, null, null, null, null )
);
assertThat( statefulMessagerMock.getLastKindPrinted() ).isNull();
}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/date/DateConversionTest.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/date/DateConversionTest.java
index 9ccf8e7e1..bc9022820 100644
--- a/processor/src/test/java/org/mapstruct/ap/test/conversion/date/DateConversionTest.java
+++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/date/DateConversionTest.java
@@ -54,6 +54,21 @@ public class DateConversionTest {
assertThat( target.getAnotherDate() ).isEqualTo( "14.02.13 00:00" );
}
+ @ProcessorTest
+ @EnabledOnJre( JRE.JAVA_8 )
+ // See https://bugs.openjdk.java.net/browse/JDK-8211262, there is a difference in the default formats on Java 9+
+ public void shouldApplyDateFormatForConversionsWithCustomLocale() {
+ Source source = new Source();
+ source.setDate( new GregorianCalendar( 2013, Calendar.JULY, 6 ).getTime() );
+ source.setAnotherDate( new GregorianCalendar( 2013, Calendar.FEBRUARY, 14 ).getTime() );
+
+ Target target = SourceTargetMapper.INSTANCE.sourceToTargetWithCustomLocale( source );
+
+ assertThat( target ).isNotNull();
+ assertThat( target.getDate() ).isEqualTo( "juillet 06, 2013" );
+ assertThat( target.getAnotherDate() ).isEqualTo( "14.02.13, 00:00" );
+ }
+
@ProcessorTest
@EnabledForJreRange(min = JRE.JAVA_11)
// See https://bugs.openjdk.java.net/browse/JDK-8211262, there is a difference in the default formats on Java 9+
@@ -69,6 +84,21 @@ public class DateConversionTest {
assertThat( target.getAnotherDate() ).isEqualTo( "14.02.13, 00:00" );
}
+ @ProcessorTest
+ @EnabledForJreRange(min = JRE.JAVA_11)
+ // See https://bugs.openjdk.java.net/browse/JDK-8211262, there is a difference in the default formats on Java 9+
+ public void shouldApplyDateFormatForConversionsJdk11WithCustomLocale() {
+ Source source = new Source();
+ source.setDate( new GregorianCalendar( 2013, Calendar.JULY, 6 ).getTime() );
+ source.setAnotherDate( new GregorianCalendar( 2013, Calendar.FEBRUARY, 14 ).getTime() );
+
+ Target target = SourceTargetMapper.INSTANCE.sourceToTargetWithCustomLocale( source );
+
+ assertThat( target ).isNotNull();
+ assertThat( target.getDate() ).isEqualTo( "juillet 06, 2013" );
+ assertThat( target.getAnotherDate() ).isEqualTo( "14.02.13, 00:00" );
+ }
+
@ProcessorTest
@EnabledOnJre(JRE.JAVA_8)
// See https://bugs.openjdk.java.net/browse/JDK-8211262, there is a difference in the default formats on Java 9+
@@ -86,6 +116,23 @@ public class DateConversionTest {
);
}
+ @ProcessorTest
+ @EnabledOnJre(JRE.JAVA_8)
+ // See https://bugs.openjdk.java.net/browse/JDK-8211262, there is a difference in the default formats on Java 9+
+ public void shouldApplyDateFormatForConversionInReverseMappingWithCustomLocale() {
+ Target target = new Target();
+ target.setDate( "juillet 06, 2013" );
+ target.setAnotherDate( "14.02.13 8:30" );
+
+ Source source = SourceTargetMapper.INSTANCE.targetToSourceWithCustomLocale( target );
+
+ assertThat( source ).isNotNull();
+ assertThat( source.getDate() ).isEqualTo( new GregorianCalendar( 2013, Calendar.JULY, 6 ).getTime() );
+ assertThat( source.getAnotherDate() ).isEqualTo(
+ new GregorianCalendar( 2013, Calendar.FEBRUARY, 14, 8, 30 ).getTime()
+ );
+ }
+
@ProcessorTest
@EnabledForJreRange(min = JRE.JAVA_11)
// See https://bugs.openjdk.java.net/browse/JDK-8211262, there is a difference in the default formats on Java 9+
@@ -103,6 +150,23 @@ public class DateConversionTest {
);
}
+ @ProcessorTest
+ @EnabledForJreRange(min = JRE.JAVA_11)
+ // See https://bugs.openjdk.java.net/browse/JDK-8211262, there is a difference in the default formats on Java 9+
+ public void shouldApplyDateFormatForConversionInReverseMappingJdk11WithCustomLocale() {
+ Target target = new Target();
+ target.setDate( "juillet 06, 2013" );
+ target.setAnotherDate( "14.02.13, 8:30" );
+
+ Source source = SourceTargetMapper.INSTANCE.targetToSourceWithCustomLocale( target );
+
+ assertThat( source ).isNotNull();
+ assertThat( source.getDate() ).isEqualTo( new GregorianCalendar( 2013, Calendar.JULY, 6 ).getTime() );
+ assertThat( source.getAnotherDate() ).isEqualTo(
+ new GregorianCalendar( 2013, Calendar.FEBRUARY, 14, 8, 30 ).getTime()
+ );
+ }
+
@ProcessorTest
public void shouldApplyStringConversionForIterableMethod() {
List dates = Arrays.asList(
@@ -117,6 +181,20 @@ public class DateConversionTest {
assertThat( stringDates ).containsExactly( "06.07.2013", "14.02.2013", "11.04.2013" );
}
+ @ProcessorTest
+ public void shouldApplyStringConversionForIterableMethodWithCustomLocale() {
+ List dates = Arrays.asList(
+ new GregorianCalendar( 2013, Calendar.JULY, 6 ).getTime(),
+ new GregorianCalendar( 2013, Calendar.FEBRUARY, 14 ).getTime(),
+ new GregorianCalendar( 2013, Calendar.APRIL, 11 ).getTime()
+ );
+
+ List stringDates = SourceTargetMapper.INSTANCE.stringListToDateListWithCustomLocale( dates );
+
+ assertThat( stringDates ).isNotNull();
+ assertThat( stringDates ).containsExactly( "juillet 06, 2013", "février 14, 2013", "avril 11, 2013" );
+ }
+
@ProcessorTest
public void shouldApplyStringConversionForArrayMethod() {
List dates = Arrays.asList(
@@ -131,6 +209,20 @@ public class DateConversionTest {
assertThat( stringDates ).isEqualTo( new String[]{ "06.07.2013", "14.02.2013", "11.04.2013" } );
}
+ @ProcessorTest
+ public void shouldApplyStringConversionForArrayMethodWithCustomLocale() {
+ List dates = Arrays.asList(
+ new GregorianCalendar( 2013, Calendar.JULY, 6 ).getTime(),
+ new GregorianCalendar( 2013, Calendar.FEBRUARY, 14 ).getTime(),
+ new GregorianCalendar( 2013, Calendar.APRIL, 11 ).getTime()
+ );
+
+ String[] stringDates = SourceTargetMapper.INSTANCE.stringListToDateArrayWithCustomLocale( dates );
+
+ assertThat( stringDates ).isNotNull();
+ assertThat( stringDates ).isEqualTo( new String[]{ "juillet 06, 2013", "février 14, 2013", "avril 11, 2013" } );
+ }
+
@ProcessorTest
public void shouldApplyStringConversionForReverseIterableMethod() {
List stringDates = Arrays.asList( "06.07.2013", "14.02.2013", "11.04.2013" );
@@ -145,6 +237,20 @@ public class DateConversionTest {
);
}
+ @ProcessorTest
+ public void shouldApplyStringConversionForReverseIterableMethodWithCustomLocale() {
+ List stringDates = Arrays.asList( "juillet 06, 2013", "février 14, 2013", "avril 11, 2013" );
+
+ List dates = SourceTargetMapper.INSTANCE.dateListToStringListWithCustomLocale( stringDates );
+
+ assertThat( dates ).isNotNull();
+ assertThat( dates ).containsExactly(
+ new GregorianCalendar( 2013, Calendar.JULY, 6 ).getTime(),
+ new GregorianCalendar( 2013, Calendar.FEBRUARY, 14 ).getTime(),
+ new GregorianCalendar( 2013, Calendar.APRIL, 11 ).getTime()
+ );
+ }
+
@ProcessorTest
public void shouldApplyStringConversionForReverseArrayMethod() {
String[] stringDates = new String[]{ "06.07.2013", "14.02.2013", "11.04.2013" };
@@ -159,6 +265,20 @@ public class DateConversionTest {
);
}
+ @ProcessorTest
+ public void shouldApplyStringConversionForReverseArrayMethodWithCustomLocale() {
+ String[] stringDates = new String[]{ "juillet 06, 2013", "février 14, 2013", "avril 11, 2013" };
+
+ List dates = SourceTargetMapper.INSTANCE.stringArrayToDateListWithCustomLocale( stringDates );
+
+ assertThat( dates ).isNotNull();
+ assertThat( dates ).containsExactly(
+ new GregorianCalendar( 2013, Calendar.JULY, 6 ).getTime(),
+ new GregorianCalendar( 2013, Calendar.FEBRUARY, 14 ).getTime(),
+ new GregorianCalendar( 2013, Calendar.APRIL, 11 ).getTime()
+ );
+ }
+
@ProcessorTest
public void shouldApplyStringConversionForReverseArrayArrayMethod() {
Date[] dates = new Date[]{
diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/date/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/date/SourceTargetMapper.java
index 2ef6a7bd9..1971a8c06 100644
--- a/processor/src/test/java/org/mapstruct/ap/test/conversion/date/SourceTargetMapper.java
+++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/date/SourceTargetMapper.java
@@ -22,21 +22,39 @@ public interface SourceTargetMapper {
@Mapping(target = "date", dateFormat = "dd.MM.yyyy")
Target sourceToTarget(Source source);
- @InheritInverseConfiguration
+ @Mapping(target = "date", dateFormat = "MMMM dd, yyyy", locale = "fr")
+ Target sourceToTargetWithCustomLocale(Source source);
+
+ @InheritInverseConfiguration(name = "sourceToTarget")
Source targetToSource(Target target);
+ @InheritInverseConfiguration(name = "sourceToTargetWithCustomLocale")
+ Source targetToSourceWithCustomLocale(Target target);
+
@IterableMapping(dateFormat = "dd.MM.yyyy")
List stringListToDateList(List dates);
+ @IterableMapping(dateFormat = "MMMM dd, yyyy", locale = "fr")
+ List stringListToDateListWithCustomLocale(List dates);
+
@IterableMapping(dateFormat = "dd.MM.yyyy")
String[] stringListToDateArray(List dates);
- @InheritInverseConfiguration
+ @IterableMapping(dateFormat = "MMMM dd, yyyy", locale = "fr")
+ String[] stringListToDateArrayWithCustomLocale(List dates);
+
+ @InheritInverseConfiguration(name = "stringListToDateList")
List dateListToStringList(List strings);
- @InheritInverseConfiguration
+ @InheritInverseConfiguration(name = "stringListToDateListWithCustomLocale")
+ List dateListToStringListWithCustomLocale(List strings);
+
+ @InheritInverseConfiguration(name = "stringListToDateArray")
List stringArrayToDateList(String[] dates);
+ @InheritInverseConfiguration(name = "stringListToDateArrayWithCustomLocale")
+ List stringArrayToDateListWithCustomLocale(String[] dates);
+
@IterableMapping(dateFormat = "dd.MM.yyyy")
String[] dateArrayToStringArray(Date[] dates);
diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/numbers/NumberFormatConversionTest.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/numbers/NumberFormatConversionTest.java
index 6dfc1b3ca..39b4e9831 100644
--- a/processor/src/test/java/org/mapstruct/ap/test/conversion/numbers/NumberFormatConversionTest.java
+++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/numbers/NumberFormatConversionTest.java
@@ -7,14 +7,15 @@ package org.mapstruct.ap.test.conversion.numbers;
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.junit.jupiter.api.extension.RegisterExtension;
import org.junitpioneer.jupiter.DefaultLocale;
import org.mapstruct.ap.testutil.ProcessorTest;
import org.mapstruct.ap.testutil.WithClasses;
+import org.mapstruct.ap.testutil.runner.GeneratedSource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
@@ -27,6 +28,10 @@ import static org.assertj.core.api.Assertions.entry;
@DefaultLocale("en")
public class NumberFormatConversionTest {
+ @RegisterExtension
+ final GeneratedSource generatedSource = new GeneratedSource()
+ .addComparisonToFixtureFor( SourceTargetMapper.class );
+
@ProcessorTest
public void shouldApplyStringConversions() {
Source source = new Source();
@@ -68,6 +73,47 @@ public class NumberFormatConversionTest {
assertThat( target.getBigInteger1() ).isEqualTo( "1.23456789E12" );
}
+ @ProcessorTest
+ public void shouldApplyStringConversionsWithCustomLocale() {
+ Source source = new Source();
+ source.setI( 1 );
+ source.setIi( 2 );
+ source.setD( 3.0 );
+ source.setDd( 4.0 );
+ source.setF( 3.0f );
+ source.setFf( 4.0f );
+ source.setL( 5L );
+ source.setLl( 6L );
+ source.setB( (byte) 7 );
+ source.setBb( (byte) 8 );
+
+ source.setComplex1( 345346.456756 );
+ source.setComplex2( 5007034.3 );
+
+ source.setBigDecimal1( new BigDecimal( "987E-20" ) );
+ source.setBigInteger1( new BigInteger( "1234567890000" ) );
+
+ Target target = SourceTargetMapper.INSTANCE.sourceToTargetWithCustomLocale( source );
+
+ assertThat( target ).isNotNull();
+ assertThat( target.getI() ).isEqualTo( "1.00" );
+ assertThat( target.getIi() ).isEqualTo( "2.00" );
+ assertThat( target.getD() ).isEqualTo( "3.00" );
+ assertThat( target.getDd() ).isEqualTo( "4.00" );
+ assertThat( target.getF() ).isEqualTo( "3.00" );
+ assertThat( target.getFf() ).isEqualTo( "4.00" );
+ assertThat( target.getL() ).isEqualTo( "5.00" );
+ assertThat( target.getLl() ).isEqualTo( "6.00" );
+ assertThat( target.getB() ).isEqualTo( "7.00" );
+ assertThat( target.getBb() ).isEqualTo( "8.00" );
+
+ assertThat( target.getComplex1() ).isEqualTo( "345.35E3" );
+ assertThat( target.getComplex2() ).isEqualTo( "$5007034.30" );
+
+ assertThat( target.getBigDecimal1() ).isEqualTo( "9,87E-18" );
+ assertThat( target.getBigInteger1() ).isEqualTo( "1,23456789E12" );
+ }
+
@ProcessorTest
public void shouldApplyReverseStringConversions() {
Target target = new Target();
@@ -109,17 +155,73 @@ public class NumberFormatConversionTest {
assertThat( source.getBigInteger1() ).isEqualTo( new BigInteger( "1234567890000" ) );
}
+ @ProcessorTest
+ public void shouldApplyReverseStringConversionsWithCustomLocale() {
+ Target target = new Target();
+ target.setI( "1.00" );
+ target.setIi( "2.00" );
+ target.setD( "3.00" );
+ target.setDd( "4.00" );
+ target.setF( "3.00" );
+ target.setFf( "4.00" );
+ target.setL( "5.00" );
+ target.setLl( "6.00" );
+ target.setB( "7.00" );
+ target.setBb( "8.00" );
+
+ target.setComplex1( "345.35E3" );
+ target.setComplex2( "$5007034.30" );
+
+ target.setBigDecimal1( "9,87E-18" );
+ target.setBigInteger1( "1,23456789E12" );
+
+ Source source = SourceTargetMapper.INSTANCE.targetToSourceWithCustomLocale( target );
+
+ assertThat( source ).isNotNull();
+ assertThat( source.getI() ).isEqualTo( 1 );
+ assertThat( source.getIi() ).isEqualTo( Integer.valueOf( 2 ) );
+ assertThat( source.getD() ).isEqualTo( 3.0 );
+ assertThat( source.getDd() ).isEqualTo( Double.valueOf( 4.0 ) );
+ assertThat( source.getF() ).isEqualTo( 3.0f );
+ assertThat( source.getFf() ).isEqualTo( Float.valueOf( 4.0f ) );
+ assertThat( source.getL() ).isEqualTo( 5L );
+ assertThat( source.getLl() ).isEqualTo( Long.valueOf( 6L ) );
+ assertThat( source.getB() ).isEqualTo( (byte) 7 );
+ assertThat( source.getBb() ).isEqualTo( (byte) 8 );
+
+ assertThat( source.getComplex1() ).isEqualTo( 345350.0 );
+ assertThat( source.getComplex2() ).isEqualTo( 5007034.3 );
+
+ assertThat( source.getBigDecimal1() ).isEqualTo( new BigDecimal( "987E-20" ) );
+ assertThat( source.getBigInteger1() ).isEqualTo( new BigInteger( "1234567890000" ) );
+ }
+
@ProcessorTest
public void shouldApplyStringConversionsToIterables() {
- List target = SourceTargetMapper.INSTANCE.sourceToTarget( Arrays.asList( 2f ) );
+ List target = SourceTargetMapper.INSTANCE.sourceToTarget( List.of( 2f ) );
assertThat( target ).hasSize( 1 );
- assertThat( target ).isEqualTo( Arrays.asList( "2.00" ) );
+ assertThat( target ).isEqualTo( List.of( "2.00" ) );
List source = SourceTargetMapper.INSTANCE.targetToSource( target );
assertThat( source ).hasSize( 1 );
- assertThat( source ).isEqualTo( Arrays.asList( 2.00f ) );
+ assertThat( source ).isEqualTo( List.of( 2.00f ) );
+ }
+
+ @ProcessorTest
+ public void shouldApplyStringConversionsToIterablesWithCustomLocale() {
+
+ List target = SourceTargetMapper.INSTANCE.sourceToTargetWithCustomLocale(
+ List.of( new BigDecimal("987E-20") )
+ );
+
+ assertThat( target ).hasSize( 1 );
+ assertThat( target ).isEqualTo( List.of( "9,87E-18" ) );
+
+ List source = SourceTargetMapper.INSTANCE.targetToSourceWithCustomLocale( target );
+ assertThat( source ).hasSize( 1 );
+ assertThat( source ).isEqualTo( List.of( new BigDecimal("987E-20") ) );
}
@ProcessorTest
@@ -137,4 +239,20 @@ public class NumberFormatConversionTest {
assertThat( source2 ).contains( entry( 1.00f, 2f ) );
}
+
+ @ProcessorTest
+ public void shouldApplyStringConversionsToMapsWithCustomLocale() {
+
+ Map source1 = new HashMap<>();
+ source1.put( new BigDecimal( "987E-20" ), new BigDecimal( "97E-10" ) );
+
+ Map target = SourceTargetMapper.INSTANCE.sourceToTargetWithCustomLocale( source1 );
+ assertThat( target ).hasSize( 1 );
+ assertThat( target ).contains( entry( "9,87E-18", "9,7E-9" ) );
+
+ Map source2 = SourceTargetMapper.INSTANCE.targetToSourceWithCustomLocale( target );
+ assertThat( source2 ).hasSize( 1 );
+ assertThat( source2 ).contains( entry( new BigDecimal( "987E-20" ), new BigDecimal( "97E-10" ) ) );
+
+ }
}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapper.java
index 537452fca..b82a7a619 100644
--- a/processor/src/test/java/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapper.java
+++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapper.java
@@ -5,6 +5,7 @@
*/
package org.mapstruct.ap.test.conversion.numbers;
+import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import org.mapstruct.InheritInverseConfiguration;
@@ -41,21 +42,55 @@ public interface SourceTargetMapper {
} )
Target sourceToTarget(Source source);
- @InheritInverseConfiguration
+ @Mappings( {
+ @Mapping( target = "i", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "ii", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "d", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "dd", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "f", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "ff", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "l", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "ll", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "b", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "bb", numberFormat = NUMBER_FORMAT, locale = "ru" ),
+ @Mapping( target = "complex1", numberFormat = "##0.##E0", locale = "ru" ),
+ @Mapping( target = "complex2", numberFormat = "$#.00", locale = "ru" ),
+ @Mapping( target = "bigDecimal1", numberFormat = "#0.#E0", locale = "ru" ),
+ @Mapping( target = "bigInteger1", numberFormat = "0.#############E0", locale = "ru" )
+
+ } )
+ Target sourceToTargetWithCustomLocale(Source source);
+
+ @InheritInverseConfiguration( name = "sourceToTarget" )
Source targetToSource(Target target);
+ @InheritInverseConfiguration( name = "sourceToTargetWithCustomLocale" )
+ Source targetToSourceWithCustomLocale(Target target);
+
@IterableMapping( numberFormat = NUMBER_FORMAT )
List sourceToTarget(List source);
- @InheritInverseConfiguration
+ @InheritInverseConfiguration( name = "sourceToTarget" )
List targetToSource(List source);
+ @IterableMapping( numberFormat = "#0.#E0", locale = "fr" )
+ List sourceToTargetWithCustomLocale(List source);
+
+ @InheritInverseConfiguration( name = "sourceToTargetWithCustomLocale" )
+ List targetToSourceWithCustomLocale(List source);
+
@MapMapping( keyNumberFormat = NUMBER_FORMAT, valueNumberFormat = "##" )
Map sourceToTarget(Map source);
- @InheritInverseConfiguration
+ @MapMapping( keyNumberFormat = "#0.#E0", valueNumberFormat = "0.#############E0", locale = "fr" )
+ Map sourceToTargetWithCustomLocale(Map source);
+
+ @InheritInverseConfiguration( name = "sourceToTarget" )
Map targetToSource(Map source);
+ @InheritInverseConfiguration( name = "sourceToTargetWithCustomLocale" )
+ Map targetToSourceWithCustomLocale(Map source);
+
}
diff --git a/processor/src/test/resources/fixtures/21/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapperImpl.java b/processor/src/test/resources/fixtures/21/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapperImpl.java
new file mode 100644
index 000000000..ccf8042e6
--- /dev/null
+++ b/processor/src/test/resources/fixtures/21/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapperImpl.java
@@ -0,0 +1,525 @@
+/*
+ * 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.conversion.numbers;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import javax.annotation.processing.Generated;
+
+@Generated(
+ value = "org.mapstruct.ap.MappingProcessor",
+ date = "2024-09-14T11:37:30+0300",
+ comments = "version: , compiler: javac, environment: Java 21.0.2 (Amazon.com Inc.)"
+)
+public class SourceTargetMapperImpl implements SourceTargetMapper {
+
+ @Override
+ public Target sourceToTarget(Source source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Target target = new Target();
+
+ target.setI( new DecimalFormat( "##.00" ).format( source.getI() ) );
+ if ( source.getIi() != null ) {
+ target.setIi( new DecimalFormat( "##.00" ).format( source.getIi() ) );
+ }
+ target.setD( new DecimalFormat( "##.00" ).format( source.getD() ) );
+ if ( source.getDd() != null ) {
+ target.setDd( new DecimalFormat( "##.00" ).format( source.getDd() ) );
+ }
+ target.setF( new DecimalFormat( "##.00" ).format( source.getF() ) );
+ if ( source.getFf() != null ) {
+ target.setFf( new DecimalFormat( "##.00" ).format( source.getFf() ) );
+ }
+ target.setL( new DecimalFormat( "##.00" ).format( source.getL() ) );
+ if ( source.getLl() != null ) {
+ target.setLl( new DecimalFormat( "##.00" ).format( source.getLl() ) );
+ }
+ target.setB( new DecimalFormat( "##.00" ).format( source.getB() ) );
+ if ( source.getBb() != null ) {
+ target.setBb( new DecimalFormat( "##.00" ).format( source.getBb() ) );
+ }
+ target.setComplex1( new DecimalFormat( "##0.##E0" ).format( source.getComplex1() ) );
+ target.setComplex2( new DecimalFormat( "$#.00" ).format( source.getComplex2() ) );
+ if ( source.getBigDecimal1() != null ) {
+ target.setBigDecimal1( createDecimalFormat( "#0.#E0" ).format( source.getBigDecimal1() ) );
+ }
+ if ( source.getBigInteger1() != null ) {
+ target.setBigInteger1( createDecimalFormat( "0.#############E0" ).format( source.getBigInteger1() ) );
+ }
+
+ return target;
+ }
+
+ @Override
+ public Target sourceToTargetWithCustomLocale(Source source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Target target = new Target();
+
+ target.setI( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getI() ) );
+ if ( source.getIi() != null ) {
+ target.setIi( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getIi() ) );
+ }
+ target.setD( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getD() ) );
+ if ( source.getDd() != null ) {
+ target.setDd( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getDd() ) );
+ }
+ target.setF( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getF() ) );
+ if ( source.getFf() != null ) {
+ target.setFf( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getFf() ) );
+ }
+ target.setL( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getL() ) );
+ if ( source.getLl() != null ) {
+ target.setLl( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getLl() ) );
+ }
+ target.setB( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getB() ) );
+ if ( source.getBb() != null ) {
+ target.setBb( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getBb() ) );
+ }
+ target.setComplex1( new DecimalFormat( "##0.##E0", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getComplex1() ) );
+ target.setComplex2( new DecimalFormat( "$#.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getComplex2() ) );
+ if ( source.getBigDecimal1() != null ) {
+ target.setBigDecimal1( createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "ru" ) ).format( source.getBigDecimal1() ) );
+ }
+ if ( source.getBigInteger1() != null ) {
+ target.setBigInteger1( createDecimalFormatWithLocale( "0.#############E0", Locale.forLanguageTag( "ru" ) ).format( source.getBigInteger1() ) );
+ }
+
+ return target;
+ }
+
+ @Override
+ public Source targetToSource(Target target) {
+ if ( target == null ) {
+ return null;
+ }
+
+ Source source = new Source();
+
+ try {
+ if ( target.getI() != null ) {
+ source.setI( new DecimalFormat( "##.00" ).parse( target.getI() ).intValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getIi() != null ) {
+ source.setIi( new DecimalFormat( "##.00" ).parse( target.getIi() ).intValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getD() != null ) {
+ source.setD( new DecimalFormat( "##.00" ).parse( target.getD() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getDd() != null ) {
+ source.setDd( new DecimalFormat( "##.00" ).parse( target.getDd() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getF() != null ) {
+ source.setF( new DecimalFormat( "##.00" ).parse( target.getF() ).floatValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getFf() != null ) {
+ source.setFf( new DecimalFormat( "##.00" ).parse( target.getFf() ).floatValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getL() != null ) {
+ source.setL( new DecimalFormat( "##.00" ).parse( target.getL() ).longValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getLl() != null ) {
+ source.setLl( new DecimalFormat( "##.00" ).parse( target.getLl() ).longValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getB() != null ) {
+ source.setB( new DecimalFormat( "##.00" ).parse( target.getB() ).byteValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBb() != null ) {
+ source.setBb( new DecimalFormat( "##.00" ).parse( target.getBb() ).byteValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getComplex1() != null ) {
+ source.setComplex1( new DecimalFormat( "##0.##E0" ).parse( target.getComplex1() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getComplex2() != null ) {
+ source.setComplex2( new DecimalFormat( "$#.00" ).parse( target.getComplex2() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBigDecimal1() != null ) {
+ source.setBigDecimal1( (BigDecimal) createDecimalFormat( "#0.#E0" ).parse( target.getBigDecimal1() ) );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBigInteger1() != null ) {
+ source.setBigInteger1( ( (BigDecimal) createDecimalFormat( "0.#############E0" ).parse( target.getBigInteger1() ) ).toBigInteger() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+
+ return source;
+ }
+
+ @Override
+ public Source targetToSourceWithCustomLocale(Target target) {
+ if ( target == null ) {
+ return null;
+ }
+
+ Source source = new Source();
+
+ try {
+ if ( target.getI() != null ) {
+ source.setI( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getI() ).intValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getIi() != null ) {
+ source.setIi( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getIi() ).intValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getD() != null ) {
+ source.setD( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getD() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getDd() != null ) {
+ source.setDd( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getDd() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getF() != null ) {
+ source.setF( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getF() ).floatValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getFf() != null ) {
+ source.setFf( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getFf() ).floatValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getL() != null ) {
+ source.setL( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getL() ).longValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getLl() != null ) {
+ source.setLl( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getLl() ).longValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getB() != null ) {
+ source.setB( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getB() ).byteValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBb() != null ) {
+ source.setBb( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getBb() ).byteValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getComplex1() != null ) {
+ source.setComplex1( new DecimalFormat( "##0.##E0", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getComplex1() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getComplex2() != null ) {
+ source.setComplex2( new DecimalFormat( "$#.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getComplex2() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBigDecimal1() != null ) {
+ source.setBigDecimal1( (BigDecimal) createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "ru" ) ).parse( target.getBigDecimal1() ) );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBigInteger1() != null ) {
+ source.setBigInteger1( ( (BigDecimal) createDecimalFormatWithLocale( "0.#############E0", Locale.forLanguageTag( "ru" ) ).parse( target.getBigInteger1() ) ).toBigInteger() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+
+ return source;
+ }
+
+ @Override
+ public List sourceToTarget(List source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ List list = new ArrayList( source.size() );
+ for ( Float float1 : source ) {
+ list.add( new DecimalFormat( "##.00" ).format( float1 ) );
+ }
+
+ return list;
+ }
+
+ @Override
+ public List targetToSource(List source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ List list = new ArrayList( source.size() );
+ for ( String string : source ) {
+ try {
+ list.add( new DecimalFormat( "##.00" ).parse( string ).floatValue() );
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ return list;
+ }
+
+ @Override
+ public List sourceToTargetWithCustomLocale(List source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ List list = new ArrayList( source.size() );
+ for ( BigDecimal bigDecimal : source ) {
+ list.add( createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "fr" ) ).format( bigDecimal ) );
+ }
+
+ return list;
+ }
+
+ @Override
+ public List targetToSourceWithCustomLocale(List source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ List list = new ArrayList( source.size() );
+ for ( String string : source ) {
+ try {
+ list.add( (BigDecimal) createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "fr" ) ).parse( string ) );
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ return list;
+ }
+
+ @Override
+ public Map sourceToTarget(Map source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Map map = LinkedHashMap.newLinkedHashMap( source.size() );
+
+ for ( java.util.Map.Entry entry : source.entrySet() ) {
+ String key = new DecimalFormat( "##.00" ).format( entry.getKey() );
+ String value = new DecimalFormat( "##" ).format( entry.getValue() );
+ map.put( key, value );
+ }
+
+ return map;
+ }
+
+ @Override
+ public Map sourceToTargetWithCustomLocale(Map source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Map map = LinkedHashMap.newLinkedHashMap( source.size() );
+
+ for ( java.util.Map.Entry entry : source.entrySet() ) {
+ String key = createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "fr" ) ).format( entry.getKey() );
+ String value = createDecimalFormatWithLocale( "0.#############E0", Locale.forLanguageTag( "fr" ) ).format( entry.getValue() );
+ map.put( key, value );
+ }
+
+ return map;
+ }
+
+ @Override
+ public Map targetToSource(Map source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Map map = LinkedHashMap.newLinkedHashMap( source.size() );
+
+ for ( java.util.Map.Entry entry : source.entrySet() ) {
+ Float key;
+ try {
+ key = new DecimalFormat( "##.00" ).parse( entry.getKey() ).floatValue();
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ Float value;
+ try {
+ value = new DecimalFormat( "##" ).parse( entry.getValue() ).floatValue();
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ map.put( key, value );
+ }
+
+ return map;
+ }
+
+ @Override
+ public Map targetToSourceWithCustomLocale(Map source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Map map = LinkedHashMap.newLinkedHashMap( source.size() );
+
+ for ( java.util.Map.Entry entry : source.entrySet() ) {
+ BigDecimal key;
+ try {
+ key = (BigDecimal) createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "fr" ) ).parse( entry.getKey() );
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ BigDecimal value;
+ try {
+ value = (BigDecimal) createDecimalFormatWithLocale( "0.#############E0", Locale.forLanguageTag( "fr" ) ).parse( entry.getValue() );
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ map.put( key, value );
+ }
+
+ return map;
+ }
+
+ private DecimalFormat createDecimalFormatWithLocale( String numberFormat, Locale locale ) {
+
+ DecimalFormat df = new DecimalFormat( numberFormat, DecimalFormatSymbols.getInstance( locale ) );
+ df.setParseBigDecimal( true );
+ return df;
+ }
+
+ private DecimalFormat createDecimalFormat( String numberFormat ) {
+
+ DecimalFormat df = new DecimalFormat( numberFormat );
+ df.setParseBigDecimal( true );
+ return df;
+ }
+}
diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapperImpl.java
new file mode 100644
index 000000000..0b536b832
--- /dev/null
+++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/conversion/numbers/SourceTargetMapperImpl.java
@@ -0,0 +1,525 @@
+/*
+ * 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.conversion.numbers;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import javax.annotation.processing.Generated;
+
+@Generated(
+ value = "org.mapstruct.ap.MappingProcessor",
+ date = "2024-09-14T11:36:20+0300",
+ comments = "version: , compiler: javac, environment: Java 17.0.10 (Private Build)"
+)
+public class SourceTargetMapperImpl implements SourceTargetMapper {
+
+ @Override
+ public Target sourceToTarget(Source source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Target target = new Target();
+
+ target.setI( new DecimalFormat( "##.00" ).format( source.getI() ) );
+ if ( source.getIi() != null ) {
+ target.setIi( new DecimalFormat( "##.00" ).format( source.getIi() ) );
+ }
+ target.setD( new DecimalFormat( "##.00" ).format( source.getD() ) );
+ if ( source.getDd() != null ) {
+ target.setDd( new DecimalFormat( "##.00" ).format( source.getDd() ) );
+ }
+ target.setF( new DecimalFormat( "##.00" ).format( source.getF() ) );
+ if ( source.getFf() != null ) {
+ target.setFf( new DecimalFormat( "##.00" ).format( source.getFf() ) );
+ }
+ target.setL( new DecimalFormat( "##.00" ).format( source.getL() ) );
+ if ( source.getLl() != null ) {
+ target.setLl( new DecimalFormat( "##.00" ).format( source.getLl() ) );
+ }
+ target.setB( new DecimalFormat( "##.00" ).format( source.getB() ) );
+ if ( source.getBb() != null ) {
+ target.setBb( new DecimalFormat( "##.00" ).format( source.getBb() ) );
+ }
+ target.setComplex1( new DecimalFormat( "##0.##E0" ).format( source.getComplex1() ) );
+ target.setComplex2( new DecimalFormat( "$#.00" ).format( source.getComplex2() ) );
+ if ( source.getBigDecimal1() != null ) {
+ target.setBigDecimal1( createDecimalFormat( "#0.#E0" ).format( source.getBigDecimal1() ) );
+ }
+ if ( source.getBigInteger1() != null ) {
+ target.setBigInteger1( createDecimalFormat( "0.#############E0" ).format( source.getBigInteger1() ) );
+ }
+
+ return target;
+ }
+
+ @Override
+ public Target sourceToTargetWithCustomLocale(Source source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Target target = new Target();
+
+ target.setI( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getI() ) );
+ if ( source.getIi() != null ) {
+ target.setIi( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getIi() ) );
+ }
+ target.setD( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getD() ) );
+ if ( source.getDd() != null ) {
+ target.setDd( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getDd() ) );
+ }
+ target.setF( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getF() ) );
+ if ( source.getFf() != null ) {
+ target.setFf( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getFf() ) );
+ }
+ target.setL( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getL() ) );
+ if ( source.getLl() != null ) {
+ target.setLl( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getLl() ) );
+ }
+ target.setB( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getB() ) );
+ if ( source.getBb() != null ) {
+ target.setBb( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getBb() ) );
+ }
+ target.setComplex1( new DecimalFormat( "##0.##E0", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getComplex1() ) );
+ target.setComplex2( new DecimalFormat( "$#.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).format( source.getComplex2() ) );
+ if ( source.getBigDecimal1() != null ) {
+ target.setBigDecimal1( createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "ru" ) ).format( source.getBigDecimal1() ) );
+ }
+ if ( source.getBigInteger1() != null ) {
+ target.setBigInteger1( createDecimalFormatWithLocale( "0.#############E0", Locale.forLanguageTag( "ru" ) ).format( source.getBigInteger1() ) );
+ }
+
+ return target;
+ }
+
+ @Override
+ public Source targetToSource(Target target) {
+ if ( target == null ) {
+ return null;
+ }
+
+ Source source = new Source();
+
+ try {
+ if ( target.getI() != null ) {
+ source.setI( new DecimalFormat( "##.00" ).parse( target.getI() ).intValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getIi() != null ) {
+ source.setIi( new DecimalFormat( "##.00" ).parse( target.getIi() ).intValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getD() != null ) {
+ source.setD( new DecimalFormat( "##.00" ).parse( target.getD() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getDd() != null ) {
+ source.setDd( new DecimalFormat( "##.00" ).parse( target.getDd() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getF() != null ) {
+ source.setF( new DecimalFormat( "##.00" ).parse( target.getF() ).floatValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getFf() != null ) {
+ source.setFf( new DecimalFormat( "##.00" ).parse( target.getFf() ).floatValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getL() != null ) {
+ source.setL( new DecimalFormat( "##.00" ).parse( target.getL() ).longValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getLl() != null ) {
+ source.setLl( new DecimalFormat( "##.00" ).parse( target.getLl() ).longValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getB() != null ) {
+ source.setB( new DecimalFormat( "##.00" ).parse( target.getB() ).byteValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBb() != null ) {
+ source.setBb( new DecimalFormat( "##.00" ).parse( target.getBb() ).byteValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getComplex1() != null ) {
+ source.setComplex1( new DecimalFormat( "##0.##E0" ).parse( target.getComplex1() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getComplex2() != null ) {
+ source.setComplex2( new DecimalFormat( "$#.00" ).parse( target.getComplex2() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBigDecimal1() != null ) {
+ source.setBigDecimal1( (BigDecimal) createDecimalFormat( "#0.#E0" ).parse( target.getBigDecimal1() ) );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBigInteger1() != null ) {
+ source.setBigInteger1( ( (BigDecimal) createDecimalFormat( "0.#############E0" ).parse( target.getBigInteger1() ) ).toBigInteger() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+
+ return source;
+ }
+
+ @Override
+ public Source targetToSourceWithCustomLocale(Target target) {
+ if ( target == null ) {
+ return null;
+ }
+
+ Source source = new Source();
+
+ try {
+ if ( target.getI() != null ) {
+ source.setI( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getI() ).intValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getIi() != null ) {
+ source.setIi( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getIi() ).intValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getD() != null ) {
+ source.setD( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getD() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getDd() != null ) {
+ source.setDd( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getDd() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getF() != null ) {
+ source.setF( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getF() ).floatValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getFf() != null ) {
+ source.setFf( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getFf() ).floatValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getL() != null ) {
+ source.setL( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getL() ).longValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getLl() != null ) {
+ source.setLl( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getLl() ).longValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getB() != null ) {
+ source.setB( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getB() ).byteValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBb() != null ) {
+ source.setBb( new DecimalFormat( "##.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getBb() ).byteValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getComplex1() != null ) {
+ source.setComplex1( new DecimalFormat( "##0.##E0", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getComplex1() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getComplex2() != null ) {
+ source.setComplex2( new DecimalFormat( "$#.00", DecimalFormatSymbols.getInstance( Locale.forLanguageTag( "ru " ) ) ).parse( target.getComplex2() ).doubleValue() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBigDecimal1() != null ) {
+ source.setBigDecimal1( (BigDecimal) createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "ru" ) ).parse( target.getBigDecimal1() ) );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ try {
+ if ( target.getBigInteger1() != null ) {
+ source.setBigInteger1( ( (BigDecimal) createDecimalFormatWithLocale( "0.#############E0", Locale.forLanguageTag( "ru" ) ).parse( target.getBigInteger1() ) ).toBigInteger() );
+ }
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+
+ return source;
+ }
+
+ @Override
+ public List sourceToTarget(List source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ List list = new ArrayList( source.size() );
+ for ( Float float1 : source ) {
+ list.add( new DecimalFormat( "##.00" ).format( float1 ) );
+ }
+
+ return list;
+ }
+
+ @Override
+ public List targetToSource(List source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ List list = new ArrayList( source.size() );
+ for ( String string : source ) {
+ try {
+ list.add( new DecimalFormat( "##.00" ).parse( string ).floatValue() );
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ return list;
+ }
+
+ @Override
+ public List sourceToTargetWithCustomLocale(List source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ List list = new ArrayList( source.size() );
+ for ( BigDecimal bigDecimal : source ) {
+ list.add( createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "fr" ) ).format( bigDecimal ) );
+ }
+
+ return list;
+ }
+
+ @Override
+ public List targetToSourceWithCustomLocale(List source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ List list = new ArrayList( source.size() );
+ for ( String string : source ) {
+ try {
+ list.add( (BigDecimal) createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "fr" ) ).parse( string ) );
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ return list;
+ }
+
+ @Override
+ public Map sourceToTarget(Map source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Map map = new LinkedHashMap( Math.max( (int) ( source.size() / .75f ) + 1, 16 ) );
+
+ for ( java.util.Map.Entry entry : source.entrySet() ) {
+ String key = new DecimalFormat( "##.00" ).format( entry.getKey() );
+ String value = new DecimalFormat( "##" ).format( entry.getValue() );
+ map.put( key, value );
+ }
+
+ return map;
+ }
+
+ @Override
+ public Map sourceToTargetWithCustomLocale(Map source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Map map = new LinkedHashMap( Math.max( (int) ( source.size() / .75f ) + 1, 16 ) );
+
+ for ( java.util.Map.Entry entry : source.entrySet() ) {
+ String key = createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "fr" ) ).format( entry.getKey() );
+ String value = createDecimalFormatWithLocale( "0.#############E0", Locale.forLanguageTag( "fr" ) ).format( entry.getValue() );
+ map.put( key, value );
+ }
+
+ return map;
+ }
+
+ @Override
+ public Map targetToSource(Map source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Map map = new LinkedHashMap( Math.max( (int) ( source.size() / .75f ) + 1, 16 ) );
+
+ for ( java.util.Map.Entry entry : source.entrySet() ) {
+ Float key;
+ try {
+ key = new DecimalFormat( "##.00" ).parse( entry.getKey() ).floatValue();
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ Float value;
+ try {
+ value = new DecimalFormat( "##" ).parse( entry.getValue() ).floatValue();
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ map.put( key, value );
+ }
+
+ return map;
+ }
+
+ @Override
+ public Map targetToSourceWithCustomLocale(Map source) {
+ if ( source == null ) {
+ return null;
+ }
+
+ Map map = new LinkedHashMap( Math.max( (int) ( source.size() / .75f ) + 1, 16 ) );
+
+ for ( java.util.Map.Entry entry : source.entrySet() ) {
+ BigDecimal key;
+ try {
+ key = (BigDecimal) createDecimalFormatWithLocale( "#0.#E0", Locale.forLanguageTag( "fr" ) ).parse( entry.getKey() );
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ BigDecimal value;
+ try {
+ value = (BigDecimal) createDecimalFormatWithLocale( "0.#############E0", Locale.forLanguageTag( "fr" ) ).parse( entry.getValue() );
+ }
+ catch ( ParseException e ) {
+ throw new RuntimeException( e );
+ }
+ map.put( key, value );
+ }
+
+ return map;
+ }
+
+ private DecimalFormat createDecimalFormatWithLocale( String numberFormat, Locale locale ) {
+
+ DecimalFormat df = new DecimalFormat( numberFormat, DecimalFormatSymbols.getInstance( locale ) );
+ df.setParseBigDecimal( true );
+ return df;
+ }
+
+ private DecimalFormat createDecimalFormat( String numberFormat ) {
+
+ DecimalFormat df = new DecimalFormat( numberFormat );
+ df.setParseBigDecimal( true );
+ return df;
+ }
+}