nl.vpro.util.Helper Maven / Gradle / Ivy
/*
* Copyright (C) 2005 All rights reserved
* Finalist IT Group B.V. The Netherlands
* Creation date 15-dec-2005.
*/
package nl.vpro.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
/**
* Simple helper methods.
*
* @author arne, peter
* @author [email protected]
*/
public class Helper {
private Helper() {
}
/**
* Gives a default in case the value is null.
*
* @param the type of the value
* @param value a value
* @param def the default
* @return value when value is not null, def otherwise
* @see #nvl(Object[])
*/
public static T withDefault(T value, T def) {
return value == null ? def : value;
}
/**
* Gives a default in case the value is -1.
*
* @param value a value
* @param def the default
* @return the value if it is not -1, def otherwise
*/
public static int withDefault(int value, int def) {
return (value == -1) ? def : value;
}
/**
* Returns the first non-null value. This method is also known as coalesce.
*
* @param the type of the value
* @param values the values
* @return the first non-null value in the arguments, or null when values is null or when all given values in it are
* all null
* @see #withDefault(Object, Object)
*/
@SafeVarargs
public static T nvl(T... values) {
T result = null;
if (values != null) {
for (int i = 0; result == null && i < values.length; i++) {
result = values[i];
}
}
return result;
}
public static String nvl(String... values) {
String result = null;
if (values != null) {
for (String value : values) {
result = value;
if (StringUtils.isNotEmpty(result)) {
break;
}
}
}
return result;
}
/**
* Returns the first non-null value. This method is also known as coalesce.
*
* @param values the values
* @return the first non-null value in the arguments, or null when values is null or when all given values in it are
* all null
* @see #withDefault(Object, Object)
*/
public static T firstNonNull(List values) {
T result = null;
if (Helper.isNotEmpty(values)) {
for (T v : values) {
if (v != null) {
result = v;
}
}
}
return result;
}
/**
* Returns the first non-null value. This method is also known as coalesce.
*
* @param values the values
* @return the first non-null value in the arguments, or null when values is null or when all given values in it are
* all null
* @see #withDefault(Object, Object)
*/
public static T firstNonNull(Set values) {
T result = null;
if (Helper.isNotEmpty(values)) {
for (T v : values) {
if (v != null) {
result = v;
}
}
}
return result;
}
/**
* @param some type
* @param collection the collection
* @return true when collection is not null and contains elements
*/
private static boolean isNotEmpty(Collection collection) {
return collection != null && ! collection.isEmpty();
}
/**
* Adds a value to a map of lists. A value list is created when there is no entry in the map for the given key.
*
* @param listMap the map of lists (not null)
* @param key the key (may be null when the map supports null keys)
* @param value the value to put in the list
* @param key type in the map
* @param actual used key type
* @param list type in the map
* @param actual used list type
*/
public static void add(Map> listMap, L key, W value) {
List list = listMap.computeIfAbsent(key, k -> new ArrayList<>());
list.add(value);
}
/**
* Adds a value to a map of sets. A value set is created when there is no entry in the map for the given key.
*
* @param setMap the map of sets (not null)
* @param key the key (may be null when the map supports null keys)
* @param value the value to put in the set
* @param key type in the map
* @param actual used key type
* @param set type in the map
* @param actual used set type
*/
public static void addToSetMap(Map> setMap, L key, W value) {
Set set = setMap.computeIfAbsent(key, k -> new HashSet<>());
set.add(value);
}
/**
* Puts a value in a map when the value is not null.
*
* @param the key type
* @param the value type
* @param map the map (not null)
* @param key the key, can be null when the map supports it
* @param value the value or null to do nothing
*/
public static void putIfNotNull(Map map, K key, V value) {
if (value != null) {
map.put(key, value);
}
}
/**
* Determines whether some string is a number. No range check is performed.
*
* @param text the string of which must be determined if it's a number
* @return {@code true} if {@code text} is a number, {@code false} otherwise
*/
public static boolean isNumber(String text) {
return (text != null) && text.matches("\\d+");
}
/**
* Converts a number to another number, potentially rounding to fit the target type.
*
* Does all standard java types except Atomic* and Mutable*.
*
* @param the target number type
* @param value the number to convert
* @param targetType the return type (not null)
* @return value cast to type N or null when value is null. Note that the information may be discarded when the
* value is incompatible with the target type.
*/
public static N numberCast(Number value, Class targetType) {
Number result;
if (value == null) {
result = null;
} else if (targetType.equals(BigDecimal.class)) {
if (value instanceof BigDecimal) {
result = value;
} else if (value instanceof BigInteger) {
result = new BigDecimal((BigInteger) value);
} else if (value instanceof Integer || value instanceof Long || value instanceof Short || value instanceof Byte) {
result = BigDecimal.valueOf(value.longValue());
} else if (value instanceof Double || value instanceof Float) {
result = new BigDecimal(value.toString());
} else {
throw new IllegalArgumentException(String.format("unknown type for value %s (%s)", value, value.getClass()));
}
} else if (targetType.equals(BigInteger.class)) {
if (value instanceof BigInteger) {
result = value;
} else if (value instanceof BigDecimal) {
result = ((BigDecimal) value).toBigInteger();
} else {
result = BigInteger.valueOf(value.longValue());
}
} else if (targetType.equals(Long.class)) {
result = value.longValue();
} else if (targetType.equals(Integer.class)) {
result = value.intValue();
} else if (targetType.equals(Short.class)) {
result = value.shortValue();
} else if (targetType.equals(Byte.class)) {
result = value.byteValue();
} else if (targetType.equals(Double.class)) {
result = value.doubleValue();
} else if (targetType.equals(Float.class)) {
result = value.floatValue();
} else {
throw new IllegalStateException("Unknown Number type");
}
return (N) result;
}
/**
* Tries and find an element in an array. {@link Objects#equals(Object, Object) equals} is used for comparisons. A
* linear search is performed - if the input array is sorted, it would be wiser to use
* {@link Arrays#binarySearch(Object[], Object)}.
*
* @param the array type
* @param element the element to find
* @param array the array to search in
* @return {@code true} if the array contains the element, {@code false} otherwise
*/
@SafeVarargs
public static boolean arrayContains(T element, T... array) {
int i = 0;
int n = array.length;
while ((i < n) && !Objects.equals(array[i], element)) {
i++;
}
return i < n;
}
/**
* Compare, taking null into account (null <).
*
* @param o1 first
* @param o2 second
* @return 1,0,-1
*/
@SuppressWarnings("unchecked")
public static int compare(Comparable o1, Comparable o2) {
int result = 0;
if (o1 != null && o2 != null) {
result = o1.compareTo(o2);
} else if (o1 == null) {
result = -1;
} else if (o2 == null) {
result = 1;
}
return result;
}
/**
* Convert a singleton list into the singleton element.
*
* @param The type of the list
* @param list the list
* @return the singleton in the list, or null
if the list is null
or the size of the
* list is zero.
* @throws IllegalStateException when more than one element is found in the list.
*/
public static T toSingleton(List list) {
T result;
if (list == null || list.isEmpty()) {
result = null;
} else if (list.size() > 1) {
throw new IllegalStateException(String.format("The list contained %s elements, it should contain 0 or 1 elements", list.size()));
} else {
result = list.get(0);
}
return result;
}
/**
* Convert a singleton set into the singleton element.
*
* @param The type of the set
* @param set the set
* @return the singleton in the set, or null
if the set is null
or the size of the set
* is zero.
* @throws IllegalStateException when more than one element is found in the set.
*/
public static T toSingleton(Set set) {
T result;
if (set == null || set.isEmpty()) {
result = null;
} else if (set.size() > 1) {
throw new IllegalStateException(String.format("The set contained %s elements, it should contain 0 or 1 elements", set.size()));
} else {
result = set.iterator().next();
}
return result;
}
/**
* @param toTest The object to test
* @param name The FQN of the class to test againts. The class should be in the classpath
* @return true if the 'name' is assignable from 'toTest'
*/
public static boolean isAssignableFrom(Object toTest, String name) {
try {
return Class.forName(name).isAssignableFrom(toTest.getClass());
} catch (Exception e) {
return false;
}
}
/**
* @param toTest The FQN object to test. The class should be in the classpath
* @param name The FQN of the class to test against. The class should be in the classpath
* @return true if the 'name' is assignable from 'toTest'
*/
public static boolean isAssignableFrom(String toTest, String name) {
try {
return Class.forName(name).isAssignableFrom(Class.forName(toTest));
} catch (Exception e) {
return false;
}
}
@SuppressWarnings("unchecked")
public static Class getClass(String name) {
try {
return (Class) Class.forName(name);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
public static String getAnnotatedProperty(Class> clazz, Class annClazz) {
Method[] methods = clazz.getMethods();
String annotationProperty = null;
for (Method method : methods) {
if (method.getAnnotation(annClazz) != null) {
String string1 = method.getName().substring(3, 4);
String string2 = method.getName().substring(4);
annotationProperty = string1.toLowerCase() + string2;
break;
}
}
if (annotationProperty == null && clazz.getSuperclass() != Object.class) {
annotationProperty = getAnnotatedProperty(clazz.getSuperclass(), annClazz);
}
return annotationProperty;
}
public static List removeNullEntries(List source) {
source.removeIf(Objects::isNull);
return source;
}
public static StringBuilder appendIfNotEmpty(StringBuilder sb, String s) {
if (StringUtils.isNotEmpty(s)) {
sb.append(s);
}
return sb;
}
/**
* joins all items in the given list using String.valueOf on each item seperated by the sep String
*
* @param list The list to join
* @param sep The separator String
* @return the result
*/
public static String join(Collection list, String sep) {
if (isNotEmpty(list)) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (T t : list) {
if (!first) {
sb.append(sep);
}
sb.append(t);
first = false;
}
return sb.toString();
} else {
return "";
}
}
/**
* Determine the similar elements in both lists. Result will be sorted.
*
* @param a List a
* @param b List b
* @return The similar elements for both lists
*/
public static > List sim(List a, List b) {
Set all = new HashSet<>();
all.addAll(a);
all.addAll(b);
Set results = new HashSet<>();
for (T t : all) {
if (a.contains(t) && b.contains(t)) {
results.add(t);
}
}
List theSimilarElements = new ArrayList<>(results);
Collections.sort(theSimilarElements);
return theSimilarElements;
}
/**
* Will splice the number in chunks no larger then maxPartSize
*
* @param number The number to splice
* @param maxPartSize The maximum size of a part in the path
* @return A list of the spliced id
*/
public static List spliceNumber(Number number, int maxPartSize) {
return spliceNumber(number, 1, maxPartSize);
}
/**
* Will splice the number in chunks no larger then maxPartSize
*
* @param number The number to splice
* @param minPartSize The minimal size of a part, smaller will be skipped
* @param maxPartSize The maximum size of a part in the path
* @return A list of the spliced id
*/
public static List spliceNumber(Number number, int minPartSize, int maxPartSize) {
if (number != null) {
String s = number.toString();
int length = s.length();
List arrayList = new ArrayList<>(length / maxPartSize + 1);
for (int start = 0; start < length; start += maxPartSize) {
int end = Math.min((start + maxPartSize), length);
if (end - start >= minPartSize) {
arrayList.add(s.substring(start, end));
}
}
return arrayList;
} else {
throw new IllegalArgumentException("number can not be null");
}
}
}