![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.juneau.internal.ObjectUtils Maven / Gradle / Ivy
// ***************************************************************************************************************************
// * 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.juneau.internal;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
import org.apache.juneau.*;
import org.apache.juneau.collections.*;
import org.apache.juneau.common.internal.*;
import org.apache.juneau.reflect.*;
/**
* Various generic object utility methods.
*
* See Also:
*
*/
public class ObjectUtils {
/**
* If the specified object is an instance of the specified class, casts it to that type.
*
* @param The class to cast to.
* @param o The object to cast.
* @param c The class to cast to.
* @return The cast object, or null if the object wasn't an instance of the specified class.
*/
public static T castOrNull(Object o, Class c) {
if (c.isInstance(o))
return c.cast(o);
return null;
}
/**
* Compares two objects for equality.
*
*
* Nulls are always considered less-than unless both are null.
*
* @param o1 Object 1.
* @param o2 Object 2.
* @return
* -1 , 0 , or 1 if o1 is less-than, equal, or greater-than o2 .
*
0 if objects are not of the same type or do not implement the {@link Comparable} interface.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static int compare(Object o1, Object o2) {
if (o1 == null) {
if (o2 == null)
return 0;
return -1;
} else if (o2 == null) {
return 1;
}
if (o1.getClass() == o2.getClass() && o1 instanceof Comparable)
return ((Comparable)o1).compareTo(o2);
return 0;
}
/**
* Compare two integers numerically.
*
* @param i1 Integer #1
* @param i2 Integer #2
* @return
* The value 0 if Integer #1 is equal to Integer #2; a value less than 0 if
* Integer #1 numerically less than Integer #2; and a value greater than 0 if Integer #1 is
* numerically greater than Integer #2 (signed comparison).
*/
public static final int compare(int i1, int i2) {
return (i1 Object 1 type.
* @param Object 2 type.
* @param o1 Object 1.
* @param o2 Object 2.
* @param test The test to use for equality.
* @return true if both objects are equal based on the test.
*/
public static boolean eq(T o1, U o2, BiPredicate test) {
if (o1 == null)
return o2 == null;
if (o2 == null)
return false;
if (o1 == o2)
return true;
return test.test(o1, o2);
}
/**
* Tests two objects for equality, gracefully handling nulls and arrays.
*
* @param The value types.
* @param o1 Object 1.
* @param o2 Object 2.
* @return true if both objects are equal based on the {@link Object#equals(Object)} method.
*/
public static boolean eq(T o1, T o2) {
if (isArray(o1) && isArray(o2)) {
int l1 = Array.getLength(o1), l2 = Array.getLength(o2);
if (l1 != l2)
return false;
for (int i = 0; i < l1; i++)
if (! eq(Array.get(o1, i), Array.get(o2, i)))
return false;
return true;
}
return Objects.equals(o1, o2);
}
/**
* Tests two arrays for equality, gracefully handling nulls.
*
* @param The value types.
* @param o1 Array 1.
* @param o2 Array 2.
* @return true if both arrays are equal based on the {@link Object#equals(Object)} method on each element.
*/
public static boolean eq(T[] o1, T[] o2) {
if (o1 == null || o2 == null) {
if (o1 != null || o2 != null)
return false;
return true;
}
if (o1.length != o2.length)
return false;
for (int i = 0; i < o1.length; i++)
if (! eq(o1[i], o2[i]))
return false;
return true;
}
/**
* Tests two objects for inequality, gracefully handling nulls.
*
* @param Object 1 type.
* @param Object 2 type.
* @param o1 Object 1.
* @param o2 Object 2.
* @param test The test to use for equality.
* @return false if both objects are equal based on the test.
*/
public static boolean ne(T o1, U o2, BiPredicate test) {
if (o1 == null)
return o2 != null;
if (o2 == null)
return true;
if (o1 == o2)
return false;
return ! test.test(o1, o2);
}
/**
* Tests two objects for equality, gracefully handling nulls and arrays.
*
* @param o1 Object 1.
* @param o2 Object 2.
* @return false if both objects are equal based on the {@link Object#equals(Object)} method.
*/
public static boolean ne(Object o1, Object o2) {
return ! eq(o1, o2);
}
private static boolean isArray(Object o) {
return o != null && o.getClass().isArray();
}
/**
* If the specified object is a {@link Supplier} or {@link Value}, returns the inner value, otherwise the same value.
*
* @param o The object to unwrap.
* @return The unwrapped object.
*/
public static Object unwrap(Object o) {
while (o instanceof Supplier)
o = ((Supplier>)o).get();
while (o instanceof Value)
o = ((Value>)o).get();
return o;
}
/**
* Returns true if the specified object is empty.
*
*
* Return true if the value is any of the following:
*
* null
* - An empty Collection
*
- An empty Map
*
- An empty array
*
- An empty CharSequence
*
- An empty String when serialized to a string using {@link Object#toString()}.
*
*
* @param o The object to test.
* @return true if the specified object is empty.
*/
@SuppressWarnings("rawtypes")
public static boolean isEmpty(Object o) {
if (o == null)
return true;
if (o instanceof Collection)
return ((Collection)o).isEmpty();
if (o instanceof Map)
return ((Map)o).isEmpty();
if (o.getClass().isArray())
return (Array.getLength(o) == 0);
return o.toString().isEmpty();
}
/**
* Returns the first non-null value in the specified array
*
* @param The value types.
* @param t The values to check.
* @return The first non-null value, or null if the array is null or empty or contains only null values.
*/
@SafeVarargs
public static T firstNonNull(T... t) {
if (t != null)
for (T tt : t)
if (tt != null)
return tt;
return null;
}
/**
* Casts an object to a specific type if it's an instance of that type.
*
* @param The type to cast to.
* @param c The type to cast to.
* @param o The object to cast to.
* @return The cast object, or null if the object wasn't the specified type.
*/
public static T cast(Class c, Object o) {
return o != null && c.isInstance(o) ? c.cast(o) : null;
}
/**
* Converts the specified object into an identifiable string of the form "Class[identityHashCode]"
* @param o The object to convert to a string.
* @return An identity string.
*/
public static String identity(Object o) {
if (o instanceof Optional)
o = ((Optional>)o).orElse(null);
if (o == null)
return null;
return ClassInfo.of(o).getShortName() + "@" + System.identityHashCode(o);
}
private static final ConcurrentHashMap,Map> PROPERTIES_METHODS = new ConcurrentHashMap<>();
/**
* Searches for all properties() methods on the specified object and creates a combine map of them.
*
* @param o The object to return a property map of.
* @return A new property map.
*/
public static JsonMap toPropertyMap(Object o) {
if (o == null)
return null;
Map methods = PROPERTIES_METHODS.get(o.getClass());
if (methods == null) {
ClassInfo ci = ClassInfo.of(o);
Map methods2 = new LinkedHashMap<>();
do {
String cname = ci.getShortName();
MethodInfo mi = ci.getDeclaredMethod(x -> x.hasName("properties"));
if (mi != null)
methods2.put(cname, mi.accessible());
ci = ci.getSuperclass();
} while (ci != null);
methods = methods2;
PROPERTIES_METHODS.put(o.getClass(), methods);
}
JsonMap m = JsonMap.create().append("id", identity(o));
methods.forEach((k,v) -> m.put(k, v.invoke(o)));
return m;
}
/**
* Returns true if the specified object is not null .
*
* @param The value type.
* @param value The value being checked.
* @return true if the specified object is not null .
*/
public static boolean isNotNull(T value) {
return value != null;
}
/**
* Returns true if the specified boolean is not null and is true .
*
* @param value The value being checked.
* @return true if the specified boolean is not null and is true .
*/
public static boolean isTrue(Boolean value) {
return value != null && value;
}
/**
* Returns true if the specified number is not null and not -1 .
*
* @param The value types.
* @param value The value being checked.
* @return true if the specified number is not null and not -1 .
*/
public static boolean isNotMinusOne(T value) {
return value != null && value.intValue() != -1;
}
/**
* Returns true if the specified object is not null and not empty.
*
* Works on any of the following data types: String, CharSequence, Collection, Map, array.
* All other types are stringified and then checked as a String.
*
* @param value The value being checked.
* @return true if the specified object is not null and not empty.
*/
public static boolean isNotEmpty(Object value) {
if (value == null) return false;
if (value instanceof CharSequence) return CharSequence.class.cast(value).length() > 0;
if (value instanceof Collection) return ! Collection.class.cast(value).isEmpty();
if (value instanceof Map) return ! Map.class.cast(value).isEmpty();
if (value.getClass().isArray()) return Array.getLength(value) > 0;
return StringUtils.isNotEmpty(StringUtils.stringify(value));
}
}