Browse Source

Add option to use error message provider for StringTo converters (#10711)

tags/8.4.0.alpha1
Teemu Suo-Anttila 6 years ago
parent
commit
0a3e1640c6

+ 30
- 10
server/src/main/java/com/vaadin/data/converter/AbstractStringToNumberConverter.java View File

@@ -21,6 +21,7 @@ import java.text.ParsePosition;
import java.util.Locale;

import com.vaadin.data.Converter;
import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;

@@ -39,9 +40,27 @@ 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.
@@ -54,8 +73,7 @@ public abstract class AbstractStringToNumberConverter<T extends Number>
*/
protected AbstractStringToNumberConverter(T emptyValue,
String errorMessage) {
this.emptyValue = emptyValue;
this.errorMessage = errorMessage;
this(emptyValue, ctx -> errorMessage);
}

/**
@@ -81,11 +99,12 @@ public abstract class AbstractStringToNumberConverter<T extends Number>
*
* @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);
}
@@ -96,9 +115,10 @@ public abstract class AbstractStringToNumberConverter<T extends Number>
// 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) {
@@ -114,8 +134,8 @@ public abstract class AbstractStringToNumberConverter<T extends Number>
*
* @return the error message
*/
protected String getErrorMessage() {
return errorMessage;
protected String getErrorMessage(ValueContext context) {
return errorMessageProvider.apply(context);
}

@Override

+ 33
- 1
server/src/main/java/com/vaadin/data/converter/StringToBigDecimalConverter.java View File

@@ -20,6 +20,7 @@ import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;

import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;

@@ -66,6 +67,37 @@ public class StringToBigDecimalConverter
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);
@@ -79,7 +111,7 @@ public class StringToBigDecimalConverter
@Override
public Result<BigDecimal> convertToModel(String value,
ValueContext context) {
return convertToNumber(value, context.getLocale().orElse(null))
return convertToNumber(value, context)
.map(number -> (BigDecimal) number);
}


+ 42
- 11
server/src/main/java/com/vaadin/data/converter/StringToBigIntegerConverter.java View File

@@ -21,6 +21,7 @@ import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;

import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;

@@ -67,6 +68,37 @@ public class StringToBigIntegerConverter
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);
@@ -80,17 +112,16 @@ public class StringToBigIntegerConverter
@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();
});
}

}

+ 37
- 4
server/src/main/java/com/vaadin/data/converter/StringToBooleanConverter.java View File

@@ -19,13 +19,15 @@ package com.vaadin.data.converter;
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>
@@ -43,7 +45,7 @@ public class StringToBooleanConverter implements Converter<String, Boolean> {

private final String falseString;

private String errorMessage;
private ErrorMessageProvider errorMessageProvider;

/**
* Creates converter with default string representations - "true" and
@@ -56,6 +58,20 @@ public class StringToBooleanConverter implements Converter<String, Boolean> {
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.
*
@@ -68,7 +84,24 @@ public class StringToBooleanConverter implements Converter<String, Boolean> {
*/
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;
}
@@ -90,7 +123,7 @@ public class StringToBooleanConverter implements Converter<String, Boolean> {
} else if (value.isEmpty()) {
return Result.ok(null);
} else {
return Result.error(errorMessage);
return Result.error(errorMessageProvider.apply(context));
}
}


+ 32
- 2
server/src/main/java/com/vaadin/data/converter/StringToDoubleConverter.java View File

@@ -19,6 +19,7 @@ package com.vaadin.data.converter;
import java.text.NumberFormat;
import java.util.Locale;

import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;

@@ -64,10 +65,39 @@ public class StringToDoubleConverter
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) {

+ 32
- 2
server/src/main/java/com/vaadin/data/converter/StringToFloatConverter.java View File

@@ -19,6 +19,7 @@ package com.vaadin.data.converter;
import java.text.NumberFormat;
import java.util.Locale;

import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;

@@ -62,10 +63,39 @@ public class StringToFloatConverter
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) {

+ 33
- 3
server/src/main/java/com/vaadin/data/converter/StringToIntegerConverter.java View File

@@ -19,6 +19,7 @@ package com.vaadin.data.converter;
import java.text.NumberFormat;
import java.util.Locale;

import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;

@@ -61,6 +62,36 @@ public class StringToIntegerConverter
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
@@ -80,8 +111,7 @@ public class StringToIntegerConverter

@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);
@@ -94,7 +124,7 @@ public class StringToIntegerConverter
// long and thus does not need to consider wrap-around.
return Result.ok(intValue);
}
return Result.error(getErrorMessage());
return Result.error(getErrorMessage(context));
});
}


+ 32
- 2
server/src/main/java/com/vaadin/data/converter/StringToLongConverter.java View File

@@ -19,6 +19,7 @@ package com.vaadin.data.converter;
import java.text.NumberFormat;
import java.util.Locale;

import com.vaadin.data.ErrorMessageProvider;
import com.vaadin.data.Result;
import com.vaadin.data.ValueContext;

@@ -61,6 +62,36 @@ public class StringToLongConverter
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
@@ -80,8 +111,7 @@ public class StringToLongConverter

@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;

+ 23
- 0
server/src/test/java/com/vaadin/data/BinderTest.java View File

@@ -1102,4 +1102,27 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> {
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());
}
}

Loading…
Cancel
Save