/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.function;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringEscapeUtils;
import com.google.common.reflect.TypeToken;
/**
* Helper methods for use when creating {@link ParameterType} instances and converting between arguments and strings.
*/
public final class ParameterUtils {
private static final Pattern WHITESPACE = Pattern.compile("\\s");
private ParameterUtils() {
}
/**
* @param type a type
* @return true if the type is a parameterized {@link Collection}, {@link List} or {@link Set}
*/
public static boolean isCollection(Type type) {
// we're only interested in parameterized types because we need to know the element type
if (!(type instanceof ParameterizedType)) {
return false;
}
Class<?> rawType = TypeToken.of(type).getRawType();
return rawType == Collection.class || rawType == List.class || rawType == Set.class;
}
/**
* @param type a type
* @return true if the type is an array
*/
public static boolean isArray(Type type) {
return (type instanceof GenericArrayType) || ((type instanceof Class<?>) && ((Class<?>) type).isArray());
}
/**
* @param type a type
* @return true if they type is a parameterized map
*/
public static boolean isMap(Type type) {
// we're only interested in parameterized types because we need to know the key and value types
if (!(type instanceof ParameterizedType)) {
return false;
}
Class<?> rawType = TypeToken.of(type).getRawType();
return rawType == Map.class;
}
/**
* Returns the element type of an array or parameterized collection ({@link Collection}, {@link List} or {@link Set}).
*
* @param type the array or collection type
* @return the type of the element in the collection or array
* @throws IllegalArgumentException if the type isn't a collection or array or if the element can't be found (e.g.
* if the type doesn't have a type parameter)
*/
public static Class<?> getElementType(Type type) {
if (!isCollection(type) && !isArray(type)) {
throw new IllegalArgumentException("Type must be a collection or array");
}
if (type instanceof GenericArrayType) {
Type genericComponentType = ((GenericArrayType) type).getGenericComponentType();
return TypeToken.of(genericComponentType).getRawType();
}
if ((type instanceof Class<?>) && ((Class<?>) type).isArray()) {
return ((Class<?>) type).getComponentType();
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
// this shouldn't ever happen
if (typeArguments.length != 1) {
throw new IllegalArgumentException("Container must have one type argument " + type);
}
return TypeToken.of(typeArguments[0]).getRawType();
}
throw new IllegalArgumentException("Can't get element type for " + type);
}
/**
* Returns the type of the keys in a generic map.
*
* @param type a map type
* @return the type of the map's key
* @throws IllegalArgumentException if the type isn't a map or the key type can't be found
*/
public static Class<?> getKeyType(Type type) {
return getMapTypeParameter(type, true);
}
/**
* Returns the type of the values in a generic map.
*
* @param type a map type
* @return the type of the map's key
* @throws IllegalArgumentException if the type isn't a map or the value type can't be found
*/
public static Class<?> getValueType(Type type) {
return getMapTypeParameter(type, false);
}
/**
* Returns a type parameter from a parameterized map type.
*
* @param type the type, must be a parameterized {@code java.util.Map}.
* @param keyType true if the key type is required, false if the value type is required
* @return the key or value type parameter
* @throws IllegalArgumentException if the type isn't a map with two type parameters
*/
private static Class<?> getMapTypeParameter(Type type, boolean keyType) {
if (!isMap(type)) {
throw new IllegalArgumentException("Type isn't a map. ");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
if (typeArguments.length != 2) {
throw new IllegalArgumentException("Expected 2 type arguments. ");
}
int argIndex = keyType ? 0 : 1;
Type valueType = typeArguments[argIndex];
return TypeToken.of(valueType).getRawType();
}
/**
* Escapes the string and wraps it in quotes if it contains any whitespace.
*
* @param str a string
* @return the escaped string, surrounded with quotes if it contains any whitespace
*/
public static String escapeString(String str) {
if (WHITESPACE.matcher(str).find()) {
return "\"" + StringEscapeUtils.escapeJava(str) + "\"";
} else {
return StringEscapeUtils.escapeJava(str);
}
}
}