diff options
Diffstat (limited to 'server')
7 files changed, 337 insertions, 16 deletions
diff --git a/server/src/com/vaadin/data/util/converter/ConverterUtil.java b/server/src/com/vaadin/data/util/converter/ConverterUtil.java index 61d155bc9a..08d7363084 100644 --- a/server/src/com/vaadin/data/util/converter/ConverterUtil.java +++ b/server/src/com/vaadin/data/util/converter/ConverterUtil.java @@ -151,10 +151,14 @@ public class ConverterUtil implements Serializable { /** * Checks if the given converter can handle conversion between the given - * presentation and model type + * presentation and model type. Does strict type checking and only returns + * true if the converter claims it can handle exactly the given types. + * + * @see #canConverterPossiblyHandle(Converter, Class, Class) * * @param converter - * The converter to check + * The converter to check. If this is null the result is always + * false. * @param presentationType * The presentation type * @param modelType @@ -168,10 +172,48 @@ public class ConverterUtil implements Serializable { return false; } - if (!modelType.isAssignableFrom(converter.getModelType())) { + if (modelType != converter.getModelType()) { + return false; + } + if (presentationType != converter.getPresentationType()) { return false; } - if (!presentationType.isAssignableFrom(converter.getPresentationType())) { + + return true; + } + + /** + * Checks if it possible that the given converter can handle conversion + * between the given presentation and model type somehow. + * + * @param converter + * The converter to check. If this is null the result is always + * false. + * @param presentationType + * The presentation type + * @param modelType + * The model type + * @return true if the converter possibly support conversion between the + * given presentation and model type, false otherwise + */ + public static boolean canConverterPossiblyHandle(Converter<?, ?> converter, + Class<?> presentationType, Class<?> modelType) { + if (converter == null) { + return false; + } + Class<?> converterModelType = converter.getModelType(); + + if (!modelType.isAssignableFrom(converterModelType) + && !converterModelType.isAssignableFrom(modelType)) { + // model types are not compatible in any way + return false; + } + + Class<?> converterPresentationType = converter.getPresentationType(); + if (!presentationType.isAssignableFrom(converterPresentationType) + && !converterPresentationType + .isAssignableFrom(presentationType)) { + // presentation types are not compatible in any way return false; } diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java index 3bca63a3b7..606bf5fb21 100644 --- a/server/src/com/vaadin/ui/AbstractField.java +++ b/server/src/com/vaadin/ui/AbstractField.java @@ -616,17 +616,14 @@ public abstract class AbstractField<T> extends AbstractComponent implements // Check if the current converter is compatible. if (newDataSource != null - && !ConverterUtil.canConverterHandle(getConverter(), getType(), - newDataSource.getType())) { - // Changing from e.g. Number -> Double should set a new converter, - // changing from Double -> Number can keep the old one (Property - // accepts Number) - - // Set a new converter if there is a new data source and - // there is no old converter or the old is incompatible. + && !ConverterUtil.canConverterPossiblyHandle(getConverter(), + getType(), newDataSource.getType())) { + // There is no converter set or there is no way the current + // converter can be compatible. setConverter(newDataSource.getType()); } - // Gets the value from source + // Gets the value from source. This requires that a valid converter has + // been set. try { if (dataSource != null) { T fieldValue = convertFromModel(getDataSourceValue()); diff --git a/server/src/com/vaadin/ui/Label.java b/server/src/com/vaadin/ui/Label.java index d037652a09..d7cee2a80d 100644 --- a/server/src/com/vaadin/ui/Label.java +++ b/server/src/com/vaadin/ui/Label.java @@ -242,14 +242,17 @@ public class Label extends AbstractComponent implements Property<String>, ((Property.ValueChangeNotifier) dataSource).removeListener(this); } + // Check if the current converter is compatible. if (newDataSource != null - && !ConverterUtil.canConverterHandle(getConverter(), - String.class, newDataSource.getType())) { - // Try to find a converter + && !ConverterUtil.canConverterPossiblyHandle(getConverter(), + getType(), newDataSource.getType())) { + // There is no converter set or there is no way the current + // converter can be compatible. Converter<String, ?> c = ConverterUtil.getConverter(String.class, newDataSource.getType(), getSession()); setConverter(c); } + dataSource = newDataSource; if (dataSource != null) { // Update the value from the data source. If data source was set to diff --git a/server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java b/server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java new file mode 100644 index 0000000000..33a6a87359 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/AnotherTestEnum.java @@ -0,0 +1,16 @@ +package com.vaadin.tests.data.converter; + +public enum AnotherTestEnum { + ONE("ONE"), TWO("TWO"); + + private String id; + + private AnotherTestEnum(String id) { + this.id = id; + } + + @Override + public String toString() { + return id; + } +} diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java new file mode 100644 index 0000000000..baa81ce656 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/TestAnyEnumToStringConverter.java @@ -0,0 +1,128 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.tests.data.converter; + +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.ReverseConverter; +import com.vaadin.ui.TextField; + +public class TestAnyEnumToStringConverter { + + public class AnyEnumToStringConverter implements Converter<Enum, String> { + + private Class<? extends Enum>[] enumClass; + + public AnyEnumToStringConverter(Class<? extends Enum>... enumClass) { + this.enumClass = enumClass; + } + + @Override + public String convertToModel(Enum value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + + return value.toString(); + } + + @Override + public Enum convertToPresentation(String value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + for (Class<? extends Enum> candidate : enumClass) { + for (Enum e : candidate.getEnumConstants()) { + if (e.toString().equals(value)) { + return e; + } + } + } + + return null; + } + + @Override + public Class<String> getModelType() { + return String.class; + } + + @Override + public Class<Enum> getPresentationType() { + return Enum.class; + } + + } + + private AnyEnumToStringConverter converter; + + @Before + public void setup() { + converter = new AnyEnumToStringConverter(TestEnum.class, + AnotherTestEnum.class); + } + + @Test + public void nullConversion() { + Assert.assertEquals(null, converter.convertToModel(null, null)); + } + + @Test + public void enumToStringConversion() { + Assert.assertEquals(TestEnum.TWO.toString(), + converter.convertToModel(TestEnum.TWO, null)); + Assert.assertEquals(AnotherTestEnum.TWO.toString(), + converter.convertToModel(AnotherTestEnum.TWO, null)); + } + + @Test + public void stringToEnumConversion() { + Assert.assertEquals(TestEnum.TWO, + converter.convertToPresentation(TestEnum.TWO.toString(), null)); + Assert.assertEquals(AnotherTestEnum.TWO, converter + .convertToPresentation(AnotherTestEnum.TWO.toString(), null)); + } + + @Test + public void stringToEnumWithField() { + TextField tf = new TextField(); + tf.setConverter(new ReverseConverter(converter)); + tf.setPropertyDataSource(new ObjectProperty(AnotherTestEnum.TWO)); + Assert.assertEquals(AnotherTestEnum.TWO.toString(), tf.getValue()); + tf.setValue(AnotherTestEnum.ONE.toString()); + Assert.assertEquals(AnotherTestEnum.ONE.toString(), tf.getValue()); + Assert.assertEquals(AnotherTestEnum.ONE, tf.getConvertedValue()); + Assert.assertEquals(AnotherTestEnum.ONE, tf.getPropertyDataSource() + .getValue()); + + tf.setPropertyDataSource(new ObjectProperty(TestEnum.TWO)); + Assert.assertEquals(TestEnum.TWO.toString(), tf.getValue()); + tf.setValue(TestEnum.ONE.toString()); + Assert.assertEquals(TestEnum.ONE.toString(), tf.getValue()); + Assert.assertEquals(TestEnum.ONE, tf.getConvertedValue()); + Assert.assertEquals(TestEnum.ONE, tf.getPropertyDataSource().getValue()); + + } +} diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestEnum.java b/server/tests/src/com/vaadin/tests/data/converter/TestEnum.java new file mode 100644 index 0000000000..a4b709a843 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/TestEnum.java @@ -0,0 +1,16 @@ +package com.vaadin.tests.data.converter; + +public enum TestEnum { + ONE("1"), TWO("2"); + + private String id; + + private TestEnum(String id) { + this.id = id; + } + + @Override + public String toString() { + return id; + } +} diff --git a/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java b/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java new file mode 100644 index 0000000000..ef8c57f7f1 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/data/converter/TestSpecificEnumToStringConverter.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.tests.data.converter; + +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.ReverseConverter; +import com.vaadin.ui.TextField; + +public class TestSpecificEnumToStringConverter { + + public class SpecificEnumToStringConverter implements + Converter<Enum, String> { + + private Class<? extends Enum> enumClass; + + public SpecificEnumToStringConverter(Class<? extends Enum> enumClass) { + this.enumClass = enumClass; + } + + @Override + public String convertToModel(Enum value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + + return value.toString(); + } + + @Override + public Enum convertToPresentation(String value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + + for (Enum e : enumClass.getEnumConstants()) { + if (e.toString().equals(value)) { + return e; + } + } + + return null; + } + + @Override + public Class<String> getModelType() { + return String.class; + } + + @Override + public Class<Enum> getPresentationType() { + return (Class<Enum>) enumClass; + } + + } + + SpecificEnumToStringConverter testEnumConverter; + SpecificEnumToStringConverter anotherTestEnumConverter; + + @Before + public void setup() { + testEnumConverter = new SpecificEnumToStringConverter(TestEnum.class); + anotherTestEnumConverter = new SpecificEnumToStringConverter( + AnotherTestEnum.class); + } + + @Test + public void nullConversion() { + Assert.assertEquals(null, testEnumConverter.convertToModel(null, null)); + } + + @Test + public void enumToStringConversion() { + Assert.assertEquals(TestEnum.TWO.toString(), + testEnumConverter.convertToModel(TestEnum.TWO, null)); + } + + @Test + public void stringToEnumConversion() { + Assert.assertEquals(TestEnum.TWO, testEnumConverter + .convertToPresentation(TestEnum.TWO.toString(), null)); + } + + @Test + public void stringToEnumWithField() { + TextField tf = new TextField(); + tf.setConverter(new ReverseConverter(anotherTestEnumConverter)); + tf.setPropertyDataSource(new ObjectProperty(AnotherTestEnum.TWO)); + Assert.assertEquals(AnotherTestEnum.TWO.toString(), tf.getValue()); + tf.setValue(AnotherTestEnum.ONE.toString()); + Assert.assertEquals(AnotherTestEnum.ONE.toString(), tf.getValue()); + Assert.assertEquals(AnotherTestEnum.ONE, tf.getConvertedValue()); + Assert.assertEquals(AnotherTestEnum.ONE, tf.getPropertyDataSource() + .getValue()); + + } +} |