You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2018/02/28 22:16:19 UTC
[isis] branch master updated: ISIS-1841 reinventing ObjectContracts
moving previous version to legacy
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push:
new 6a279e1 ISIS-1841 reinventing ObjectContracts moving previous version to legacy
6a279e1 is described below
commit 6a279e14ac117529e70742791715f20158036384
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Feb 28 23:16:15 2018 +0100
ISIS-1841 reinventing ObjectContracts moving previous version to legacy
---
.../apache/isis/applib/internal/base/_Strings.java | 4 +-
.../java/org/apache/isis/applib/util/Equality.java | 57 ++++
.../java/org/apache/isis/applib/util/Hashing.java | 48 +++
.../apache/isis/applib/util/ObjectContracts.java | 352 +++++----------------
.../java/org/apache/isis/applib/util/ToString.java | 63 ++++
5 files changed, 244 insertions(+), 280 deletions(-)
diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/base/_Strings.java b/core/applib/src/main/java/org/apache/isis/applib/internal/base/_Strings.java
index c7340fb..247e89c 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/internal/base/_Strings.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/internal/base/_Strings.java
@@ -60,7 +60,7 @@ public final class _Strings {
* (a duplicate of in {@link _Constants.emptyStringArray} )
*/
public final static String[] emptyArray = new String[0];
-
+
// -- BASIC PREDICATES
/**
@@ -211,7 +211,7 @@ public final class _Strings {
}
return sb.toString();
}
-
+
// -- SPLITTING
/**
diff --git a/core/applib/src/main/java/org/apache/isis/applib/util/Equality.java b/core/applib/src/main/java/org/apache/isis/applib/util/Equality.java
new file mode 100644
index 0000000..20d1c0c
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/util/Equality.java
@@ -0,0 +1,57 @@
+package org.apache.isis.applib.util;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+import org.apache.isis.applib.internal.base._Casts;
+import org.apache.isis.applib.internal.collections._Lists;
+
+/**
+ * Fluent Object Equality Composition.
+ *
+ * @param <T>
+ * @since 2.0.0
+ */
+public class Equality<T> {
+
+ public static <T> Equality<T> checkEquals(Function<T, ?> getter) {
+ Objects.requireNonNull(getter);
+ return new Equality<>(getter);
+ }
+
+ private final List<Function<T, ?>> chain = _Lists.newArrayList();
+
+ private Equality(Function<T, ?> getter) {
+ chain.add(getter);
+ }
+
+ public Equality<T> thenCheckEquals(Function<T, ?> getter){
+ Objects.requireNonNull(getter);
+ chain.add(getter);
+ return this;
+ }
+
+ public boolean equals(T target, Object other){
+ if(target==null && other==null) {
+ return true;
+ }
+ if(target==null || other==null) {
+ return false;
+ }
+ if(target.getClass() != other.getClass()) {
+ return false;
+ }
+ final T o = _Casts.uncheckedCast(other);
+
+ for(Function<T, ?> getter : chain) {
+ if(!Objects.equals(getter.apply(target), getter.apply(o)))
+ return false;
+ }
+
+ return true;
+ }
+
+
+
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/util/Hashing.java b/core/applib/src/main/java/org/apache/isis/applib/util/Hashing.java
new file mode 100644
index 0000000..9f5fdd8
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/util/Hashing.java
@@ -0,0 +1,48 @@
+package org.apache.isis.applib.util;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+import org.apache.isis.applib.internal.collections._Lists;
+
+/**
+ * Fluent Object Hash Code Composition.
+ *
+ * @param <T>
+ * @since 2.0.0
+ *
+ */
+public class Hashing<T> {
+
+ public static <T> Hashing<T> hashing(Function<T, ?> getter){
+ return new Hashing<>(getter);
+ }
+
+ private final List<Function<T, ?>> getters = _Lists.newArrayList();
+
+ private Hashing(Function<T, ?> getter) {
+ getters.add(getter);
+ }
+
+ public Hashing<T> thenHashing(Function<T, ?> getter){
+ Objects.requireNonNull(getter);
+ getters.add(getter);
+ return this;
+ }
+
+ public int hashCode(T object){
+ if(object==null) {
+ return 0;
+ }
+ int result = 1;
+ for(Function<T, ?> getter : getters) {
+ final Object element = getter.apply(object);
+ result = 31 * result + (element == null ? 0 : element.hashCode());
+ }
+ return result;
+ }
+
+
+
+}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/util/ObjectContracts.java b/core/applib/src/main/java/org/apache/isis/applib/util/ObjectContracts.java
index b7ecb23..2f1bfb2 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/util/ObjectContracts.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/util/ObjectContracts.java
@@ -1,286 +1,82 @@
-/**
- * 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
+/*
+ * 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
+ * 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.
+ * 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.isis.applib.util;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.apache.isis.applib.internal.base._Casts;
-import org.apache.isis.applib.internal.base._NullSafe;
-import org.apache.isis.applib.internal.base._Strings;
-import org.apache.isis.applib.internal.collections._Lists;
-
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-import com.google.common.collect.ComparisonChain;
-import com.google.common.collect.Ordering;
+import java.util.function.Function;
+/**
+ * Provides fluent composition for Objects' equals, hashCode and toString.
+ *
+ * Sample usage by composing getters ...
+ *
+ *
+ * <pre>
+ * private final static Equality<ApplicationFeature> equality =
+ * ObjectContracts.checkEquals(ApplicationFeature::getFeatureId);
+ *
+ * private final static Hashing<ApplicationFeature> hashing =
+ * ObjectContracts.hashing(ApplicationFeature::getFeatureId);
+ *
+ * private final static ToString<ApplicationFeature> toString =
+ * ObjectContracts.toString("featureId", ApplicationFeature::getFeatureId);
+ *
+ * public boolean equals(final Object obj) {
+ * return equality.equals(this, obj);
+ * }
+ *
+ * public int hashCode() {
+ * return hashing.hashCode(this);
+ * }
+ *
+ * public String toString() {
+ * return toString.toString(this);
+ * }
+ * </pre>
+ *
+ * For 'compareTo' use JDK's comparator composition ...
+ *
+ * <pre>
+ * private final static Comparator<ApplicationFeature> comparator =
+ * Comparator.comparing(ApplicationFeature::getFeatureId);
+ *
+ * public int compareTo(final ApplicationFeature other) {
+ * return comparator.compare(this, other);
+ * }
+ * </pre>
+ *
+ * @since 2.0.0 (re-invented)
+ *
+ */
public class ObjectContracts {
-
- //region > compare
-
- /**
- * Evaluates which of p and q is first.
- *
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- * @param propertyNames - the property name or names, CSV format. If multiple properties, use the {@link #compare(Object, Object, String...) varargs} overloaded version of this method.
- */
- @Deprecated
- public static <T> int compare(final T p, final T q, final String propertyNames) {
- final Iterable<String> propertyNamesIter = csvToIterable(propertyNames);
- return compare(p, q, propertyNamesIter);
- }
-
- /**
- * Evaluates which of p and q is first.
- *
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- */
- @Deprecated
- public static <T> int compare(final T p, final T q, final String... propertyNames) {
- final Iterable<String> propertyNamesIter = varargsToIterable(propertyNames);
- return compare(p, q, propertyNamesIter);
- }
-
- private static <T> int compare(final T p, final T q, final Iterable<String> propertyNamesIter) {
- if(p == null) { return -1;}
- if(q == null) { return +1;}
- if(p.getClass() != q.getClass()) {
- // just sort on the class type
- return Ordering.natural().onResultOf((Function<Object, String>) o -> o.getClass().getSimpleName()).compare(p, q);
- }
-
- final Iterable<Clause> clauses = clausesFor(propertyNamesIter);
- ComparisonChain chain = ComparisonChain.start();
- for (final Clause clause : clauses) {
- final Comparable<T> propertyValueOfP = _Casts.uncheckedCast(clause.getValueOf(p));
- final Comparable<T> propertyValueOfQ = _Casts.uncheckedCast(clause.getValueOf(q));
- chain = chain.compare(propertyValueOfP, propertyValueOfQ, clause.getDirection().getOrdering());
- }
- return chain.result();
- }
- //endregion
-
- //region > compareBy
- /**
- * Returns a {@link Comparator} to evaluate objects by their property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- * @param propertyNames - the property name or names, CSV format. If multiple properties, use the {@link #compareBy(String...)} varargs} overloaded version of this method.
- */
- @Deprecated
- public static <T> Comparator<T> compareBy(final String propertyNames){
- return (p, q) -> compare(p, q, propertyNames);
- }
- /**
- * Returns a {@link Comparator} to evaluate objects by their property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- */
- @Deprecated
- public static <T> Comparator<T> compareBy(final String... propertyNames){
- return (p, q) -> compare(p, q, propertyNames);
- }
- //endregion
-
- //region > toString
-
- /**
- * Returns a string representation of the object consisting of the specified property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- * @param propertyNames - the property name or names, CSV format. If multiple properties, use the {@link #toString(Object, String...)} varargs} overloaded version of this method.
- */
- @Deprecated
- public static String toString(Object p, String propertyNames) {
- return new ObjectContracts().toStringOf(p, propertyNames);
- }
- /**
- * Returns a string representation of the object consisting of the specified property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- */
- @Deprecated
- public static String toString(Object p, String... propertyNames) {
- return new ObjectContracts().toStringOf(p, propertyNames);
- }
- //endregion
-
- //region > hashCode
- /**
- * Returns the hashCode for the object using the specified property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- * @param propertyNames - the property name or names, CSV format. If multiple properties, use the {@link #hashCode(Object, String...)} varargs} overloaded version of this method.
- */
- @Deprecated
- public static int hashCode(Object obj, String propertyNames) {
- final Iterable<String> propertyNamesIter = csvToIterable(propertyNames);
- return hashCode(obj, propertyNamesIter);
- }
-
- /**
- * Returns the hashCode for the object using the specified property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- */
- @Deprecated
- public static int hashCode(Object obj, String... propertyNames) {
- final Iterable<String> propertyNamesIter = varargsToIterable(propertyNames);
- return hashCode(obj, propertyNamesIter);
- }
-
- private static int hashCode(final Object obj, final Iterable<String> propertyNamesIter) {
- final List<Object> propertyValues = _Lists.newArrayList();
- for (final Clause clause : clausesFor(propertyNamesIter)) {
- final Object propertyValue = clause.getValueOf(obj);
- if(propertyValue != null) {
- propertyValues.add(propertyValue);
- }
- }
- return Objects.hashCode(propertyValues.toArray());
- }
- //endregion
-
- //region > equals
-
- /**
- * Returns whether two objects are equal, considering just the specified property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- * @param propertyNames - the property name or names, CSV format. If multiple properties, use the {@link #equals(Object, Object, String...)} varargs} overloaded version of this method.
- */
- @Deprecated
- public static boolean equals(Object p, Object q, String propertyNames) {
- if(p==null && q==null) {
- return true;
- }
- if(p==null || q==null) {
- return false;
- }
- if(p.getClass() != q.getClass()) {
- return false;
- }
- final Iterable<String> propertyNamesIter = csvToIterable(propertyNames);
- return equals(p, q, propertyNamesIter);
- }
-
- /**
- * Returns whether two objects are equal, considering just the specified property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- */
- @Deprecated
- public static boolean equals(Object p, Object q, String... propertyNames) {
- if(p==null && q==null) {
- return true;
- }
- if(p==null || q==null) {
- return false;
- }
- if(p.getClass() != q.getClass()) {
- return false;
- }
- final Iterable<String> propertyNamesIter = varargsToIterable(propertyNames);
- return equals(p, q, propertyNamesIter);
- }
-
- private static boolean equals(final Object p, final Object q, final Iterable<String> propertyNamesIter) {
- final Iterable<Clause> clauses = clausesFor(propertyNamesIter);
- for (final Clause clause : clauses) {
- final Object pValue = clause.getValueOf(p);
- final Object qValue = clause.getValueOf(q);
- if(!Objects.equal(pValue, qValue)) {
- return false;
- }
- }
- return true;
- }
- //endregion
-
- //region > helpers
- private static Iterable<Clause> clausesFor(final Iterable<String> iterable) {
- return _NullSafe.stream(iterable)
- .map(Clause::parse)
- .collect(Collectors.toList());
- }
-
- private static Iterable<String> csvToIterable(final String propertyNames) {
- return _Strings.splitThenStream(propertyNames, ",")
- .collect(Collectors.toList());
- }
-
- private static List<String> varargsToIterable(final String[] iterable) {
- return Arrays.asList(iterable);
- }
- //endregion
-
- //region > toStringOf
-
- public interface ToStringEvaluator {
- boolean canEvaluate(Object o);
- String evaluate(Object o);
- }
-
- private final List<ToStringEvaluator> evaluators = _Lists.newArrayList();
-
- public ObjectContracts with(ToStringEvaluator evaluator) {
- evaluators.add(evaluator);
- return this;
- }
-
- /**
- * Returns a string representation of two objects, considering just the specified property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- * @param propertyNames - the property name or names, CSV format. If multiple properties, use the {@link #toString(Object, String...)} varargs} overloaded version of this method.
- */
- @Deprecated
- public String toStringOf(Object p, String propertyNames) {
- final Iterable<String> propertyNamesIter = csvToIterable(propertyNames);
- return toStringOf(p, propertyNamesIter);
- }
-
- /**
- * Returns a string representation of two objects, considering just the specified property name(s).
- * @deprecated - please be aware that this utility heavily uses reflection. We don't actually intend to deprecate this method (it's useful while prototyping), but we wanted to bring this to your attention!
- */
- @Deprecated
- public String toStringOf(Object p, String... propertyNames) {
- final Iterable<String> propertyNamesIter = varargsToIterable(propertyNames);
- return toStringOf(p, propertyNamesIter);
- }
-
- private String toStringOf(final Object p, final Iterable<String> propertyNamesIter) {
- final ToStringHelper stringHelper = Objects.toStringHelper(p);
- for (final Clause clause : clausesFor(propertyNamesIter)) {
- stringHelper.add(clause.getPropertyName(), asString(clause, p));
- }
- return stringHelper.toString();
- }
-
- private String asString(final Clause clause, Object p) {
- final Object value = clause.getValueOf(p);
- if(value == null) {
- return null;
- }
- for (ToStringEvaluator evaluator : evaluators) {
- if(evaluator.canEvaluate(value)) {
- return evaluator.evaluate(value);
- }
- }
- return value.toString();
- }
-
- //endregion
-
-
+
+ public static <T> ToString<T> toString(String name, Function<T, ?> getter) {
+ return ToString.toString(name, getter);
+ }
+
+ public static <T> Equality<T> checkEquals(Function<T, ?> getter) {
+ return Equality.checkEquals(getter);
+ }
+
+ public static <T> Hashing<T> hashing(Function<T, ?> getter) {
+ return Hashing.hashing(getter);
+ }
+
+
+
}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/util/ToString.java b/core/applib/src/main/java/org/apache/isis/applib/util/ToString.java
new file mode 100644
index 0000000..3b99fa2
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/util/ToString.java
@@ -0,0 +1,63 @@
+package org.apache.isis.applib.util;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.apache.isis.applib.internal.collections._Lists;
+
+/**
+ * Fluent Object to String Composition.
+ *
+ * @param <T>
+ * @since 2.0.0
+ *
+ */
+public class ToString<T> {
+
+ public static <T> ToString<T> toString(String name, Function<T, ?> getter) {
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(getter);
+ return new ToString<>(name, getter);
+ }
+
+ private final List<String> names = _Lists.newArrayList();
+ private final List<Function<T, ?>> getters = _Lists.newArrayList();
+
+ private ToString(String name, Function<T, ?> getter) {
+ names.add(name);
+ getters.add(getter);
+ }
+
+ public ToString<T> thenToString(String name, Function<T, ?> getter){
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(getter);
+ names.add(name);
+ getters.add(getter);
+ return this;
+ }
+
+ public String toString(T target){
+ if(target==null) {
+ return "null";
+ }
+
+ final Iterator<String> nameIterator = names.iterator();
+
+ return String.format("%s{%s}",
+
+ target.getClass().getSimpleName(),
+
+ getters.stream()
+ .map(getter->getter.apply(target))
+ .map(value->nameIterator.next()+"="+value)
+ .collect(Collectors.joining(", "))
+
+ );
+ }
+
+
+
+}
--
To stop receiving notification emails like this one, please contact
ahuber@apache.org.