This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch dev/2.0.0/ISIS-1762-j8-utils in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/dev/2.0.0/ISIS-1762-j8-utils by this push: new 07e362e ISIS-1762 added Reflect and NullSafe, reviewing o.a.i.c.commons 07e362e is described below commit 07e362e2b507d80e0eae9abf303cc7a2bbef18e7 Author: Andi Huber <ahu...@apache.org> AuthorDate: Fri Oct 27 15:25:23 2017 +0200 ISIS-1762 added Reflect and NullSafe, reviewing o.a.i.c.commons --- .../core/commons/exceptions/ExceptionUtils.java | 14 +- .../isis/core/commons/lang/ArrayExtensions.java | 11 +- .../isis/core/commons/lang/ClassPredicates.java | 1 - .../isis/core/commons/lang/MethodExtensions.java | 2 - .../apache/isis/core/commons/lang/NullSafe.java | 129 ++++++++++++++++ .../apache/isis/core/commons/lang/Nullable.java | 7 + .../isis/core/commons/lang/StringPredicates.java | 1 - .../isis/core/commons/reflection/Reflect.java | 167 +++++++++++++++++++++ 8 files changed, 317 insertions(+), 15 deletions(-) diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/exceptions/ExceptionUtils.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/exceptions/ExceptionUtils.java index 376caf5..1b313c6 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/commons/exceptions/ExceptionUtils.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/exceptions/ExceptionUtils.java @@ -26,6 +26,8 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import org.apache.isis.core.commons.reflection.Reflect; + /** * <p>Provides utilities for manipulating and examining * <code>Throwable</code> objects.</p> @@ -67,7 +69,7 @@ public class ExceptionUtils { static { Method causeMethod; try { - causeMethod = Throwable.class.getMethod("getCause", null); + causeMethod = Throwable.class.getMethod("getCause", Reflect.emptyClasses); } catch (Exception e) { causeMethod = null; } @@ -243,10 +245,10 @@ public class ExceptionUtils { return true; } - Class cls = throwable.getClass(); + Class<?> cls = throwable.getClass(); for (final String causeMethodName : CAUSE_METHOD_NAMES) { try { - Method method = cls.getMethod(causeMethodName, null); + Method method = cls.getMethod(causeMethodName, Reflect.emptyClasses); if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) { return true; } @@ -287,7 +289,7 @@ public class ExceptionUtils { * @return the array of throwables, never null */ public static Throwable[] getThrowables(Throwable throwable) { - List list = getThrowableList(throwable); + List<Throwable> list = getThrowableList(throwable); return (Throwable[]) list.toArray(new Throwable[list.size()]); } @@ -310,8 +312,8 @@ public class ExceptionUtils { * @return the list of throwables, never null * @since Commons Lang 2.2 */ - public static List getThrowableList(Throwable throwable) { - List list = new ArrayList(); + public static List<Throwable> getThrowableList(Throwable throwable) { + List<Throwable> list = new ArrayList<Throwable>(); while (throwable != null && list.contains(throwable) == false) { list.add(throwable); throwable = ExceptionUtils.getCause(throwable); diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/ArrayExtensions.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/ArrayExtensions.java index 26bb45c..4e20585 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/ArrayExtensions.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/ArrayExtensions.java @@ -22,15 +22,14 @@ package org.apache.isis.core.commons.lang; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import com.google.common.collect.Lists; - import org.apache.isis.core.commons.exceptions.IsisException; +import com.google.common.collect.Lists; + public final class ArrayExtensions { private ArrayExtensions() { @@ -72,7 +71,8 @@ public final class ArrayExtensions { return converted; } - public static <T> T[] combine(final T[]... arrays) { + @SafeVarargs + public static <T> T[] combine(final T[]... arrays) { final List<T> combinedList = Lists.newArrayList(); for (final T[] array : arrays) { Collections.addAll(combinedList, array); @@ -93,7 +93,8 @@ public final class ArrayExtensions { return argList.toArray(new String[] {}); } - public static <T> T coalesce(final T... objects) { + @SafeVarargs + public static <T> T coalesce(final T... objects) { for (final T object : objects) { if (object != null) { return object; diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/ClassPredicates.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/ClassPredicates.java index 803265b..d2554f2 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/ClassPredicates.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/ClassPredicates.java @@ -18,7 +18,6 @@ */ package org.apache.isis.core.commons.lang; -import com.google.common.base.Function; import com.google.common.base.Predicate; public final class ClassPredicates { diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/MethodExtensions.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/MethodExtensions.java index 4d4e839..fb95bf9 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/MethodExtensions.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/MethodExtensions.java @@ -23,8 +23,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import com.google.common.primitives.Primitives; - import org.apache.isis.core.metamodel.exceptions.MetaModelException; public class MethodExtensions { diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/NullSafe.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/NullSafe.java new file mode 100644 index 0000000..985b498 --- /dev/null +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/NullSafe.java @@ -0,0 +1,129 @@ +/* + * 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.isis.core.commons.lang; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +/** + * + * Provides convenient null check / null safe methods primarily + * to shortcut null-check idioms. + * + * @author ahu...@apache.org + * @since 2.0.0 + * + */ +public class NullSafe { + + // -- STREAM CREATION + + /** + * Shortcut for {@code Optional.ofNullable(array).map(Stream::of)} + * @param array + * @return a sequential ordered stream whose elements are the elements of + * the specified {@code array}, or the empty stream if array is {@code null}. + */ + public static <T> Stream<T> stream(T[] array) { + return array!=null ? Stream.empty() : Stream.of(array); + } + + /** + * Shortcut for {@code Optional.ofNullable(coll).map(Stream::of)} + * @param coll + * @return a sequential ordered stream whose elements are the elements of + * the specified {@code coll}, or the empty stream if coll is {@code null}. + */ + public static <T> Stream<T> stream(Collection<T> coll){ + return coll!=null ? coll.stream() : Stream.empty(); + } + + // -- ABSENCE/PRESENCE PREDICATES + + /** + * Allows to replace a lambda expression {@code x->x!=null} with {@code NullSafe::isPresent} + * @param x + * @return whether {@code x} is not null. + */ + public static boolean isPresent(Object x) { + return x!=null; + } + + /** + * Allows to replace a lambda expression {@code x->x==null} with {@code NullSafe::isAbsent} + * @param x + * @return whether {@code x} is null. + */ + public static boolean isAbsent(Object x) { + return x!=null; + } + + // -- EQUALS/COMPARE + + /** + * equivalent to {@link java.util.Objects#equals(Object, Object)} + */ + public static boolean equals(final Object x, final Object y) { + return Objects.equals(x, y); + } + + /** + * Natural order compare, with nulls ordered first. + * @param x + * @param y + * @return + */ + public static <T extends Comparable<T>> int compareNullsFirst(final T x, final T y) { + return Objects.compare(x, y, Comparator.nullsFirst(Comparator.naturalOrder())); + + } + + /** + * Natural order compare, with nulls ordered last. + * @param x + * @param y + * @return + */ + public static <T extends Comparable<T>> int compareNullsLast(final T x, final T y) { + return Objects.compare(x, y, Comparator.nullsLast(Comparator.naturalOrder())); + + } + + + // -- EMTPY CHECKS + + public static boolean isEmpty(String x) { return x==null || x.length() == 0; } + public static boolean isEmpty(Collection<?> x) { return x==null || x.size() == 0; } + public static boolean isEmpty(Map<?,?> x) { return x==null || x.size() == 0; } + public static boolean isEmpty(boolean[] array){ return array==null || array.length == 0;} + public static boolean isEmpty(byte[] array){ return array==null || array.length == 0;} + public static boolean isEmpty(char[] array){ return array==null || array.length == 0;} + public static boolean isEmpty(double[] array){ return array==null || array.length == 0;} + public static boolean isEmpty(float[] array){ return array==null || array.length == 0;} + public static boolean isEmpty(int[] array){ return array==null || array.length == 0;} + public static boolean isEmpty(long[] array){ return array==null || array.length == 0;} + public static boolean isEmpty(short[] array){ return array==null || array.length == 0;} + public static <T> boolean isEmpty(T[] array){ return array==null || array.length == 0;} + + + +} diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/Nullable.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/Nullable.java index deac021..f06d014 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/Nullable.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/Nullable.java @@ -18,6 +18,13 @@ */ package org.apache.isis.core.commons.lang; +/** + * + * @deprecated use {@link java.util.Optional} instead + * + * @param <T> + */ +@Deprecated public class Nullable<T> { public static <T> Nullable<T> some(T t) { diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/StringPredicates.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/StringPredicates.java index c8beb4a..349cf22 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/StringPredicates.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/StringPredicates.java @@ -19,7 +19,6 @@ package org.apache.isis.core.commons.lang; -import com.google.common.base.Function; import com.google.common.base.Predicate; public final class StringPredicates { diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/reflection/Reflect.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/reflection/Reflect.java new file mode 100644 index 0000000..82cc7e5 --- /dev/null +++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/reflection/Reflect.java @@ -0,0 +1,167 @@ +/* + * 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.isis.core.commons.reflection; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Stream; + +/** + * + * Provides shortcuts for common java.lang.reflect idioms. + * + * @author ahu...@apache.org + * @since 2.0.0 + * + */ +public class Reflect { + + public static Object[] emptyObjects = {}; + public static Class<?>[] emptyClasses = {}; + + // -- CLASS REFLECTION + + /** + * Returns declared methods of this class/interface and all super classes/interfaces. + * @param type + * @return + */ + public static List<Method> getAllDeclaredMethods(Class<?> type) { + final List<Method> methods = new ArrayList<>(); + + Stream.of(type.getDeclaredMethods()).forEach(methods::add); + visitInterfaces(type,c->Stream.of(c.getDeclaredMethods()).forEach(methods::add)); + visitSuperclassesOf(type,c->Stream.of(c.getDeclaredMethods()).forEach(methods::add)); + return methods; + } + + /** + * Returns declared fields of this class/interface and all super classes/interfaces. + * @param type + * @return + */ + public static List<Field> getAllDeclaredFields(Class<?> type) { + final List<Field> fields = new ArrayList<>(); + + Stream.of(type.getDeclaredFields()).forEach(fields::add); + visitInterfaces(type,c->Stream.of(c.getDeclaredFields()).forEach(fields::add)); + visitSuperclassesOf(type,c->Stream.of(c.getDeclaredFields()).forEach(fields::add)); + return fields; + } + + public static void visitSuperclassesOf(final Class<?> clazz, final Consumer<Class<?>> visitor){ + final Class<?> superclass = clazz.getSuperclass(); + if(superclass!=null){ + visitor.accept(superclass); + visitSuperclassesOf(superclass, visitor); + } + } + + public static void visitInterfaces(final Class<?> clazz, final Consumer<Class<?>> visitor){ + if(clazz.isInterface()) + visitor.accept(clazz); + + for(Class<?> interf : clazz.getInterfaces()) + visitor.accept(interf); + } + + public static Method getGetter(Object bean, String propertyName) throws IntrospectionException { + final BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); + for(PropertyDescriptor pd:beanInfo.getPropertyDescriptors()){ + if(!pd.getName().equals(propertyName)) + continue; + return pd.getReadMethod(); + } + return null; + } + + // -- PRIMITIVE TYPES + + private static final Set<Class<?>> primitives = new HashSet<>(Arrays.asList( + boolean.class, + byte.class, + char.class, + double.class, + float.class, + int.class, + long.class, + short.class + //void.class //separated out into its own predicate: isVoid(...) + )); + + private static final Set<Class<?>> primitiveWrappers = new HashSet<>(Arrays.asList( + Boolean.class, + Byte.class, + Character.class, + Double.class, + Float.class, + Integer.class, + Long.class, + Short.class + //Void.class //separated out into its own predicate: isVoid(...) + )); + + // -- TYPE PREDICATES + + public static boolean isVoid(Class<?> c) { + Objects.requireNonNull(c); + return c == void.class || c == Void.class; + } + + public static boolean isPrimitive(Class<?> c) { + Objects.requireNonNull(c); + return primitives.contains(c); + } + + public static boolean isPrimitiveWrapper(Class<?> c) { + Objects.requireNonNull(c); + return primitiveWrappers.contains(c); + } + + + // -- METHOD PREDICATES + + public static boolean isNoArg(Method m) { + Objects.requireNonNull(m); + return m.getParameterTypes().length==0; + } + + public static boolean isPublic(Method m) { + Objects.requireNonNull(m); + return Modifier.isPublic(m.getModifiers()); + } + + public static boolean isVoid(Method m) { + Objects.requireNonNull(m); + return isVoid(m.getReturnType()); + } + +} -- To stop receiving notification emails like this one, please contact ['"commits@isis.apache.org" <commits@isis.apache.org>'].