You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by mg...@apache.org on 2016/04/24 17:14:25 UTC

wicket git commit: Add filter/map/flatMap/orElse/orElseGet methods to IModel

Repository: wicket
Updated Branches:
  refs/heads/monad-model [created] 484132a85


Add filter/map/flatMap/orElse/orElseGet methods to IModel

discussion-at: http://markmail.org/message/i34iulxttjc7umij


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/484132a8
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/484132a8
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/484132a8

Branch: refs/heads/monad-model
Commit: 484132a85c81fe96878d1c93e19940fb71d6f10f
Parents: f2f0ba0
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Sun Apr 24 17:11:53 2016 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Sun Apr 24 17:11:53 2016 +0200

----------------------------------------------------------------------
 .../java/org/apache/wicket/model/IModel.java    | 185 +++++++++++++++++++
 .../apache/wicket/model/LambdaModelTest.java    |  18 +-
 .../org/apache/wicket/model/lambda/Person.java  |  40 ++++
 3 files changed, 242 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/484132a8/wicket-core/src/main/java/org/apache/wicket/model/IModel.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/model/IModel.java b/wicket-core/src/main/java/org/apache/wicket/model/IModel.java
index 53994ae..789d27a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/model/IModel.java
+++ b/wicket-core/src/main/java/org/apache/wicket/model/IModel.java
@@ -17,6 +17,10 @@
 package org.apache.wicket.model;
 
 
