import java.util.Locale;
import com.vaadin.data.Converter;
+import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;
public abstract class AbstractStringToNumberConverter<T extends Number>
implements Converter<String, T> {
- private final String errorMessage;
+ private final ErrorMessageProvider errorMessageProvider;
private T emptyValue;
+ /**
+ * Creates a new converter instance with the given empty string value and
+ * error message provider.
+ *
+ * @param emptyValue
+ * the presentation value to return when converting an empty
+ * string, may be <code>null</code>
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ protected AbstractStringToNumberConverter(T emptyValue,
+ ErrorMessageProvider errorMessageProvider) {
+ this.emptyValue = emptyValue;
+ this.errorMessageProvider = errorMessageProvider;
+ }
+
/**
* Creates a new converter instance with the given empty string value and
* error message.
*/
protected AbstractStringToNumberConverter(T emptyValue,
String errorMessage) {
- this.emptyValue = emptyValue;
- this.errorMessage = errorMessage;
+ this(emptyValue, ctx -> errorMessage);
}
/**
*
* @param value
* The value to convert
- * @param locale
- * The locale to use for conversion
+ * @param context
+ * The value context for conversion
* @return The converted value
*/
- protected Result<Number> convertToNumber(String value, Locale locale) {
+ protected Result<Number> convertToNumber(String value,
+ ValueContext context) {
if (value == null) {
return Result.ok(null);
}
// Parse and detect errors. If the full string was not used, it is
// an error.
ParsePosition parsePosition = new ParsePosition(0);
- Number parsedValue = getFormat(locale).parse(value, parsePosition);
+ Number parsedValue = getFormat(context.getLocale().orElse(null))
+ .parse(value, parsePosition);
if (parsePosition.getIndex() != value.length()) {
- return Result.error(getErrorMessage());
+ return Result.error(getErrorMessage(context));
}
if (parsedValue == null) {
*
* @return the error message
*/
- protected String getErrorMessage() {
- return errorMessage;
+ protected String getErrorMessage(ValueContext context) {
+ return errorMessageProvider.apply(context);
}
@Override
import java.text.NumberFormat;
import java.util.Locale;
+import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;
super(emptyValue, errorMessage);
}
+ /**
+ * Creates a new converter instance with the given error message provider.
+ * Empty strings are converted to <code>null</code>.
+ *
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToBigDecimalConverter(
+ ErrorMessageProvider errorMessageProvider) {
+ this(null, errorMessageProvider);
+ }
+
+ /**
+ * Creates a new converter instance with the given empty string value and
+ * error message provider.
+ *
+ * @param emptyValue
+ * the presentation value to return when converting an empty
+ * string, may be <code>null</code>
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToBigDecimalConverter(BigDecimal emptyValue,
+ ErrorMessageProvider errorMessageProvider) {
+ super(emptyValue, errorMessageProvider);
+ }
+
@Override
protected NumberFormat getFormat(Locale locale) {
NumberFormat numberFormat = super.getFormat(locale);
@Override
public Result<BigDecimal> convertToModel(String value,
ValueContext context) {
- return convertToNumber(value, context.getLocale().orElse(null))
+ return convertToNumber(value, context)
.map(number -> (BigDecimal) number);
}
import java.text.NumberFormat;
import java.util.Locale;
+import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;
super(emptyValue, errorMessage);
}
+ /**
+ * Creates a new converter instance with the given error message provider.
+ * Empty strings are converted to <code>null</code>.
+ *
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToBigIntegerConverter(
+ ErrorMessageProvider errorMessageProvider) {
+ this(null, errorMessageProvider);
+ }
+
+ /**
+ * Creates a new converter instance with the given empty string value and
+ * error message provider.
+ *
+ * @param emptyValue
+ * the presentation value to return when converting an empty
+ * string, may be <code>null</code>
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToBigIntegerConverter(BigInteger emptyValue,
+ ErrorMessageProvider errorMessageProvider) {
+ super(emptyValue, errorMessageProvider);
+ }
+
@Override
protected NumberFormat getFormat(Locale locale) {
NumberFormat numberFormat = super.getFormat(locale);
@Override
public Result<BigInteger> convertToModel(String value,
ValueContext context) {
- return convertToNumber(value, context.getLocale().orElse(null))
- .map(number -> {
- if (number == null) {
- return null;
- }
- // Empty value will be a BigInteger
- if (number instanceof BigInteger) {
- return (BigInteger) number;
- }
- return ((BigDecimal) number).toBigInteger();
- });
+ return convertToNumber(value, context).map(number -> {
+ if (number == null) {
+ return null;
+ }
+ // Empty value will be a BigInteger
+ if (number instanceof BigInteger) {
+ return (BigInteger) number;
+ }
+ return ((BigDecimal) number).toBigInteger();
+ });
}
}
import java.util.Locale;
import com.vaadin.data.Converter;
+import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;
/**
* A converter that converts from {@link String} to {@link Boolean} and back.
* The String representation is given by {@link Boolean#toString()} or provided
- * in constructor {@link StringToBooleanConverter#StringToBooleanConverter(String, String, String)}.
+ * in constructor
+ * {@link StringToBooleanConverter#StringToBooleanConverter(String, String, String)}.
* <p>
* Leading and trailing white spaces are ignored when converting from a String.
* </p>
private final String falseString;
- private String errorMessage;
+ private ErrorMessageProvider errorMessageProvider;
/**
* Creates converter with default string representations - "true" and
this(errorMessage, Boolean.TRUE.toString(), Boolean.FALSE.toString());
}
+ /**
+ * Creates a new converter instance with the given error message provider.
+ * Empty strings are converted to <code>null</code>.
+ *
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToBooleanConverter(ErrorMessageProvider errorMessageProvider) {
+ this(Boolean.TRUE.toString(), Boolean.FALSE.toString(),
+ errorMessageProvider);
+ }
+
/**
* Creates converter with custom string representation.
*
*/
public StringToBooleanConverter(String errorMessage, String trueString,
String falseString) {
- this.errorMessage = errorMessage;
+ this(trueString, falseString, ctx -> errorMessage);
+ }
+
+ /**
+ * Creates converter with custom string representation.
+ *
+ * @param falseString
+ * string representation for <code>false</code>
+ * @param trueString
+ * string representation for <code>true</code>
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToBooleanConverter(String trueString, String falseString,
+ ErrorMessageProvider errorMessageProvider) {
+ this.errorMessageProvider = errorMessageProvider;
this.trueString = trueString;
this.falseString = falseString;
}
} else if (value.isEmpty()) {
return Result.ok(null);
} else {
- return Result.error(errorMessage);
+ return Result.error(errorMessageProvider.apply(context));
}
}
import java.text.NumberFormat;
import java.util.Locale;
+import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;
super(emptyValue, errorMessage);
}
+ /**
+ * Creates a new converter instance with the given error message provider.
+ * Empty strings are converted to <code>null</code>.
+ *
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToDoubleConverter(ErrorMessageProvider errorMessageProvider) {
+ this(null, errorMessageProvider);
+ }
+
+ /**
+ * Creates a new converter instance with the given empty string value and
+ * error message provider.
+ *
+ * @param emptyValue
+ * the presentation value to return when converting an empty
+ * string, may be <code>null</code>
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToDoubleConverter(Double emptyValue,
+ ErrorMessageProvider errorMessageProvider) {
+ super(emptyValue, errorMessageProvider);
+ }
+
@Override
public Result<Double> convertToModel(String value, ValueContext context) {
- Result<Number> n = convertToNumber(value,
- context.getLocale().orElse(null));
+ Result<Number> n = convertToNumber(value, context);
return n.map(number -> {
if (number == null) {
import java.text.NumberFormat;
import java.util.Locale;
+import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;
super(emptyValue, errorMessage);
}
+ /**
+ * Creates a new converter instance with the given error message provider.
+ * Empty strings are converted to <code>null</code>.
+ *
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToFloatConverter(ErrorMessageProvider errorMessageProvider) {
+ this(null, errorMessageProvider);
+ }
+
+ /**
+ * Creates a new converter instance with the given empty string value and
+ * error message provider.
+ *
+ * @param emptyValue
+ * the presentation value to return when converting an empty
+ * string, may be <code>null</code>
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToFloatConverter(Float emptyValue,
+ ErrorMessageProvider errorMessageProvider) {
+ super(emptyValue, errorMessageProvider);
+ }
+
@Override
public Result<Float> convertToModel(String value, ValueContext context) {
- Result<Number> n = convertToNumber(value,
- context.getLocale().orElse(null));
+ Result<Number> n = convertToNumber(value, context);
return n.map(number -> {
if (number == null) {
import java.text.NumberFormat;
import java.util.Locale;
+import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;
super(emptyValue, errorMessage);
}
+ /**
+ * Creates a new converter instance with the given error message provider.
+ * Empty strings are converted to <code>null</code>.
+ *
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToIntegerConverter(ErrorMessageProvider errorMessageProvider) {
+ this(null, errorMessageProvider);
+ }
+
+ /**
+ * Creates a new converter instance with the given empty string value and
+ * error message provider.
+ *
+ * @param emptyValue
+ * the presentation value to return when converting an empty
+ * string, may be <code>null</code>
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToIntegerConverter(Integer emptyValue,
+ ErrorMessageProvider errorMessageProvider) {
+ super(emptyValue, errorMessageProvider);
+ }
+
/**
* Returns the format used by
* {@link #convertToPresentation(Object, ValueContext)} and
@Override
public Result<Integer> convertToModel(String value, ValueContext context) {
- Result<Number> n = convertToNumber(value,
- context.getLocale().orElse(null));
+ Result<Number> n = convertToNumber(value, context);
return n.flatMap(number -> {
if (number == null) {
return Result.ok(null);
// long and thus does not need to consider wrap-around.
return Result.ok(intValue);
}
- return Result.error(getErrorMessage());
+ return Result.error(getErrorMessage(context));
});
}
import java.text.NumberFormat;
import java.util.Locale;
+import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;
super(emptyValue, errorMessage);
}
+ /**
+ * Creates a new converter instance with the given error message provider.
+ * Empty strings are converted to <code>null</code>.
+ *
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToLongConverter(ErrorMessageProvider errorMessageProvider) {
+ this(null, errorMessageProvider);
+ }
+
+ /**
+ * Creates a new converter instance with the given empty string value and
+ * error message provider.
+ *
+ * @param emptyValue
+ * the presentation value to return when converting an empty
+ * string, may be <code>null</code>
+ * @param errorMessageProvider
+ * the error message provider to use if conversion fails
+ *
+ * @since
+ */
+ public StringToLongConverter(Long emptyValue,
+ ErrorMessageProvider errorMessageProvider) {
+ super(emptyValue, errorMessageProvider);
+ }
+
/**
* Returns the format used by
* {@link #convertToPresentation(Object, ValueContext)} and
@Override
public Result<Long> convertToModel(String value, ValueContext context) {
- Result<Number> n = convertToNumber(value,
- context.getLocale().orElse(null));
+ Result<Number> n = convertToNumber(value, context);
return n.map(number -> {
if (number == null) {
return null;
assertTrue("Binding should be readonly", binding.isReadOnly());
assertTrue("Name field should be readonly", nameField.isReadOnly());
}
+
+ @Test
+ public void conversionWithLocaleBasedErrorMessage() {
+ String fiError = "VIRHE";
+ String otherError = "ERROR";
+
+ binder.forField(ageField).withConverter(new StringToIntegerConverter(
+ context -> context.getLocale().map(Locale::getLanguage)
+ .orElse("en").equals("fi") ? fiError : otherError))
+ .bind(Person::getAge, Person::setAge);
+
+ binder.setBean(item);
+
+ ageField.setValue("not a number");
+
+ assertEquals(otherError,
+ ageField.getErrorMessage().getFormattedHtmlMessage());
+ ageField.setLocale(new Locale("fi"));
+ // Re-validate to get the error message with correct locale
+ binder.validate();
+ assertEquals(fiError,
+ ageField.getErrorMessage().getFormattedHtmlMessage());
+ }
}