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/03/08 23:37:27 UTC

[46/52] [abbrv] wicket git commit: WICKET-5991 Introduce models which use Java 8 supplier/consumer

WICKET-5991 Introduce models which use Java 8 supplier/consumer

Add:
- LambdaModel - a model with supplier and consumer (dual to Model)
- SupplierModel - a read-only model that uses a Supplier to provide the object (dual to AbstractReadOnlyModel)
- SupplierCachingModel - a read-only model that uses a Supplier to provide the object. Caches the result until detached. (dual to LoadableDetachableModel)


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

Branch: refs/heads/lambdas
Commit: 414fc134cf719941bca6ed3e61e70c55d3b2f163
Parents: ebe8dfc
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Sun Oct 4 13:51:48 2015 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Tue Mar 8 23:16:54 2016 +0100

----------------------------------------------------------------------
 .../apache/wicket/model/lambda/LambdaModel.java | 103 +++++++++++++++++++
 .../model/lambda/SupplierCachingModel.java      |  79 ++++++++++++++
 .../wicket/model/lambda/SupplierModel.java      |  81 +++++++++++++++
 .../wicket/model/lambda/WicketConsumer.java     |  30 ++++++
 .../wicket/model/lambda/WicketFunction.java     |  32 ++++++
 .../wicket/model/lambda/WicketSupplier.java     |  30 ++++++
 .../wicket/model/lambda/LambdaModelTest.java    |  91 ++++++++++++++++
 .../org/apache/wicket/model/lambda/Person.java  |  37 +++++++
 .../model/lambda/SupplierCachingModelTest.java  |  92 +++++++++++++++++
 .../wicket/model/lambda/SupplierModelTest.java  |  92 +++++++++++++++++
 10 files changed, 667 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/wicket-core/src/main/java/org/apache/wicket/model/lambda/LambdaModel.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/model/lambda/LambdaModel.java b/wicket-core/src/main/java/org/apache/wicket/model/lambda/LambdaModel.java