+import org.apache.wicket.lambda.WicketBiFunction;
+import org.apache.wicket.lambda.WicketFunction;
+import org.apache.wicket.lambda.WicketSupplier;
+
 /**
  * A IModel wraps the actual model Object used by a Component. IModel implementations are used as a
  * facade for the real model so that users have control over the actual persistence strategy. Note
@@ -78,4 +82,185 @@ public interface IModel<T> extends IDetachable
 
 	@Override
 	default void detach() {}
+
+	/**
+	 * Returns a IModel checking whether the predicate holds for the
+	 * contained object, if it is not null. If the predicate doesn't evaluate
+	 * to true, the contained object will be null.
+	 *
+	 * @param predicate a predicate to be used for testing the contained object
+	 * @return a new IModel
+	 */
+	default IModel<T> filter(WicketFunction<T, Boolean> predicate) {
+		return (IModel<T>) () -> {
+			T object = IModel.this.getObject();
+			if (object != null && predicate.apply(object)) {
+				return object;
+			}
+			else {
+				return null;
+			}
+		};
+	}
+
+	/**
+	 * Returns a IModel applying the given mapper to
+	 * the contained object, if it is not NULL.
+	 *
+	 * @param <R> the new type of the contained object
+	 * @param mapper a mapper, to be applied to the contained object
+	 * @return a new IModel
+	 */
+	default <R> IModel<R> map(WicketFunction<T, R> mapper) {
+		return (IModel<R>) () -> {
+			T object = IModel.this.getObject();
+			if (object == null) {
+				return null;
+			}
+			else {
+				return mapper.apply(object);
+			}
+		};
+	}
+
+	/**
+	 * Returns a IModel applying the given combining function to
+	 * the contained object of this and the given other model, if they are not null.
+	 *
+	 * @param <R> the resulting type
+	 * @param <U> the other models type
+	 * @param combine a function combining this and the others object to
+	 * a result.
+	 * @param other another model to be combined with this one
+	 * @return a new IModel
+	 */
+	default <R, U> IModel<R> mapWith(WicketBiFunction<T, U, R> combine, IModel<U> other) {
+		return (IModel<R>) () -> {
+			T t = IModel.this.getObject();
+			U u = other.getObject();
+			if (t != null && u != null) {
+				return combine.apply(t, u);
+			}
+			else {
+				return null;
+			}
+		};
+	}
+
+	/**
+	 * Returns a IModel applying the given mapper to the contained
+	 * object, if it is not NULL.
+	 *
+	 * @param <R> the new type of the contained object
+	 * @param mapper a mapper, to be applied to the contained object
+	 * @return a new IModel
+	 */
+	default <R> IModel<R> flatMap(WicketFunction<T, IModel<R>> mapper) {
+		return (IModel<R>) () -> {
+			T object = IModel.this.getObject();
+			if (object == null) {
+				return null;
+			}
+			else {
+				return mapper.apply(object).getObject();
+			}
+		};
+	}
+
+	/**
+	 * Returns a IModel applying the {@link WicketFunction} contained
+	 * inside the given model to the object contained inside this model.
+	 *
+	 * @param <R> the type of the new contained object
+	 * @param mapper an {@link IModel} containing a function to be applied
+	 * to the contained model object.
+	 * @return a new IModel
+	 */
+	default <R> IModel<R> apply(IModel<WicketFunction<T, R>> mapper) {
+		return (IModel<R>) () -> {
+			T object = IModel.this.getObject();
+			WicketFunction<T, R> f = mapper.getObject();
+			if (object == null || f == null) {
+				return null;
+			}
+			else {
+				return f.apply(object);
+			}
+		};
+	}
+
+	/**
+	 * Returns a IModel, returning either the contained object
+	 * or the given default value, depending on the nullness of the
+	 * contained object.
+	 *
+	 * @param other a default value
+	 * @return a new IModel
+	 */
+	default IModel<T> orElse(T other) {
+		return (IModel<T>) () -> {
+			T object = IModel.this.getObject();
+			if (object == null) {
+				return other;
+			}
+			else {
+				return object;
+			}
+		};
+	}
+
+	/**
+	 * Returns a IModel, returning either the contained object
+	 * or invoking the given supplier to get a default value.
+	 *
+	 * @param other a supplier to be used as a default
+	 * @return a new IModel
+	 */
+	default IModel<T> orElseGet(WicketSupplier<T> other) {
+		return (IModel<T>) () -> {
+			T object = IModel.this.getObject();
+			if (object == null) {
+				return other.get();
+			}
+			else {
+				return object;
+			}
+		};
+	}
+
+	/**
+	 * Returns a IModel lifting the given object into the
+	 * Model.
+	 *
+	 * @param <T> the type of the given object
+	 * @param object an object to be lifted into a IModel
+	 * @return a new IModel
+	 */
+	static <T> IModel<T> of(T object) {
+		return of((WicketSupplier<T>) () -> object);
+	}
+
+	/**
+	 * Returns a IModel applying the given supplier to
+	 * get the object.
+	 *
+	 * @param <T> the type of the given object
+	 * @param supplier a supplier, to be used to get a value
+	 * @return a new IModel
+	 */
+	static <T> IModel<T> of(WicketSupplier<T> supplier) {
+		return (IModel<T>) () -> supplier.get();
+	}
+
+	/**
+	 * Returns a IModel using the getObject() method
+	 * of the given model.
+	 *
+	 * @param <T> the type of the contained object
+	 * @param model a model,
+	 * @return a new IModel
+	 */
+	static <T> IModel<T> of(IModel<T> model) {
+		return (IModel<T>) () -> model.getObject();
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/484132a8/wicket-core/src/test/java/org/apache/wicket/model/LambdaModelTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/model/LambdaModelTest.java b/wicket-core/src/test/java/org/apache/wicket/model/LambdaModelTest.java
index 8bb31ff..597ed16 100644
--- a/wicket-core/src/test/java/org/apache/wicket/model/LambdaModelTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/model/LambdaModelTest.java
@@ -38,8 +38,24 @@ public class LambdaModelTest
 	public void methodReference()
 	{
 		Person person = new Person();
+		person.setName("john");
+		Person.Address address = new Person.Address();
+		person.setAddress(address);
+//		address.setStreet("Street");
+		address.setNumber(123);
+
 		IModel<String> personNameModel = new LambdaModel<>(person::getName, person::setName);
-		check(personNameModel);
+//		check(personNameModel);
+
+		IModel<Person.Address> addressModel = Model.<Person>of(Model.of(person))
+					.filter((p) -> p.getName().equals("john"))
+					.map(Person::getAddress);
+
+		System.err.println("addressModel= " + addressModel
+					.flatMap(address1 -> Model.loadableDetachable(() -> address1))
+					.map(Person.Address::getStreet)
+					.orElse("N/A")
+					.getObject());
 	}
 
 	@Test

http://git-wip-us.apache.org/repos/asf/wicket/blob/484132a8/wicket-core/src/test/java/org/apache/wicket/model/lambda/Person.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/model/lambda/Person.java b/wicket-core/src/test/java/org/apache/wicket/model/lambda/Person.java
index 4e4e74a..0134c46 100644
--- a/wicket-core/src/test/java/org/apache/wicket/model/lambda/Person.java
+++ b/wicket-core/src/test/java/org/apache/wicket/model/lambda/Person.java
@@ -25,6 +25,8 @@ public class Person implements Serializable
 {
 	private String name;
 
+	private Address address;
+
 	public String getName()
 	{
 		return name;
@@ -34,4 +36,42 @@ public class Person implements Serializable
 	{
 		this.name = name;
 	}
+
+	public Address getAddress()
+	{
+		return address;
+	}
+
+	public void setAddress(Address address)
+	{
+		this.address = address;
+	}
+
+	public static class Address implements Serializable
+	{
+		private String street;
+
+		private int number;
+
+		public String getStreet()
+		{
+			return street;
+		}
+
+		public void setStreet(String street)
+		{
+			this.street = street;
+		}
+
+		public int getNumber()
+		{
+			return number;
+		}
+
+		public void setNumber(int number)
+		{
+			this.number = number;
+		}
+	}
+
 }