diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BeanMapPropertyField.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BeanMapPropertyField.java new file mode 100644 index 000000000..c29fe98d1 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/BeanMapPropertyField.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright 2018 Manuel Mauky + * + * 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 de.saxsys.mvvmfx.utils.mapping; + +import de.saxsys.mvvmfx.internal.SideEffect; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.MapGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.MapSetter; +import javafx.beans.property.MapProperty; +import javafx.beans.property.Property; +import javafx.collections.FXCollections; +import javafx.collections.MapChangeListener; +import javafx.collections.ObservableMap; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +/** + * An implementation of {@link PropertyField} that is used when the field of the model class is a {@link Map} and is + * not a JavaFX {@link javafx.beans.property.MapProperty} but is following the old Java-Beans standard, i.e. + * there is getter and setter method for the field. + * + * @param the type of the key. + * @param the type of the value. + */ +class BeanMapPropertyField, R extends Property> + implements PropertyField { + + private final MapGetter getter; + + private final MapSetter setter; + + private Map defaultValue; + + private final MapProperty targetProperty; + + BeanMapPropertyField(SideEffect updateFunction, MapGetter getter, MapSetter setter, + Supplier> propertySupplier) { + this(updateFunction, getter, setter, propertySupplier, Collections.emptyMap()); + } + + BeanMapPropertyField(SideEffect updateFunction, MapGetter getter, MapSetter setter, + Supplier> propertySupplier, + Map defaultValue) { + this.defaultValue = defaultValue; + this.getter = getter; + this.setter = setter; + this.targetProperty = propertySupplier.get(); + this.targetProperty.setValue(FXCollections.observableMap(new HashMap<>())); + this.targetProperty.addListener((MapChangeListener) change -> updateFunction.call()); + } + + static void setAll(Map target, Map newValues) { + target.keySet().retainAll(newValues.keySet()); + target.putAll(newValues); + } + + @Override + public void commit(M wrappedObject) { + setter.accept(wrappedObject, targetProperty.getValue()); + } + + @Override + public void reload(M wrappedObject) { + setAll(targetProperty, getter.apply(wrappedObject)); + } + + @Override + public void resetToDefault() { + + targetProperty.get().clear(); + setAll(targetProperty, defaultValue); + } + + @Override + public void updateDefault(M wrappedObject) { + defaultValue = new HashMap<>(getter.apply(wrappedObject)); + } + + @Override + public R getProperty() { + return (R) targetProperty; + } + + @Override + public boolean isDifferent(M wrappedObject) { + final Map modelValue = getter.apply(wrappedObject); + final Map wrapperValue = targetProperty; + + return !Objects.equals(modelValue, wrapperValue); + } + +} \ No newline at end of file diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FxMapPropertyField.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FxMapPropertyField.java new file mode 100644 index 000000000..78100e4d4 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/FxMapPropertyField.java @@ -0,0 +1,89 @@ +package de.saxsys.mvvmfx.utils.mapping; + +import de.saxsys.mvvmfx.internal.SideEffect; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.MapPropertyAccessor; +import javafx.beans.property.MapProperty; +import javafx.beans.property.Property; +import javafx.collections.FXCollections; +import javafx.collections.MapChangeListener; +import javafx.collections.ObservableMap; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +import static de.saxsys.mvvmfx.utils.mapping.BeanMapPropertyField.setAll; + +/** + * An implementation of {@link PropertyField} that is used when the field of the model class is a {@link Map} and will + * be mapped to a JavaFX {@link MapProperty}. + * + * @param the type of the key elements. + * @param the type of the value elements. + */ +class FxMapPropertyField, R extends Property> + implements PropertyField { + + private Map defaultValue; + + private final MapPropertyAccessor accessor; + + private final MapProperty targetProperty; + + FxMapPropertyField( + SideEffect updateFunction, MapPropertyAccessor accessor, + Supplier> propertySupplier) { + this(updateFunction, accessor, propertySupplier, Collections.emptyMap()); + } + + FxMapPropertyField(SideEffect updateFunction, MapPropertyAccessor accessor, + Supplier> propertySupplier, + Map defaultValue) { + this.accessor = accessor; + this.defaultValue = defaultValue; + this.targetProperty = propertySupplier.get(); + + this.targetProperty.setValue(FXCollections.observableMap(new HashMap<>())); + this.targetProperty.addListener((MapChangeListener) change -> updateFunction.call()); + } + + @Override + public void commit(M wrappedObject) { + setAll(accessor.apply(wrappedObject), targetProperty.getValue()); + } + + @Override + public void reload(M wrappedObject) { + setAll(targetProperty, accessor.apply(wrappedObject).getValue()); + } + + @Override + public void resetToDefault() { + try { + targetProperty.get().clear(); + setAll(targetProperty, defaultValue); + } catch (Exception e) { + System.out.println(e); + } + } + + @Override + public void updateDefault(M wrappedObject) { + defaultValue = new HashMap<>(accessor.apply(wrappedObject).getValue()); + } + + @Override + public R getProperty() { + return (R) targetProperty; + } + + @Override + public boolean isDifferent(M wrappedObject) { + final Map modelValue = accessor.apply(wrappedObject).getValue(); + final Map wrapperValue = targetProperty; + + return !Objects.equals(modelValue, wrapperValue); + } +} \ No newline at end of file diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ImmutableMapPropertyField.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ImmutableMapPropertyField.java new file mode 100644 index 000000000..f3136b2f6 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ImmutableMapPropertyField.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright 2018 Manuel Mauky + * + * 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 de.saxsys.mvvmfx.utils.mapping; + +import de.saxsys.mvvmfx.internal.SideEffect; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.MapGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.MapImmutableSetter; +import javafx.beans.property.MapProperty; +import javafx.beans.property.Property; +import javafx.collections.FXCollections; +import javafx.collections.MapChangeListener; +import javafx.collections.ObservableMap; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +import static de.saxsys.mvvmfx.utils.mapping.BeanMapPropertyField.setAll; + +class ImmutableMapPropertyField, R extends Property> + implements ImmutablePropertyField { + + private final MapGetter getter; + + private final MapImmutableSetter immutableSetter; + + private Map defaultValue; + + private final MapProperty targetProperty; + + ImmutableMapPropertyField( + SideEffect updateFunction, + MapGetter getter, MapImmutableSetter immutableSetter, + Supplier> propertySupplier) { + this(updateFunction, getter, immutableSetter, propertySupplier, Collections.emptyMap()); + } + + ImmutableMapPropertyField(SideEffect updateFunction, + MapGetter getter, MapImmutableSetter immutableSetter, + Supplier> propertySupplier, Map defaultValue) { + this.defaultValue = defaultValue; + this.getter = getter; + this.immutableSetter = immutableSetter; + this.targetProperty = propertySupplier.get(); + this.targetProperty.setValue(FXCollections.observableMap(new HashMap<>())); + this.targetProperty.addListener((MapChangeListener) change -> updateFunction.call()); + } + + @Override + public void commit(M wrappedObject) { + // commit is not supported because the model instance is immutable. + } + + @Override + public M commitImmutable(M wrappedObject) { + return immutableSetter.apply(wrappedObject, targetProperty.getValue()); + } + + @Override + public void reload(M wrappedObject) { + setAll(targetProperty, getter.apply(wrappedObject)); + } + + @Override + public void resetToDefault() { + setAll(targetProperty, defaultValue); + } + + @Override + public void updateDefault(M wrappedObject) { + defaultValue = new HashMap<>(getter.apply(wrappedObject)); + } + + @Override + public R getProperty() { + return (R) targetProperty; + } + + @Override + public boolean isDifferent(M wrappedObject) { + final Map modelValue = getter.apply(wrappedObject); + final Map wrappedValue = targetProperty; + + return !Objects.equals(modelValue, wrappedValue); + } +} \ No newline at end of file diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java index e6678fa8e..922b2ce09 100644 --- a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapper.java @@ -39,6 +39,10 @@ import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.LongImmutableSetter; import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.LongPropertyAccessor; import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.LongSetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.MapGetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.MapImmutableSetter; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.MapPropertyAccessor; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.MapSetter; import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.ObjectGetter; import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.ObjectImmutableSetter; import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.ObjectPropertyAccessor; @@ -68,6 +72,7 @@ import javafx.beans.property.IntegerProperty; import javafx.beans.property.ListProperty; import javafx.beans.property.LongProperty; +import javafx.beans.property.MapProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.Property; import javafx.beans.property.ReadOnlyBooleanProperty; @@ -79,6 +84,7 @@ import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleLongProperty; +import javafx.beans.property.SimpleMapProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleSetProperty; import javafx.beans.property.SimpleStringProperty; @@ -1556,4 +1562,91 @@ public SetProperty field(String identifier, SetPropertyAccessor acc return addIdentified(identifier, new FxSetPropertyField<>(this::propertyWasChanged, accessor, () -> new SimpleSetProperty<>(null, identifier), defaultValue)); } + + /* Field type map */ + + public MapProperty field(MapGetter getter, MapSetter setter) { + return add(new BeanMapPropertyField<>(this::propertyWasChanged, getter, + (m, map) -> setter.accept(m, FXCollections.observableMap(map)), SimpleMapProperty::new)); + } + + public MapProperty immutableField(MapGetter getter, + MapImmutableSetter immutableSetter) { + return addImmutable(new ImmutableMapPropertyField<>( + this::propertyWasChanged, + getter, + (m, map) -> immutableSetter.apply(m, FXCollections.observableMap(map)), + SimpleMapProperty::new + )); + } + + public MapProperty field(MapGetter getter, MapSetter setter, + Map defaultValue) { + return add(new BeanMapPropertyField<>(this::propertyWasChanged, getter, + (m, map) -> setter.accept(m, FXCollections.observableMap(map)), SimpleMapProperty::new, + defaultValue)); + } + + public MapProperty immutableField(MapGetter getter, + MapImmutableSetter immutableSetter, Map defaultValue) { + return addImmutable(new ImmutableMapPropertyField<>( + this::propertyWasChanged, + getter, + (m, map) -> immutableSetter.apply(m, FXCollections.observableMap(map)), + SimpleMapProperty::new, + defaultValue)); + } + + public MapProperty field(MapPropertyAccessor accessor) { + return add(new FxMapPropertyField<>(this::propertyWasChanged, accessor, SimpleMapProperty::new)); + } + + public MapProperty field(MapPropertyAccessor accessor, Map defaultValue) { + return add( + new FxMapPropertyField<>(this::propertyWasChanged, accessor, SimpleMapProperty::new, defaultValue)); + } + + public MapProperty field(String identifier, MapGetter getter, MapSetter setter) { + return addIdentified(identifier, new BeanMapPropertyField<>(this::propertyWasChanged, getter, + (m, map) -> setter.accept(m, FXCollections.observableMap(map)), + () -> new SimpleMapProperty<>(null, identifier))); + } + + public MapProperty field(String identifier, MapGetter getter, MapSetter setter, + Map defaultValue) { + return addIdentified(identifier, new BeanMapPropertyField<>(this::propertyWasChanged, getter, + (m, map) -> setter.accept(m, FXCollections.observableMap(map)), + () -> new SimpleMapProperty<>(null, identifier), defaultValue)); + } + + public MapProperty immutableField(String identifier, MapGetter getter, + MapImmutableSetter immutableSetter) { + return addIdentifiedImmutable(identifier, new ImmutableMapPropertyField<>( + this::propertyWasChanged, + getter, + (m, map) -> immutableSetter.apply(m, FXCollections.observableMap(map)), + () -> new SimpleMapProperty<>(null, identifier))); + } + + public MapProperty immutableField(String identifier, MapGetter getter, + MapImmutableSetter immutableSetter, + Map defaultValue) { + return addIdentifiedImmutable(identifier, new ImmutableMapPropertyField<>( + this::propertyWasChanged, + getter, + (m, map) -> immutableSetter.apply(m, FXCollections.observableMap(map)), + () -> new SimpleMapProperty<>(null, identifier), + defaultValue)); + } + + public MapProperty field(String identifier, MapPropertyAccessor accessor) { + return addIdentified(identifier, new FxMapPropertyField<>(this::propertyWasChanged, accessor, + () -> new SimpleMapProperty<>(null, identifier))); + } + + public MapProperty field(String identifier, MapPropertyAccessor accessor, + Map defaultValue) { + return addIdentified(identifier, new FxMapPropertyField<>(this::propertyWasChanged, accessor, + () -> new SimpleMapProperty<>(null, identifier), defaultValue)); + } } diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapGetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapGetter.java new file mode 100644 index 000000000..2199c9c6e --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapGetter.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2018 Manuel Mauky + * + * 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 de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.Map; +import java.util.function.Function; + +/** + * A functional interface to define a getter method of a map type. + * + * @param the generic type of the model. + * @param the type of the key. + * @param the type of the value. + */ +@FunctionalInterface +public interface MapGetter extends Function> { + + /** + * @param model the model instance + * + * @return the value of the field + */ + @Override + Map apply(M model); +} \ No newline at end of file diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapImmutableSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapImmutableSetter.java new file mode 100644 index 000000000..ff7c8909d --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapImmutableSetter.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2018 Manuel Mauky + * + * 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 de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.Map; +import java.util.function.BiFunction; + +/** + * A functional interface to define an immutable "setter" method of type {@link Map}. As the model element is immutable + * this method is not a real "setter". Instead it returns a new immutable copy of the original model element that has + * the specified field updated to the new value. + * + * @param the generic type of the model. + */ +@FunctionalInterface +public interface MapImmutableSetter extends BiFunction, M> { + + /** + * @param model the model instance + * @param newElements the new elements of this map field. + * + * @return a new model instance with the new values + */ + @Override + M apply(M model, Map newElements); +} \ No newline at end of file diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapPropertyAccessor.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapPropertyAccessor.java new file mode 100644 index 000000000..cba684d9a --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapPropertyAccessor.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2018 Manuel Mauky + * + * 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 de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import javafx.beans.property.MapProperty; + +import java.util.function.Function; + +/** + * A functional interface to define an accessor method for a property of a map type. + * + * @param the generic type of the model. + * @param the type of the key elements + * @param the type of the value elements + */ +@FunctionalInterface +public interface MapPropertyAccessor extends Function> { + + /** + * @param model the model instance + * + * @return the property field of the model + */ + @Override + MapProperty apply(M model); +} \ No newline at end of file diff --git a/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapSetter.java b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapSetter.java new file mode 100644 index 000000000..1346233f0 --- /dev/null +++ b/mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/mapping/accessorfunctions/MapSetter.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2018 Manuel Mauky + * + * 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 de.saxsys.mvvmfx.utils.mapping.accessorfunctions; + +import java.util.Map; +import java.util.function.BiConsumer; + +/** + * A functional interface to define a getter method of a map type. + * + * @param the generic type of the model. + * @param the type of the key. + * @param the type of the value. + */ +@FunctionalInterface +public interface MapSetter extends BiConsumer> { + + /** + * @param model the model instance + * + * @return the value of the field + */ + @Override + void accept(M model, Map value); +} \ No newline at end of file diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java index 99475d47b..c3d84cb8c 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ExampleModel.java @@ -16,6 +16,7 @@ package de.saxsys.mvvmfx.utils.mapping; import java.util.List; +import java.util.Map; import java.util.Set; import javafx.beans.property.BooleanProperty; @@ -24,6 +25,7 @@ import javafx.beans.property.IntegerProperty; import javafx.beans.property.ListProperty; import javafx.beans.property.LongProperty; +import javafx.beans.property.MapProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SetProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -32,6 +34,7 @@ import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleLongProperty; +import javafx.beans.property.SimpleMapProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleSetProperty; import javafx.beans.property.SimpleStringProperty; @@ -54,6 +57,7 @@ public class ExampleModel { private SetProperty setProperty = new SimpleSetProperty<>(); + private MapProperty mapProperty = new SimpleMapProperty<>(); public int getInteger() { return integerProperty.get(); @@ -163,4 +167,17 @@ public void setSet(Set set) { this.setProperty.retainAll(set); this.setProperty.addAll(set); } + + public Map getMap() { + return mapProperty.get(); + } + + public MapProperty mapProperty() { + return mapProperty; + } + + public void setMap(Map map) { + this.mapProperty.get().clear(); + this.mapProperty.get().putAll(map); + } } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/FieldMethodOverloadingTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/FieldMethodOverloadingTest.java index 9e8531ac6..61da6cb39 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/FieldMethodOverloadingTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/FieldMethodOverloadingTest.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; import org.junit.jupiter.api.BeforeEach; @@ -34,6 +35,7 @@ import javafx.beans.property.IntegerProperty; import javafx.beans.property.ListProperty; import javafx.beans.property.LongProperty; +import javafx.beans.property.MapProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.Property; import javafx.beans.property.SetProperty; @@ -281,7 +283,7 @@ public void listProperty() { } @Test - public void lsetProperty() { + public void setProperty() { Set defaultValue = Collections.emptySet(); final SetProperty beanField = wrapper.field(ExampleModel::getSet, ExampleModel::setSet); final SetProperty fxField = wrapper.field(ExampleModel::setProperty); @@ -309,6 +311,38 @@ public void lsetProperty() { verifyDefaultValues(idFxFieldDefault, defaultValue, alternativeValue); } + @Test + public void mapProperty() { + Map defaultValue = Collections.emptyMap(); + final MapProperty beanField = wrapper.field(ExampleModel::getMap, ExampleModel::setMap); + final MapProperty fxField = wrapper.field(ExampleModel::mapProperty); + final MapProperty beanFieldDefault = wrapper.field(ExampleModel::getMap, ExampleModel::setMap, + defaultValue); + final MapProperty fxFieldDefault = wrapper.field(ExampleModel::mapProperty, defaultValue); + + final MapProperty idBeanField = wrapper + .field("idBeanField", ExampleModel::getMap, ExampleModel::setMap); + final MapProperty idFxField = wrapper.field("idFxField", ExampleModel::mapProperty); + final MapProperty idBeanFieldDefault = wrapper.field("idBeanFieldDefault", + ExampleModel::getMap, + ExampleModel::setMap, defaultValue); + final MapProperty idFxFieldDefault = wrapper + .field("idFxFieldDefault", ExampleModel::mapProperty, + defaultValue); + + // for listProperty we can't use the other "verify" method because of type mismatch. + verifyId(idBeanField, "idBeanField"); + verifyId(idFxField, "idFxField"); + verifyId(idBeanFieldDefault, "idBeanFieldDefault"); + verifyId(idFxFieldDefault, "idFxFieldDefault"); + + Map alternativeValue = Collections.singletonMap("1", "2"); + verifyDefaultValues(beanFieldDefault, defaultValue, alternativeValue); + verifyDefaultValues(fxFieldDefault, defaultValue, alternativeValue); + verifyDefaultValues(idBeanFieldDefault, defaultValue, alternativeValue); + verifyDefaultValues(idFxFieldDefault, defaultValue, alternativeValue); + } + private void verifyDefaultValues(Collection property, Collection defaultValue, Collection otherValue) { property.addAll(otherValue); @@ -318,4 +352,16 @@ private void verifyDefaultValues(Collection property, Collection defau wrapper.reset(); assertThat(property).containsAll(defaultValue); } + + private void verifyDefaultValues(Map property, Map defaultValue, Map otherValue) { + + property.putAll(otherValue); + + wrapper.commit(); + assertThat(property.entrySet()).containsExactlyElementsOf(otherValue.entrySet()); + + wrapper.reset(); + assertThat(property.entrySet()).containsExactlyElementsOf(defaultValue.entrySet()); + } } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java index 6d22d083d..b3fadd2ce 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/ModelWrapperTest.java @@ -20,12 +20,19 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import de.saxsys.mvvmfx.utils.mapping.accessorfunctions.SetPropertyAccessor; +import javafx.beans.property.MapProperty; import javafx.collections.ObservableList; +import javafx.collections.ObservableMap; import javafx.collections.ObservableSet; + +import org.assertj.core.data.MapEntry; import org.junit.jupiter.api.Test; import javafx.beans.property.IntegerProperty; @@ -45,6 +52,7 @@ public void testCopyValuesTo() { personA.setAge(32); personA.setNicknames(Collections.singletonList("captain")); personA.setEmailAddresses(Collections.singleton("test@example.org")); + personA.setPhoneNumbers(Collections.singletonMap("private", "0351 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(personA); @@ -52,11 +60,15 @@ public void testCopyValuesTo() { final IntegerProperty ageProperty = personWrapper.field(Person::getAge, Person::setAge); final ListProperty nicknamesProperty = personWrapper.field(Person::getNicknames, Person::setNicknames); final SetProperty emailAddressesProperty = personWrapper.field(Person::getEmailAddresses, Person::setEmailAddresses); + final MapProperty phoneNumbersProperty = personWrapper.field(Person::getPhoneNumbers, + Person::setPhoneNumbers); + assertThat(nameProperty.getValue()).isEqualTo("horst"); assertThat(ageProperty.getValue()).isEqualTo(32); assertThat(nicknamesProperty.getValue()).containsOnly("captain"); assertThat(emailAddressesProperty.getValue()).containsOnly("test@example.org"); + assertThat(phoneNumbersProperty.getValue()).containsOnly(MapEntry.entry("private", "0351 1234567")); // when Person personB = new Person(); @@ -64,6 +76,7 @@ public void testCopyValuesTo() { personB.setAge(23); personB.setNicknames(Collections.singletonList("lui")); personB.setEmailAddresses(Collections.singleton("luise@example.org")); + personB.setPhoneNumbers(Collections.singletonMap("private", "03581 7654321")); personWrapper.copyValuesTo(personB); @@ -73,19 +86,21 @@ public void testCopyValuesTo() { assertThat(personB.getAge()).isEqualTo(32); assertThat(personB.getNicknames()).containsExactly("captain"); assertThat(personB.getEmailAddresses()).containsExactly("test@example.org"); + assertThat(personB.getPhoneNumbers()).containsExactly(MapEntry.entry("private", "0351 1234567")); // the properties have still the old values assertThat(nameProperty.getValue()).isEqualTo("horst"); assertThat(ageProperty.getValue()).isEqualTo(32); assertThat(nicknamesProperty.getValue()).containsOnly("captain"); assertThat(emailAddressesProperty.getValue()).containsOnly("test@example.org"); + assertThat(phoneNumbersProperty.getValue()).containsOnly(MapEntry.entry("private", "0351 1234567")); // and of cause the old person a has it's old values too assertThat(personA.getName()).isEqualTo("horst"); assertThat(personA.getAge()).isEqualTo(32); assertThat(personA.getNicknames()).containsExactly("captain"); assertThat(personA.getEmailAddresses()).containsExactly("test@example.org"); - + assertThat(personA.getPhoneNumbers()).containsExactly(MapEntry.entry("private", "0351 1234567")); } @Test @@ -93,8 +108,9 @@ public void testWithGetterAndSetter() { Person person = new Person(); person.setName("horst"); person.setAge(32); - person.setNicknames(Arrays.asList("captain")); + person.setNicknames(Collections.singletonList("captain")); person.setEmailAddresses(Collections.singleton("test@example.org")); + person.setPhoneNumbers(Collections.singletonMap("private", "0351 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -102,22 +118,27 @@ public void testWithGetterAndSetter() { final IntegerProperty ageProperty = personWrapper.field(Person::getAge, Person::setAge); final ListProperty nicknamesProperty = personWrapper.field(Person::getNicknames, Person::setNicknames); final SetProperty emailAddressesProperty = personWrapper.field(Person::getEmailAddresses, Person::setEmailAddresses); + final MapProperty phoneNumbersProperty = personWrapper.field(Person::getPhoneNumbers, + Person::setPhoneNumbers); assertThat(nameProperty.getValue()).isEqualTo("horst"); assertThat(ageProperty.getValue()).isEqualTo(32); assertThat(nicknamesProperty.getValue()).containsOnly("captain"); assertThat(emailAddressesProperty.getValue()).containsOnly("test@example.org"); + assertThat(phoneNumbersProperty.getValue()).containsOnly(MapEntry.entry("private", "0351 1234567")); nameProperty.setValue("hugo"); ageProperty.setValue(33); nicknamesProperty.add("player"); emailAddressesProperty.add("test2@example.org"); + phoneNumbersProperty.putIfAbsent("mobile", "0123 4567890"); // still the old values assertThat(person.getName()).isEqualTo("horst"); assertThat(person.getAge()).isEqualTo(32); assertThat(person.getNicknames()).containsOnly("captain"); assertThat(person.getEmailAddresses()).containsOnly("test@example.org"); + assertThat(person.getPhoneNumbers()).containsOnly(MapEntry.entry("private", "0351 1234567")); personWrapper.commit(); @@ -126,11 +147,15 @@ public void testWithGetterAndSetter() { assertThat(person.getAge()).isEqualTo(33); assertThat(person.getNicknames()).containsOnly("captain", "player"); assertThat(person.getEmailAddresses()).containsOnly("test@example.org", "test2@example.org"); + assertThat(person.getPhoneNumbers()).containsOnly( + MapEntry.entry("private", "0351 1234567"), + MapEntry.entry("mobile", "0123 4567890")); nameProperty.setValue("luise"); ageProperty.setValue(15); nicknamesProperty.setValue(FXCollections.observableArrayList("student")); emailAddressesProperty.setValue(FXCollections.observableSet("luise@example.org")); + phoneNumbersProperty.setValue(observableMap("mobile", "0124 9876543")); personWrapper.reset(); @@ -138,12 +163,16 @@ public void testWithGetterAndSetter() { assertThat(ageProperty.getValue()).isEqualTo(0); assertThat(nicknamesProperty.getValue()).isEmpty(); assertThat(emailAddressesProperty.getValue()).isEmpty(); + assertThat(phoneNumbersProperty.getValue()).isEmpty(); // the wrapped object has still the values from the last commit. assertThat(person.getName()).isEqualTo("hugo"); assertThat(person.getAge()).isEqualTo(33); assertThat(person.getNicknames()).containsOnly("captain", "player"); assertThat(person.getEmailAddresses()).containsOnly("test@example.org", "test2@example.org"); + assertThat(person.getPhoneNumbers()).containsOnly( + MapEntry.entry("private", "0351 1234567"), + MapEntry.entry("mobile", "0123 4567890")); personWrapper.reload(); // now the properties have the values from the wrapped object @@ -151,12 +180,17 @@ public void testWithGetterAndSetter() { assertThat(ageProperty.getValue()).isEqualTo(33); assertThat(nicknamesProperty.get()).containsOnly("captain", "player"); assertThat(emailAddressesProperty.get()).containsOnly("test@example.org", "test2@example.org"); + assertThat(phoneNumbersProperty.get()).containsOnly( + MapEntry.entry("private", "0351 1234567"), + MapEntry.entry("mobile", "0123 4567890")); + Person otherPerson = new Person(); otherPerson.setName("gisela"); otherPerson.setAge(23); - otherPerson.setNicknames(Arrays.asList("referee")); + otherPerson.setNicknames(Collections.singletonList("referee")); otherPerson.setEmailAddresses(Collections.singleton("gisela@example.org")); + otherPerson.setPhoneNumbers(Collections.singletonMap("private", "030 112233")); personWrapper.set(otherPerson); personWrapper.reload(); @@ -165,11 +199,16 @@ public void testWithGetterAndSetter() { assertThat(ageProperty.getValue()).isEqualTo(23); assertThat(nicknamesProperty.getValue()).containsOnly("referee"); assertThat(emailAddressesProperty.getValue()).containsOnly("gisela@example.org"); + assertThat(phoneNumbersProperty.get()).containsOnly( + MapEntry.entry("private", "030 112233") + ); nameProperty.setValue("georg"); ageProperty.setValue(24); nicknamesProperty.setValue(FXCollections.observableArrayList("spectator")); emailAddressesProperty.setValue(FXCollections.observableSet("georg@example.org")); + phoneNumbersProperty.setValue(observableMap("private", + "0351 7654321")); personWrapper.commit(); @@ -178,12 +217,16 @@ public void testWithGetterAndSetter() { assertThat(person.getAge()).isEqualTo(33); assertThat(person.getNicknames()).containsOnly("captain", "player"); assertThat(person.getEmailAddresses()).containsOnly("test@example.org", "test2@example.org"); + assertThat(person.getPhoneNumbers()).containsOnly( + MapEntry.entry("private", "0351 1234567"), + MapEntry.entry("mobile", "0123 4567890")); // new person has the new values assertThat(otherPerson.getName()).isEqualTo("georg"); assertThat(otherPerson.getAge()).isEqualTo(24); assertThat(otherPerson.getNicknames()).containsOnly("spectator"); assertThat(otherPerson.getEmailAddresses()).containsOnly("georg@example.org"); + assertThat(otherPerson.getPhoneNumbers()).containsOnly(MapEntry.entry("private", "0351 7654321")); } @@ -192,8 +235,9 @@ public void testWithJavaFXPropertiesField() { PersonFX person = new PersonFX(); person.setName("horst"); person.setAge(32); - person.setNicknames(Arrays.asList("captain")); + person.setNicknames(Collections.singletonList("captain")); person.setEmailAddresses(Collections.singleton("test@example.org")); + person.setPhoneNumbers(observableMap("private", "0351 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -201,22 +245,26 @@ public void testWithJavaFXPropertiesField() { final IntegerProperty ageProperty = personWrapper.field(PersonFX::ageProperty); final ListProperty nicknamesProperty = personWrapper.field(PersonFX::nicknamesProperty); final SetProperty emailAddressesProperty = personWrapper.field(PersonFX::emailAddressesProperty); + final MapProperty phoneNumbersProperty = personWrapper.field(PersonFX::phoneNumbersProperty); assertThat(nameProperty.getValue()).isEqualTo("horst"); assertThat(ageProperty.getValue()).isEqualTo(32); assertThat(nicknamesProperty.getValue()).containsOnly("captain"); assertThat(emailAddressesProperty.getValue()).containsOnly("test@example.org"); + assertThat(phoneNumbersProperty.getValue()).containsOnly(MapEntry.entry("private", "0351 1234567")); nameProperty.setValue("hugo"); ageProperty.setValue(33); nicknamesProperty.add("player"); emailAddressesProperty.add("test2@example.org"); + phoneNumbersProperty.putIfAbsent("mobile", "0123 4567890"); // still the old values assertThat(person.getName()).isEqualTo("horst"); assertThat(person.getAge()).isEqualTo(32); assertThat(person.getNicknames()).containsOnly("captain"); assertThat(person.getEmailAddresses()).containsOnly("test@example.org"); + assertThat(person.getPhoneNumbers()).containsOnly(MapEntry.entry("private", "0351 1234567")); personWrapper.commit(); @@ -225,11 +273,16 @@ public void testWithJavaFXPropertiesField() { assertThat(person.getAge()).isEqualTo(33); assertThat(person.getNicknames()).containsOnly("captain", "player"); assertThat(person.getEmailAddresses()).containsOnly("test@example.org", "test2@example.org"); + assertThat(person.getPhoneNumbers()).containsOnly( + MapEntry.entry("private", "0351 1234567"), + MapEntry.entry("mobile", "0123 4567890")); + nameProperty.setValue("luise"); ageProperty.setValue(15); nicknamesProperty.setValue(FXCollections.observableArrayList("student")); emailAddressesProperty.setValue(FXCollections.observableSet("luise@example.org")); + phoneNumbersProperty.setValue(observableMap("mobile", "0124 9876543")); personWrapper.reset(); @@ -237,12 +290,16 @@ public void testWithJavaFXPropertiesField() { assertThat(ageProperty.getValue()).isEqualTo(0); assertThat(nicknamesProperty.getValue()).isEmpty(); assertThat(emailAddressesProperty.getValue()).isEmpty(); + assertThat(phoneNumbersProperty.getValue()).isEmpty(); // the wrapped object has still the values from the last commit. assertThat(person.getName()).isEqualTo("hugo"); assertThat(person.getAge()).isEqualTo(33); assertThat(person.getNicknames()).containsOnly("captain", "player"); assertThat(person.getEmailAddresses()).containsOnly("test@example.org", "test2@example.org"); + assertThat(person.getPhoneNumbers()).containsOnly( + MapEntry.entry("private", "0351 1234567"), + MapEntry.entry("mobile", "0123 4567890")); personWrapper.reload(); // now the properties have the values from the wrapped object @@ -250,12 +307,16 @@ public void testWithJavaFXPropertiesField() { assertThat(ageProperty.getValue()).isEqualTo(33); assertThat(nicknamesProperty.get()).containsOnly("captain", "player"); assertThat(emailAddressesProperty.get()).containsOnly("test@example.org", "test2@example.org"); + assertThat(person.getPhoneNumbers()).containsOnly( + MapEntry.entry("private", "0351 1234567"), + MapEntry.entry("mobile", "0123 4567890")); PersonFX otherPerson = new PersonFX(); otherPerson.setName("gisela"); otherPerson.setAge(23); - otherPerson.setNicknames(Arrays.asList("referee")); + otherPerson.setNicknames(Collections.singletonList("referee")); otherPerson.setEmailAddresses(Collections.singleton("gisela@example.org")); + otherPerson.setPhoneNumbers(Collections.singletonMap("private", "030 112233")); personWrapper.set(otherPerson); personWrapper.reload(); @@ -264,11 +325,13 @@ public void testWithJavaFXPropertiesField() { assertThat(ageProperty.getValue()).isEqualTo(23); assertThat(nicknamesProperty.getValue()).containsOnly("referee"); assertThat(emailAddressesProperty.getValue()).containsOnly("gisela@example.org"); + assertThat(phoneNumbersProperty.getValue()).containsOnly(MapEntry.entry("private", "030 112233")); nameProperty.setValue("georg"); ageProperty.setValue(24); nicknamesProperty.setValue(FXCollections.observableArrayList("spectator")); emailAddressesProperty.setValue(FXCollections.observableSet("georg@example.org")); + phoneNumbersProperty.setValue(observableMap("private", "0351 7654321")); personWrapper.commit(); @@ -277,13 +340,17 @@ public void testWithJavaFXPropertiesField() { assertThat(person.getAge()).isEqualTo(33); assertThat(person.getNicknames()).containsOnly("captain", "player"); assertThat(person.getEmailAddresses()).containsOnly("test@example.org", "test2@example.org"); + assertThat(person.getPhoneNumbers()).containsOnly( + MapEntry.entry("private", "0351 1234567"), + MapEntry.entry("mobile", "0123 4567890")); + // new person has the new values assertThat(otherPerson.getName()).isEqualTo("georg"); assertThat(otherPerson.getAge()).isEqualTo(24); assertThat(otherPerson.getNicknames()).containsOnly("spectator"); assertThat(otherPerson.getEmailAddresses()).containsOnly("georg@example.org"); - + assertThat(otherPerson.getPhoneNumbers()).containsOnly(MapEntry.entry("private", "0351 7654321")); } @Test @@ -293,7 +360,8 @@ public void testWithImmutables() { .withName("horst") .withAge(32) .withNicknames(Collections.singletonList("captain")) - .withEmailAddresses(Collections.singleton("test@example.org")); + .withEmailAddresses(Collections.singleton("test@example.org")) + .withPhoneNumbers(Collections.singletonMap("private", "0351 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person1); @@ -304,16 +372,20 @@ public void testWithImmutables() { final ListProperty nicknamesProperty = personWrapper.immutableField(PersonImmutable::getNicknames, PersonImmutable::withNicknames); final SetProperty emailAddressesProperty = personWrapper.immutableField(PersonImmutable::getEmailAddresses, PersonImmutable::withEmailAddresses); + final MapProperty phoneNumbersProperty = personWrapper.immutableField( + PersonImmutable::getPhoneNumbers, PersonImmutable::withPhoneNumbers); assertThat(nameProperty.getValue()).isEqualTo("horst"); assertThat(ageProperty.getValue()).isEqualTo(32); assertThat(nicknamesProperty.getValue()).containsOnly("captain"); assertThat(emailAddressesProperty.getValue()).containsOnly("test@example.org"); + assertThat(phoneNumbersProperty.getValue()).containsOnly(MapEntry.entry("private", "0351 1234567")); nameProperty.setValue("hugo"); ageProperty.setValue(33); nicknamesProperty.add("player"); emailAddressesProperty.add("hugo@example.org"); + phoneNumbersProperty.putIfAbsent("mobile", "0123 4567890"); personWrapper.commit(); @@ -322,6 +394,7 @@ public void testWithImmutables() { assertThat(person1.getAge()).isEqualTo(32); assertThat(person1.getNicknames()).containsOnly("captain"); assertThat(person1.getEmailAddresses()).containsOnly("test@example.org"); + assertThat(person1.getPhoneNumbers()).containsOnly(MapEntry.entry("private", "0351 1234567")); PersonImmutable person2 = personWrapper.get(); @@ -330,11 +403,15 @@ public void testWithImmutables() { assertThat(person2.getAge()).isEqualTo(33); assertThat(person2.getNicknames()).containsOnly("captain", "player"); assertThat(person2.getEmailAddresses()).containsOnly("test@example.org", "hugo@example.org"); + assertThat(person2.getPhoneNumbers()).containsOnly( + MapEntry.entry("mobile", "0123 4567890"), + MapEntry.entry("private", "0351 1234567")); nameProperty.setValue("luise"); ageProperty.setValue(33); nicknamesProperty.setValue(FXCollections.observableArrayList("student")); emailAddressesProperty.setValue(FXCollections.observableSet("luise@example.org")); + phoneNumbersProperty.setValue(observableMap("mobile", "0124 9876543")); personWrapper.reset(); @@ -342,6 +419,7 @@ public void testWithImmutables() { assertThat(ageProperty.getValue()).isEqualTo(0); assertThat(nicknamesProperty.getValue()).isEmpty(); assertThat(emailAddressesProperty.getValue()).isEmpty(); + assertThat(phoneNumbersProperty.getValue()).isEmpty(); personWrapper.reload(); // now the properties have the values from the wrapped object @@ -349,11 +427,15 @@ public void testWithImmutables() { assertThat(ageProperty.getValue()).isEqualTo(33); assertThat(nicknamesProperty.get()).containsOnly("captain", "player"); assertThat(emailAddressesProperty.get()).containsOnly("test@example.org", "hugo@example.org"); + assertThat(phoneNumbersProperty.get()).containsOnly( + MapEntry.entry("mobile", "0123 4567890"), + MapEntry.entry("private", "0351 1234567")); PersonImmutable person3 = person1.withName("gisela") .withAge(23) .withNicknames(Collections.singletonList("referee")) - .withEmailAddresses(Collections.singleton("gisela@example.org")); + .withEmailAddresses(Collections.singleton("gisela@example.org")) + .withPhoneNumbers(Collections.singletonMap("private", "030 112233")); personWrapper.set(person3); personWrapper.reload(); @@ -362,6 +444,7 @@ public void testWithImmutables() { assertThat(ageProperty.getValue()).isEqualTo(23); assertThat(nicknamesProperty.getValue()).containsOnly("referee"); assertThat(emailAddressesProperty.getValue()).containsOnly("gisela@example.org"); + assertThat(phoneNumbersProperty.getValue()).containsOnly(MapEntry.entry("private", "030 112233")); } @Test @@ -369,8 +452,9 @@ public void testIdentifiedFields() { Person person = new Person(); person.setName("horst"); person.setAge(32); - person.setNicknames(Arrays.asList("captain")); + person.setNicknames(Collections.singletonList("captain")); person.setEmailAddresses(Collections.singleton("test@example.org")); + person.setPhoneNumbers(Collections.singletonMap("private", "0351 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(); @@ -380,6 +464,10 @@ public void testIdentifiedFields() { Person::setNicknames); final SetProperty emailAddressesProperty = personWrapper.field("emailAddresses", Person::getEmailAddresses, Person::setEmailAddresses); + final MapProperty phoneNumbersProperty = personWrapper.field("phoneNumbers", + Person::getPhoneNumbers, + Person::setPhoneNumbers); + final StringProperty nameProperty2 = personWrapper.field("name", Person::getName, Person::setName); final IntegerProperty ageProperty2 = personWrapper.field("age", Person::getAge, Person::setAge); @@ -387,17 +475,22 @@ public void testIdentifiedFields() { Person::setNicknames); final SetProperty emailAddressesProperty2 = personWrapper.field("emailAddresses", Person::getEmailAddresses, Person::setEmailAddresses); + final MapProperty phoneNumbersProperty2 = personWrapper.field("phoneNumbers", + Person::getPhoneNumbers, + Person::setPhoneNumbers); assertThat(nameProperty).isSameAs(nameProperty2); assertThat(ageProperty).isSameAs(ageProperty2); assertThat(nicknamesProperty).isSameAs(nicknamesProperty2); assertThat(emailAddressesProperty).isSameAs(emailAddressesProperty2); + assertThat(phoneNumbersProperty).isSameAs(phoneNumbersProperty2); // with identified fields the "name" of the created properties should be set assertThat(nameProperty.getName()).isEqualTo("name"); assertThat(ageProperty.getName()).isEqualTo("age"); assertThat(nicknamesProperty.getName()).isEqualTo("nicknames"); assertThat(emailAddressesProperty.getName()).isEqualTo("emailAddresses"); + assertThat(phoneNumbersProperty.getName()).isEqualTo("phoneNumbers"); } @Test @@ -407,7 +500,8 @@ public void testIdentifiedFieldsWithImmutables() { .withName("horst") .withAge(32) .withNicknames(Collections.singletonList("captain")) - .withEmailAddresses(Collections.singleton("test@example.org")); + .withEmailAddresses(Collections.singleton("test@example.org")) + .withPhoneNumbers(Collections.singletonMap("private", "0351 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person1); @@ -418,6 +512,10 @@ public void testIdentifiedFieldsWithImmutables() { personWrapper.immutableField("nicknames", PersonImmutable::getNicknames, PersonImmutable::withNicknames); final SetProperty emailAddressesProperty = personWrapper.immutableField("emailAddresses", PersonImmutable::getEmailAddresses, PersonImmutable::withEmailAddresses); + final MapProperty phoneNumbersProperty = personWrapper.immutableField("phoneNumbers", + PersonImmutable::getPhoneNumbers, + PersonImmutable::withPhoneNumbers); + final StringProperty nameProperty2 = personWrapper .immutableField("name", PersonImmutable::getName, PersonImmutable::withName); @@ -426,16 +524,21 @@ public void testIdentifiedFieldsWithImmutables() { personWrapper.immutableField("nicknames", PersonImmutable::getNicknames, PersonImmutable::withNicknames); final SetProperty emailAddressesProperty2 = personWrapper.immutableField("emailAddresses", PersonImmutable::getEmailAddresses, PersonImmutable::withEmailAddresses); + final MapProperty phoneNumbersProperty2 = personWrapper.immutableField("phoneNumbers", + PersonImmutable::getPhoneNumbers, + PersonImmutable::withPhoneNumbers); assertThat(nameProperty).isSameAs(nameProperty2); assertThat(ageProperty).isSameAs(ageProperty2); assertThat(nicknamesProperty).isSameAs(nicknamesProperty2); assertThat(emailAddressesProperty).isSameAs(emailAddressesProperty2); + assertThat(phoneNumbersProperty).isSameAs(phoneNumbersProperty2); assertThat(nameProperty.getName()).isEqualTo("name"); assertThat(ageProperty.getName()).isEqualTo("age"); assertThat(nicknamesProperty.getName()).isEqualTo("nicknames"); assertThat(emailAddressesProperty.getName()).isEqualTo("emailAddresses"); + assertThat(phoneNumbersProperty.getName()).isEqualTo("phoneNumbers"); } @Test @@ -443,7 +546,9 @@ public void testDirtyFlag() { Person person = new Person(); person.setName("horst"); person.setAge(32); - person.setNicknames(Arrays.asList("captain")); + person.setNicknames(Collections.singletonList("captain")); + person.setEmailAddresses(Collections.singleton("test@example.org")); + person.setPhoneNumbers(Collections.singletonMap("private", "+49 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -452,6 +557,10 @@ public void testDirtyFlag() { final StringProperty name = personWrapper.field(Person::getName, Person::setName); final IntegerProperty age = personWrapper.field(Person::getAge, Person::setAge); final ListProperty nicknames = personWrapper.field(Person::getNicknames, Person::setNicknames); + final SetProperty emailAddresses = personWrapper.field(Person::getEmailAddresses, + Person::setEmailAddresses); + final MapProperty phoneNumbers = personWrapper.field(Person::getPhoneNumbers, + Person::setPhoneNumbers); name.set("hugo"); @@ -496,6 +605,25 @@ public void testDirtyFlag() { personWrapper.reload(); assertThat(personWrapper.isDirty()).isFalse(); + + emailAddresses.setValue(FXCollections.observableSet("player@example.org")); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reset(); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reload(); + assertThat(personWrapper.isDirty()).isFalse(); + + + phoneNumbers.setValue(observableMap("other", "+49 203204303")); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reset(); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reload(); + assertThat(personWrapper.isDirty()).isFalse(); } @Test @@ -503,6 +631,9 @@ public void testDirtyFlagWithFxProperties() { PersonFX person = new PersonFX(); person.setName("horst"); person.setAge(32); + person.setNicknames(Collections.singletonList("captain")); + person.setEmailAddresses(Collections.singleton("test@example.org")); + person.setPhoneNumbers(Collections.singletonMap("private", "+49 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -511,6 +642,8 @@ public void testDirtyFlagWithFxProperties() { final StringProperty name = personWrapper.field(PersonFX::nameProperty); final IntegerProperty age = personWrapper.field(PersonFX::ageProperty); final ListProperty nicknames = personWrapper.field(PersonFX::nicknamesProperty); + final SetProperty emailAddresses = personWrapper.field(PersonFX::emailAddressesProperty); + final MapProperty phoneNumbers = personWrapper.field(PersonFX::phoneNumbersProperty); name.set("hugo"); @@ -554,6 +687,27 @@ public void testDirtyFlagWithFxProperties() { personWrapper.reload(); assertThat(personWrapper.isDirty()).isFalse(); + + + + emailAddresses.setValue(FXCollections.observableSet("player@example.org")); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reset(); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reload(); + assertThat(personWrapper.isDirty()).isFalse(); + + + phoneNumbers.setValue(observableMap("other", "+49 203204303")); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reset(); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reload(); + assertThat(personWrapper.isDirty()).isFalse(); } @Test @@ -562,7 +716,9 @@ public void testDirtyFlagWithImmutables() { PersonImmutable person = PersonImmutable.create() .withName("horst") .withAge(32) - .withNicknames(Collections.singletonList("captain")); + .withNicknames(Collections.singletonList("captain")) + .withEmailAddresses(Collections.singleton("test@example.org")) + .withPhoneNumbers(Collections.singletonMap("private", "+49 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -573,6 +729,10 @@ public void testDirtyFlagWithImmutables() { final IntegerProperty age = personWrapper.immutableField(PersonImmutable::getAge, PersonImmutable::withAge); final ListProperty nicknames = personWrapper.immutableField(PersonImmutable::getNicknames, PersonImmutable::withNicknames); + final SetProperty emailAddresses = personWrapper.field(PersonImmutable::getEmailAddresses, + PersonImmutable::withEmailAddresses); + final MapProperty phoneNumbers = personWrapper.field(PersonImmutable::getPhoneNumbers, + PersonImmutable::withPhoneNumbers); name.set("hugo"); @@ -616,6 +776,27 @@ public void testDirtyFlagWithImmutables() { personWrapper.reload(); assertThat(personWrapper.isDirty()).isFalse(); + + + + emailAddresses.setValue(FXCollections.observableSet("player@example.org")); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reset(); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reload(); + assertThat(personWrapper.isDirty()).isFalse(); + + + phoneNumbers.setValue(observableMap("other", "+49 203204303")); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reset(); + assertThat(personWrapper.isDirty()).isTrue(); + + personWrapper.reload(); + assertThat(personWrapper.isDirty()).isFalse(); } @Test @@ -623,8 +804,9 @@ public void testDifferentFlag() { Person person = new Person(); person.setName("horst"); person.setAge(32); - person.setNicknames(Arrays.asList("captain")); + person.setNicknames(Collections.singletonList("captain")); person.setEmailAddresses(Collections.singleton("test@example.org")); + person.setPhoneNumbers(Collections.singletonMap("private", "0351 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -634,6 +816,7 @@ public void testDifferentFlag() { final IntegerProperty age = personWrapper.field(Person::getAge, Person::setAge); final ListProperty nicknames = personWrapper.field(Person::getNicknames, Person::setNicknames); final SetProperty emailAddresses = personWrapper.field(Person::getEmailAddresses, Person::setEmailAddresses); + final MapProperty phoneNumbers = personWrapper.field(Person::getPhoneNumbers, Person::setPhoneNumbers); assertThat(personWrapper.isDifferent()).isFalse(); @@ -713,6 +896,15 @@ public void testDifferentFlag() { personWrapper.reset(); assertThat(personWrapper.isDifferent()).isTrue(); + + personWrapper.reload(); + assertThat(personWrapper.isDifferent()).isFalse(); + + phoneNumbers.set(observableMap("other", "+49 12445")); + assertThat(personWrapper.isDifferent()).isTrue(); + + phoneNumbers.remove("other"); + assertThat(personWrapper.isDifferent()).isFalse(); } @@ -721,8 +913,9 @@ public void testDifferentFlagWithFxProperties() { PersonFX person = new PersonFX(); person.setName("horst"); person.setAge(32); - person.setNicknames(Arrays.asList("captain")); + person.setNicknames(Collections.singletonList("captain")); person.setEmailAddresses(Collections.singleton("test@example.org")); + person.setPhoneNumbers(Collections.singletonMap("private", "0351 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -732,6 +925,7 @@ public void testDifferentFlagWithFxProperties() { final IntegerProperty age = personWrapper.field(PersonFX::ageProperty); final ListProperty nicknames = personWrapper.field(PersonFX::nicknamesProperty); final SetProperty emailAddresses = personWrapper.field(PersonFX::emailAddressesProperty); + final MapProperty phoneNumbers = personWrapper.field(PersonFX::phoneNumbersProperty); name.set("hugo"); assertThat(personWrapper.isDifferent()).isTrue(); @@ -795,6 +989,16 @@ public void testDifferentFlagWithFxProperties() { personWrapper.reset(); assertThat(personWrapper.isDifferent()).isTrue(); + + personWrapper.reload(); + assertThat(personWrapper.isDifferent()).isFalse(); + + phoneNumbers.put("other", "+49 12445"); + assertThat(personWrapper.isDifferent()).isTrue(); + + phoneNumbers.remove("other"); + assertThat(personWrapper.isDifferent()).isFalse(); + } @Test @@ -802,7 +1006,9 @@ public void testDifferentFlagWithImmutables() { PersonImmutable person = PersonImmutable.create() .withName("horst") .withAge(32) - .withNicknames(Collections.singletonList("captain")); + .withNicknames(Collections.singletonList("captain")) + .withEmailAddresses(Collections.singleton("test@example.org")) + .withPhoneNumbers(Collections.singletonMap("private", "+49 12342434")); ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -813,6 +1019,11 @@ public void testDifferentFlagWithImmutables() { final IntegerProperty age = personWrapper.immutableField(PersonImmutable::getAge, PersonImmutable::withAge); final ListProperty nicknames = personWrapper.immutableField(PersonImmutable::getNicknames, PersonImmutable::withNicknames); + final SetProperty emailAddresses = personWrapper.immutableField(PersonImmutable::getEmailAddresses, + PersonImmutable::withEmailAddresses); + final MapProperty phoneNumbers = + personWrapper.immutableField(PersonImmutable::getPhoneNumbers, + PersonImmutable::withPhoneNumbers); name.set("hugo"); assertThat(personWrapper.isDifferent()).isTrue(); @@ -849,6 +1060,16 @@ public void testDifferentFlagWithImmutables() { nicknames.add("player"); assertThat(personWrapper.isDifferent()).isTrue(); + + personWrapper.reload(); + assertThat(personWrapper.isDifferent()).isFalse(); + + phoneNumbers.put("other", "+49 12445"); + assertThat(personWrapper.isDifferent()).isTrue(); + + phoneNumbers.remove("other"); + assertThat(personWrapper.isDifferent()).isFalse(); + } @Test @@ -856,8 +1077,9 @@ public void defaultValuesCanBeUpdatedToCurrentValues() { final Person person = new Person(); person.setName("horst"); person.setAge(32); - person.setNicknames(Arrays.asList("captain")); + person.setNicknames(Collections.singletonList("captain")); person.setEmailAddresses(Collections.singleton("test@example.org")); + person.setPhoneNumbers(Collections.singletonMap("private", "+49 11223434")); final ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -894,6 +1116,17 @@ public void defaultValuesCanBeUpdatedToCurrentValues() { personWrapper.useCurrentValuesAsDefaults(); personWrapper.reset(); assertThat(person.getEmailAddresses()).containsExactly("hugo@example.org"); + + + final MapProperty phoneNumbers = personWrapper.field(Person::getPhoneNumbers, + Person::setPhoneNumbers, + person.getPhoneNumbers()); + phoneNumbers.put("other", "112324232"); + phoneNumbers.remove("private"); + personWrapper.commit(); + personWrapper.useCurrentValuesAsDefaults(); + personWrapper.reset(); + assertThat(person.getPhoneNumbers()).containsExactly(MapEntry.entry("other", "112324232")); } @Test @@ -902,7 +1135,8 @@ public void defaultValuesCanBeUpdatedToCurrentValuesWithImmutables() { .withName("Luise") .withAge(32) .withNicknames(Collections.singletonList("captain")) - .withEmailAddresses(Collections.singleton("test@example.org")); + .withEmailAddresses(Collections.singleton("test@example.org")) + .withPhoneNumbers(Collections.singletonMap("private", "+49 1234567")); ModelWrapper personWrapper = new ModelWrapper<>(person); @@ -918,6 +1152,9 @@ public void defaultValuesCanBeUpdatedToCurrentValuesWithImmutables() { final SetProperty emailAddresses = personWrapper.immutableField(PersonImmutable::getEmailAddresses, PersonImmutable::withEmailAddresses, person.getEmailAddresses()); + final MapProperty phoneNumbers = personWrapper.immutableField(PersonImmutable::getPhoneNumbers, + PersonImmutable::withPhoneNumbers, person.getPhoneNumbers()); + name.set("test"); personWrapper.commit(); personWrapper.useCurrentValuesAsDefaults(); @@ -943,6 +1180,14 @@ public void defaultValuesCanBeUpdatedToCurrentValuesWithImmutables() { personWrapper.useCurrentValuesAsDefaults(); personWrapper.reset(); assertThat(emailAddresses.get()).containsExactly("hugo@example.org"); + + + phoneNumbers.put("other", "1234567"); + phoneNumbers.remove("private"); + personWrapper.commit(); + personWrapper.useCurrentValuesAsDefaults(); + personWrapper.reset(); + assertThat(phoneNumbers.get()).containsExactly(MapEntry.entry("other", "1234567")); } @Test @@ -950,13 +1195,15 @@ public void valuesShouldBeUpdatedWhenModelInstanceChanges() { final Person person1 = new Person(); person1.setName("horst"); person1.setAge(32); - person1.setNicknames(Arrays.asList("captain")); + person1.setNicknames(Collections.singletonList("captain")); person1.setEmailAddresses(Collections.singleton("test@example.org")); + person1.setPhoneNumbers(Collections.singletonMap("private_Horst", "0351 1234567")); final Person person2 = new Person(); person2.setName("dieter"); person2.setAge(42); - person2.setNicknames(Arrays.asList("robin")); + person2.setNicknames(Collections.singletonList("robin")); person2.setEmailAddresses(Collections.singleton("dieter@example.org")); + person2.setPhoneNumbers(Collections.singletonMap("private_Dieter", "030 001199")); final SimpleObjectProperty modelProp = new SimpleObjectProperty<>(person1); @@ -968,23 +1215,28 @@ public void valuesShouldBeUpdatedWhenModelInstanceChanges() { .field(Person::getNicknames, Person::setNicknames, person1.getNicknames()); final SetProperty emailAddresses = personWrapper.field(Person::getEmailAddresses, Person::setEmailAddresses, person1.getEmailAddresses()); + final MapProperty phoneNumbers = personWrapper.field(Person::getPhoneNumbers, + Person::setPhoneNumbers, person1.getPhoneNumbers()); assertThat(nameField.get()).isEqualTo(person1.getName()); assertThat(ageField.get()).isEqualTo(person1.getAge()); assertThat(nicknames.get()).containsExactlyElementsOf(person1.getNicknames()); assertThat(emailAddresses.get()).containsExactlyElementsOf(person1.getEmailAddresses()); + assertThat(phoneNumbers.get().entrySet()).containsExactlyElementsOf(person1.getPhoneNumbers().entrySet()); modelProp.set(person2); assertThat(nameField.get()).isEqualTo(person2.getName()); assertThat(ageField.get()).isEqualTo(person2.getAge()); assertThat(nicknames.get()).containsExactlyElementsOf(person2.getNicknames()); assertThat(emailAddresses.get()).containsExactlyElementsOf(person2.getEmailAddresses()); + assertThat(phoneNumbers.get().entrySet()).containsExactlyElementsOf(person2.getPhoneNumbers().entrySet()); personWrapper.reset(); assertThat(nameField.get()).isEqualTo(person1.getName()); assertThat(ageField.get()).isEqualTo(person1.getAge()); assertThat(nicknames.get()).containsExactlyElementsOf(person1.getNicknames()); assertThat(emailAddresses.get()).containsExactlyElementsOf(person1.getEmailAddresses()); + assertThat(phoneNumbers.get().entrySet()).containsExactlyElementsOf(person1.getPhoneNumbers().entrySet()); } @Test @@ -993,13 +1245,15 @@ public void valuesShouldBeUpdatedWhenModelInstanceChangesWithImmutables() { .withName("horst") .withAge(32) .withNicknames(Collections.singletonList("captain")) - .withEmailAddresses(Collections.singleton("test@example.org")); + .withEmailAddresses(Collections.singleton("test@example.org")) + .withPhoneNumbers(Collections.singletonMap("private_Horst", "0351 1234567")); PersonImmutable person2 = PersonImmutable.create() .withName("dieter") .withAge(42) .withNicknames(Collections.singletonList("robin")) - .withEmailAddresses(Collections.singleton("dieter@example.org")); + .withEmailAddresses(Collections.singleton("dieter@example.org")) + .withPhoneNumbers(Collections.singletonMap("private_Dieter", "030 001199")); final SimpleObjectProperty modelProp = new SimpleObjectProperty<>(person1); @@ -1013,23 +1267,29 @@ public void valuesShouldBeUpdatedWhenModelInstanceChangesWithImmutables() { personWrapper.immutableField(PersonImmutable::getNicknames, PersonImmutable::withNicknames, person1.getNicknames()); final SetProperty emailAddresses = personWrapper.immutableField(PersonImmutable::getEmailAddresses, PersonImmutable::withEmailAddresses, person1.getEmailAddresses()); + final MapProperty phoneNumbers = personWrapper.immutableField(PersonImmutable::getPhoneNumbers, + PersonImmutable::withPhoneNumbers, + person1.getPhoneNumbers()); assertThat(nameField.get()).isEqualTo(person1.getName()); assertThat(ageField.get()).isEqualTo(person1.getAge()); assertThat(nicknames.get()).containsExactlyElementsOf(person1.getNicknames()); assertThat(emailAddresses.get()).containsExactlyElementsOf(person1.getEmailAddresses()); + assertThat(phoneNumbers.get().entrySet()).containsExactlyElementsOf(person1.getPhoneNumbers().entrySet()); modelProp.set(person2); assertThat(nameField.get()).isEqualTo(person2.getName()); assertThat(ageField.get()).isEqualTo(person2.getAge()); assertThat(nicknames.get()).containsExactlyElementsOf(person2.getNicknames()); assertThat(emailAddresses.get()).containsExactlyElementsOf(person2.getEmailAddresses()); + assertThat(phoneNumbers.get().entrySet()).containsExactlyElementsOf(person2.getPhoneNumbers().entrySet()); personWrapper.reset(); assertThat(nameField.get()).isEqualTo(person1.getName()); assertThat(ageField.get()).isEqualTo(person1.getAge()); assertThat(nicknames.get()).containsExactlyElementsOf(person1.getNicknames()); assertThat(emailAddresses.get()).containsExactlyElementsOf(person1.getEmailAddresses()); + assertThat(phoneNumbers.get().entrySet()).containsExactlyElementsOf(person1.getPhoneNumbers().entrySet()); } @Test @@ -1043,6 +1303,8 @@ public void testUseCurrentValuesAsDefaultWhenModelIsNull() { )); SetProperty emailAddresses = wrapper.field("emailAddresses", Person::getEmailAddresses, Person::setEmailAddresses, Collections.singleton("test@example.org")); + MapProperty phoneNumbers = wrapper.field("phoneNumbers", Person::getPhoneNumbers, + Person::setPhoneNumbers, Collections.singletonMap("private_Horst", "0351 1234567")); wrapper.reset(); @@ -1050,6 +1312,7 @@ public void testUseCurrentValuesAsDefaultWhenModelIsNull() { assertThat(age.get()).isEqualTo(12); assertThat(nicknames.get()).containsExactly("captain"); assertThat(emailAddresses.get()).containsExactly("test@example.org"); + assertThat(phoneNumbers.get()).containsOnly(MapEntry.entry("private_Horst", "0351 1234567")); wrapper.useCurrentValuesAsDefaults(); @@ -1060,6 +1323,7 @@ public void testUseCurrentValuesAsDefaultWhenModelIsNull() { assertThat(age.get()).isEqualTo(12); assertThat(nicknames.get()).containsExactly("captain"); assertThat(emailAddresses.get()).containsExactly("test@example.org"); + assertThat(phoneNumbers.get()).containsOnly(MapEntry.entry("private_Horst", "0351 1234567")); } @Test @@ -1067,7 +1331,7 @@ public void testDefaultValues() { final Person person = new Person(); person.setName("horst"); person.setAge(32); - person.setNicknames(Arrays.asList("captain")); + person.setNicknames(Collections.singletonList("captain")); ModelWrapper wrapperWithDefaults = new ModelWrapper<>(); ModelWrapper wrapperWithoutDefaults = new ModelWrapper<>(); @@ -1139,4 +1403,11 @@ public void testSet() { // then assertThat(person.getEmailAddresses()).containsOnly("test@example.org"); } + + + private ObservableMap observableMap(K key, V value) { + Map map = new HashMap<>(); + map.put(key, value); + return FXCollections.observableMap(map); + } } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/Person.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/Person.java index 46e6c2dd2..dd28e5d09 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/Person.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/Person.java @@ -16,8 +16,10 @@ package de.saxsys.mvvmfx.utils.mapping; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; public class Person { @@ -30,6 +32,8 @@ public class Person { private Set emailAddresses = new HashSet<>(); + private Map phoneNumbers = new HashMap<>(); + public List getNicknames() { return nicknames; } @@ -61,4 +65,12 @@ public String getName() { public void setName(String name) { this.name = name; } + + public Map getPhoneNumbers() { + return phoneNumbers; + } + + public void setPhoneNumbers(Map phoneNumbers) { + this.phoneNumbers = phoneNumbers; + } } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonFX.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonFX.java index 1b6b70b6e..64a1fc92c 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonFX.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonFX.java @@ -17,17 +17,22 @@ import javafx.beans.property.IntegerProperty; import javafx.beans.property.ListProperty; +import javafx.beans.property.MapProperty; import javafx.beans.property.SetProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.SimpleMapProperty; import javafx.beans.property.SimpleSetProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; +import javafx.collections.ObservableMap; import javafx.collections.ObservableSet; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; public class PersonFX { @@ -40,6 +45,9 @@ public class PersonFX { private SetProperty emailAddresses = new SimpleSetProperty<>(FXCollections.observableSet(new HashSet<>())); + private MapProperty phoneNumbers = new SimpleMapProperty<>( + FXCollections.observableMap(new HashMap<>())); + public String getName() { return name.get(); } @@ -87,4 +95,17 @@ public SetProperty emailAddressesProperty() { public void setEmailAddresses(Set emailAddresses) { this.emailAddresses.addAll(emailAddresses); } + + public Map getPhoneNumbers() { + return phoneNumbers.get(); + } + + public MapProperty phoneNumbersProperty() { + return phoneNumbers; + } + + public void setPhoneNumbers(Map phoneNumbers) { + this.phoneNumbers.clear(); + this.phoneNumbers.putAll(phoneNumbers); + } } diff --git a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonImmutable.java b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonImmutable.java index 984e5ef41..8bfe637c3 100644 --- a/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonImmutable.java +++ b/mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/mapping/PersonImmutable.java @@ -2,8 +2,10 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; public class PersonImmutable { @@ -13,15 +15,19 @@ public class PersonImmutable { private final Set emailAddresses = new HashSet<>(); + private final Map phoneNumbers = new HashMap<>(); + public static PersonImmutable create(){ - return new PersonImmutable("", 0, Collections.emptyList(), Collections.emptySet()); + return new PersonImmutable("", 0, Collections.emptyList(), Collections.emptySet(), Collections.emptyMap()); } - private PersonImmutable(String name, int age, List nicknames, Set emailAddresses) { + private PersonImmutable(String name, int age, List nicknames, Set emailAddresses, Map phoneNumbers) { this.name = name; this.age = age; this.nicknames.addAll(nicknames); this.emailAddresses.addAll(emailAddresses); + this.phoneNumbers.putAll(phoneNumbers); } public String getName() { @@ -29,7 +35,7 @@ public String getName() { } public PersonImmutable withName(String name) { - return new PersonImmutable(name, this.age, this.nicknames, this.emailAddresses); + return new PersonImmutable(name, this.age, this.nicknames, this.emailAddresses, this.phoneNumbers); } public int getAge() { @@ -37,7 +43,7 @@ public int getAge() { } public PersonImmutable withAge(int age) { - return new PersonImmutable(this.name, age, this.nicknames, this.emailAddresses); + return new PersonImmutable(this.name, age, this.nicknames, this.emailAddresses, this.phoneNumbers); } public List getNicknames() { @@ -45,7 +51,7 @@ public List getNicknames() { } public PersonImmutable withNicknames(List nicknames) { - return new PersonImmutable(this.name, this.age, nicknames, this.emailAddresses); + return new PersonImmutable(this.name, this.age, nicknames, this.emailAddresses, this.phoneNumbers); } public Set getEmailAddresses() { @@ -53,7 +59,14 @@ public Set getEmailAddresses() { } public PersonImmutable withEmailAddresses(Set emailAddresses) { - return new PersonImmutable(this.name, this.age, this.nicknames, emailAddresses); + return new PersonImmutable(this.name, this.age, this.nicknames, emailAddresses, this.phoneNumbers); + } + + public Map getPhoneNumbers() { + return Collections.unmodifiableMap(phoneNumbers); } + public PersonImmutable withPhoneNumbers(Map phoneNumbers) { + return new PersonImmutable(this.name, this.age, this.nicknames, this.emailAddresses, phoneNumbers); + } }