new file mode 100644
index 0000000..2620680
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/model/lambda/LambdaModel.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import java.util.Objects;
+
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * <code>LambdaModel</code> is a basic implementation of an <code>IModel</code>
+ * that uses a serializable {@link java.util.function.Supplier} to get the object
+ * and {@link java.util.function.Consumer} to set it.
+ *
+ * The detach method defaults does nothing.
+ *
+ * @param <T> The type of the Model Object
+ */
+public class LambdaModel<T> implements IModel<T>
+{
+	private static final long serialVersionUID = 1L;
+
+	private final WicketSupplier<T> getter;
+	private final WicketConsumer<T> setter;
+
+	/**
+	 * Construct the model, using the given supplier and consumer as
+	 * implementation for getObject and setObject.
+	 *
+	 * @param getter Used for the getObject() method.
+	 * @param setter Used for the setObject(T object) method.
+	 */
+	public LambdaModel(WicketSupplier<T> getter, WicketConsumer<T> setter)
+	{
+		this.getter = Args.notNull(getter, "getter");
+		this.setter = Args.notNull(setter, "setter");
+	}
+
+	public static <T> LambdaModel<T> of(WicketSupplier<T> getter, WicketConsumer<T> setter)
+	{
+		return new LambdaModel<>(getter, setter);
+	}
+
+	@Override
+	public T getObject()
+	{
+		return getter.get();
+	}
+
+	@Override
+	public void setObject(T t)
+	{
+		setter.accept(t);
+	}
+
+	@Override
+	public void detach()
+	{
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return org.apache.wicket.util.lang.Objects.hashCode(getter, setter);
+	}
+
+	@Override
+	public boolean equals(Object obj)
+	{
+		if (obj == null)
+		{
+			return false;
+		}
+		if (getClass() != obj.getClass())
+		{
+			return false;
+		}
+		final LambdaModel<?> other = (LambdaModel<?>) obj;
+		if (!Objects.equals(this.getter, other.getter))
+		{
+			return false;
+		}
+		if (!Objects.equals(this.setter, other.setter))
+		{
+			return false;
+		}
+		return true;
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/wicket-core/src/main/java/org/apache/wicket/model/lambda/SupplierCachingModel.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/model/lambda/SupplierCachingModel.java b/wicket-core/src/main/java/org/apache/wicket/model/lambda/SupplierCachingModel.java
new file mode 100644
index 0000000..910eaad
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/model/lambda/SupplierCachingModel.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import java.util.Objects;
+
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * A caching model that gets its value from a {@link WicketSupplier}.
+ *
+ * @param <T>
+ *            - type of the model object
+ */
+public class SupplierCachingModel<T> extends LoadableDetachableModel<T>
+{
+	/**
+	 * Supplies the model object.
+	 */
+	private WicketSupplier<T> getter;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param getter
+	 *              The getter of the model object
+	 */
+	public SupplierCachingModel(WicketSupplier<T> getter)
+	{
+		this.getter = Args.notNull(getter, "getter");
+	}
+
+	@Override
+	protected final T load()
+	{
+		return getter.get();
+	}
+
+
+	@Override
+	public int hashCode()
+	{
+		return org.apache.wicket.util.lang.Objects.hashCode(getter);
+	}
+
+	@Override
+	public boolean equals(Object obj)
+	{
+		if (obj == null)
+		{
+			return false;
+		}
+		if (getClass() != obj.getClass())
+		{
+			return false;
+		}
+		final SupplierCachingModel<?> other = (SupplierCachingModel<?>) obj;
+		if (!Objects.equals(this.getter, other.getter))
+		{
+			return false;
+		}
+		return true;
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/wicket-core/src/main/java/org/apache/wicket/model/lambda/SupplierModel.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/model/lambda/SupplierModel.java b/wicket-core/src/main/java/org/apache/wicket/model/lambda/SupplierModel.java
new file mode 100644
index 0000000..3f167be
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/model/lambda/SupplierModel.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import java.util.Objects;
+
+import org.apache.wicket.model.AbstractReadOnlyModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * A caching model that gets its value from a {@link WicketSupplier}.
+ *
+ * @param <T>
+ *            - type of the model object
+ */
+public class SupplierModel<T> extends AbstractReadOnlyModel<T>
+{
+	/**
+	 * Supplies the model object.
+	 */
+	private WicketSupplier<T> getter;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param getter
+	 *              The getter of the model object
+	 */
+	public SupplierModel(WicketSupplier<T> getter)
+	{
+		this.getter = Args.notNull(getter, "getter");
+	}
+
+
+	@Override
+	public T getObject()
+	{
+		return getter.get();
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return org.apache.wicket.util.lang.Objects.hashCode(getter);
+	}
+
+	@Override
+	public boolean equals(Object obj)
+	{
+		if (obj == null)
+		{
+			return false;
+		}
+		if (getClass() != obj.getClass())
+		{
+			return false;
+		}
+		final SupplierModel<?> other = (SupplierModel<?>) obj;
+		if (!Objects.equals(this.getter, other.getter))
+		{
+			return false;
+		}
+		return true;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketConsumer.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketConsumer.java b/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketConsumer.java
new file mode 100644
index 0000000..fd67e32
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketConsumer.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import java.io.Serializable;
+import java.util.function.Consumer;
+
+/**
+ * A {@link Serializable} {@link Consumer}.
+ *
+ * @param <T>
+ *            - the type of the input to consume
+ */
+public interface WicketConsumer<T> extends Consumer<T>, Serializable
+{
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketFunction.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketFunction.java b/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketFunction.java
new file mode 100644
index 0000000..6c1fcec
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketFunction.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import java.io.Serializable;
+import java.util.function.Function;
+
+/**
+ * A {@link Serializable} {@link Function}.
+ *
+ * @param <T>
+ *            - the type of the input to the function
+ * @param <R>
+ *            - the type of the result of the function
+ */
+public interface WicketFunction<T, R> extends Function<T, R>, Serializable
+{
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketSupplier.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketSupplier.java b/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketSupplier.java
new file mode 100644
index 0000000..d876d77
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/model/lambda/WicketSupplier.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import java.io.Serializable;
+import java.util.function.Supplier;
+
+/**
+ * A {@link Serializable} {@link Supplier}.
+ *
+ * @param <T>
+ *            - the type of results supplied by this supplier
+ */
+public interface WicketSupplier<T> extends Supplier<T>, Serializable
+{
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/wicket-core/src/test/java/org/apache/wicket/model/lambda/LambdaModelTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/model/lambda/LambdaModelTest.java b/wicket-core/src/test/java/org/apache/wicket/model/lambda/LambdaModelTest.java
new file mode 100644
index 0000000..8bf21ae
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/model/lambda/LambdaModelTest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.*;
+
+import org.apache.wicket.core.util.lang.WicketObjects;
+import org.apache.wicket.model.IModel;
+import org.junit.Test;
+
+/**
+ * Tests for {@link LambdaModel}
+ */
+public class LambdaModelTest
+{
+	@Test
+	public void methodReference()
+	{
+		Person person = new Person();
+		IModel<String> personNameModel = new LambdaModel<>(person::getName, person::setName);
+		check(personNameModel);
+	}
+
+	@Test
+	public void explicitLambdas()
+	{
+		Person person = new Person();
+		IModel<String> personNameModel = new LambdaModel<>(
+				() -> person.getName(),
+				(name) -> person.setName(name));
+		check(personNameModel);
+	}
+
+	@Test
+	public void equality()
+	{
+		Person person = new Person();
+		final WicketSupplier<String> getName = person::getName;
+		final WicketConsumer<String> setName = person::setName;
+		IModel<String> personNameModel1 = new LambdaModel<>(getName, setName);
+		IModel<String> personNameModel2 = new LambdaModel<>(getName, setName);
+		assertEquals(personNameModel1, personNameModel2);
+	}
+
+	@Test
+	public void hashcode()
+	{
+		Person person = new Person();
+		final WicketSupplier<String> getName = person::getName;
+		final WicketConsumer<String> setName = person::setName;
+		IModel<String> personNameModel1 = new LambdaModel<>(getName, setName);
+		IModel<String> personNameModel2 = new LambdaModel<>(getName, setName);
+		assertEquals(personNameModel1.hashCode(), personNameModel2.hashCode());
+	}
+
+	private void check(IModel<String> personNameModel)
+	{
+		assertThat(personNameModel.getObject(), is(nullValue()));
+
+		final String personName = "new name";
+		personNameModel.setObject(personName);
+		assertThat(personNameModel.getObject(), is(personName));
+
+		serialize(personNameModel, personName);
+	}
+
+	private void serialize(IModel<String> personNameModel, String personName)
+	{
+		final IModel<String> clone = WicketObjects.cloneObject(personNameModel);
+		assertThat(clone, is(instanceOf(LambdaModel.class)));
+		assertThat(clone.getObject(), is(personName));
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/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
new file mode 100644
index 0000000..79f114c
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/model/lambda/Person.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import java.io.Serializable;
+
+/**
+ * A test object for lambda related tests
+ */
+class Person implements Serializable
+{
+	private String name;
+
+	public String getName()
+	{
+		return name;
+	}
+
+	public void setName(String name)
+	{
+		this.name = name;
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/wicket-core/src/test/java/org/apache/wicket/model/lambda/SupplierCachingModelTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/model/lambda/SupplierCachingModelTest.java b/wicket-core/src/test/java/org/apache/wicket/model/lambda/SupplierCachingModelTest.java
new file mode 100644
index 0000000..dc2208d
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/model/lambda/SupplierCachingModelTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.wicket.core.util.lang.WicketObjects;
+import org.apache.wicket.model.IModel;
+import org.junit.Test;
+
+/**
+ * Tests for {@link SupplierCachingModel}
+ */
+public class SupplierCachingModelTest
+{
+	@Test
+	public void caching()
+	{
+		// given
+		Person person = mock(Person.class);
+		when(person.getName()).thenReturn("The person's name");
+		IModel<String> personNameModel = new SupplierCachingModel<>(person::getName);
+
+		// when
+
+		// once
+		personNameModel.getObject();
+		personNameModel.getObject();
+
+		personNameModel.detach();
+		// twice
+		personNameModel.getObject();
+		personNameModel.getObject();
+		personNameModel.getObject();
+
+		// then
+		verify(person, times(2)).getName();
+	}
+
+	@Test
+	public void serialize()
+	{
+		Person person = new Person();
+		final String personName = "The person's name";
+		person.setName(personName);
+		final WicketSupplier<String> getName = person::getName;
+		IModel<String> personNameModel = new SupplierCachingModel<>(getName);
+
+		final IModel<String> clone = WicketObjects.cloneObject(personNameModel);
+		assertThat(clone.getObject(), is(personName));
+	}
+
+	@Test
+	public void equality()
+	{
+		Person person = new Person();
+		final WicketSupplier<String> getName = person::getName;
+		IModel<String> personNameModel1 = new SupplierCachingModel<>(getName);
+		IModel<String> personNameModel2 = new SupplierCachingModel<>(getName);
+		assertEquals(personNameModel1, personNameModel2);
+	}
+
+	@Test
+	public void hashcode()
+	{
+		Person person = new Person();
+		final WicketSupplier<String> getName = person::getName;
+		IModel<String> personNameModel1 = new SupplierCachingModel<>(getName);
+		IModel<String> personNameModel2 = new SupplierCachingModel<>(getName);
+		assertEquals(personNameModel1.hashCode(), personNameModel2.hashCode());
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/414fc134/wicket-core/src/test/java/org/apache/wicket/model/lambda/SupplierModelTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/model/lambda/SupplierModelTest.java b/wicket-core/src/test/java/org/apache/wicket/model/lambda/SupplierModelTest.java
new file mode 100644
index 0000000..384dd89
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/model/lambda/SupplierModelTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.model.lambda;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.wicket.core.util.lang.WicketObjects;
+import org.apache.wicket.model.IModel;
+import org.junit.Test;
+
+/**
+ * Tests for {@link SupplierModel}
+ */
+public class SupplierModelTest
+{
+	@Test
+	public void nocaching()
+	{
+		// given
+		Person person = mock(Person.class);
+		when(person.getName()).thenReturn("The person's name");
+		IModel<String> personNameModel = new SupplierModel<>(person::getName);
+
+		// when
+
+		// once
+		personNameModel.getObject();
+		personNameModel.getObject();
+
+		personNameModel.detach();
+		// twice
+		personNameModel.getObject();
+		personNameModel.getObject();
+		personNameModel.getObject();
+
+		// then
+		verify(person, times(5)).getName();
+	}
+
+	@Test
+	public void serialize()
+	{
+		Person person = new Person();
+		final String personName = "The person's name";
+		person.setName(personName);
+		final WicketSupplier<String> getName = person::getName;
+		IModel<String> personNameModel = new SupplierModel<>(getName);
+
+		final IModel<String> clone = WicketObjects.cloneObject(personNameModel);
+		assertThat(clone.getObject(), is(personName));
+	}
+
+	@Test
+	public void equality()
+	{
+		Person person = new Person();
+		final WicketSupplier<String> getName = person::getName;
+		IModel<String> personNameModel1 = new SupplierModel<>(getName);
+		IModel<String> personNameModel2 = new SupplierModel<>(getName);
+		assertEquals(personNameModel1, personNameModel2);
+	}
+
+	@Test
+	public void hashcode()
+	{
+		Person person = new Person();
+		final WicketSupplier<String> getName = person::getName;
+		IModel<String> personNameModel1 = new SupplierModel<>(getName);
+		IModel<String> personNameModel2 = new SupplierModel<>(getName);
+		assertEquals(personNameModel1.hashCode(), personNameModel2.hashCode());
+	}
+}