All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dooapp.gaedo.utils.Utils Maven / Gradle / Ivy

package com.dooapp.gaedo.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Queue;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import com.dooapp.gaedo.finders.Informer;
import com.dooapp.gaedo.properties.Property;

public class Utils {

	/**
	 * From an input container type, and a possibly null input value, generates a Map corresponding to the container interface kind
	 * @param rawContainerClass this is the expected type of the map (TreeMap, HashMap, anymap)
	 * @param property this is the current map value. it can be null
	 * @return property if non null, an instance of rawContainerClass elsewhere
	 */
	@SuppressWarnings("rawtypes")
	public static Map generateMap(Class rawContainerClass, Map property) {
		if (property == null) {
			if (SortedMap.class.isAssignableFrom(rawContainerClass)) {
				property = new TreeMap();
			} else if (Map.class.isAssignableFrom(rawContainerClass)) {
				property = new HashMap();
			}
		}
		return property;
	}

	/**
	 * Generate an instance of one of the concrete types corresponding to input
	 * type (if input type is not cocnrete)
	 *
	 * @param rawContainerType
	 * @param property
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static  Collection generateCollection(Class rawContainerType,
			Collection property) {
		if (property == null) {
			if (rawContainerType.isInterface()) {
				if (BlockingQueue.class.isAssignableFrom(rawContainerType)) {
					property = new ArrayBlockingQueue(10);
				} else if (Queue.class.isAssignableFrom(rawContainerType)) {
					property = new ArrayBlockingQueue(10);
				} else if (NavigableSet.class.isAssignableFrom(rawContainerType)) {
					property = new TreeSet();
				} else if (Set.class.isAssignableFrom(rawContainerType)) {
					property = new HashSet();
				} else if (SortedSet.class.isAssignableFrom(rawContainerType)) {
					property = new TreeSet();
				} else if (List.class.isAssignableFrom(rawContainerType)) {
					property = new LinkedList();
				} else if (Collection.class.isAssignableFrom(rawContainerType)) {
					property = new LinkedList();
				}
			} else if (Modifier.isAbstract(rawContainerType.getModifiers())) {
				throw new UnsupportedOperationException(
						"are you kiddin or what ? Replace your abstract type "
								+ rawContainerType.getName()
								+ "by an interface, it's wayyyy better !");
			} else {
				try {
					property = (Collection) rawContainerType.newInstance();
				} catch (Exception e) {
					throw new UnableToCreateObjectException(e, rawContainerType);
				}
			}
		}
		return property;
	}

	/**
	 * Maybe transform type in object one. if type is not a primitive, nothing is done
	 * @param toObjectify
	 * @return
	 */
	public static Class maybeObjectify(Class toObjectify) {
		Class returned = objectify(toObjectify);
		if(returned==null)
			returned = toObjectify;
		return returned;
	}

	/**
	 * Apply the {@link #maybeObjectify(Class)} algorithm to a string containing a class name
	 * @param toObjectify class name to objectify
	 * @return
	 */
	public static String maybeObjectify(String toObjectify) {
		String returned = objectify(toObjectify);
		if(returned==null)
			returned = toObjectify;
		return returned;
	}

	/**
	 * Transform a primitive type into its associated class : Integer.Type will become Integer.class, and so on ...
	 * @param toCompareClass
	 * @return
	 */
	public static String objectify(String toCompareClass) {
		if(Integer.TYPE.getName().equals(toCompareClass)) {
			return Integer.class.getName();
		} else if(Long.TYPE.getName().equals(toCompareClass)) {
			return Long.class.getName();
		} else if(Short.TYPE.getName().equals(toCompareClass)) {
			return Short.class.getName();
		} else if(Float.TYPE.getName().equals(toCompareClass)) {
			return Float.class.getName();
		} else if(Double.TYPE.getName().equals(toCompareClass)) {
			return Double.class.getName();
		} else if(Byte.TYPE.getName().equals(toCompareClass)) {
			return Byte.class.getName();
		} else if(Character.TYPE.getName().equals(toCompareClass)) {
			return Character.class.getName();
		} else if(Boolean.TYPE.getName().equals(toCompareClass)) {
			return Boolean.class.getName();
		}
		return null;
	}

	/**
	 * Transform an object type into associated primitive type
	 * @param toCompareClass
	 * @return
	 */
	public static String primitize(String toCompareClass) {
		if(Integer.class.getName().equals(toCompareClass)) {
			return Integer.TYPE.getName();
		} else if(Long.class.getName().equals(toCompareClass)) {
			return Long.TYPE.getName();
		} else if(Short.class.getName().equals(toCompareClass)) {
			return Short.TYPE.getName();
		} else if(Float.class.getName().equals(toCompareClass)) {
			return Float.TYPE.getName();
		} else if(Double.class.getName().equals(toCompareClass)) {
			return Double.TYPE.getName();
		} else if(Byte.class.getName().equals(toCompareClass)) {
			return Byte.TYPE.getName();
		} else if(Character.class.getName().equals(toCompareClass)) {
			return Character.TYPE.getName();
		} else if(Boolean.class.getName().equals(toCompareClass)) {
			return Boolean.TYPE.getName();
		}
		return null;
	}

	/**
	 * Transform an object type into associated primitive type
	 * @param toCompareClass
	 * @return
	 */
	public static Class primitize(Class toCompareClass) {
		if(Integer.class.equals(toCompareClass)) {
			return Integer.TYPE;
		} else if(Long.class.equals(toCompareClass)) {
			return Long.TYPE;
		} else if(Short.class.equals(toCompareClass)) {
			return Short.TYPE;
		} else if(Float.class.equals(toCompareClass)) {
			return Float.TYPE;
		} else if(Double.class.equals(toCompareClass)) {
			return Double.TYPE;
		} else if(Byte.class.equals(toCompareClass)) {
			return Byte.TYPE;
		} else if(Character.class.equals(toCompareClass)) {
			return Character.TYPE;
		} else if(Boolean.class.equals(toCompareClass)) {
			return Boolean.TYPE;
		}
		return null;
	}

	/**
	 * Transform a primitive type into its associated class : Integer.Type will become Integer.class, and so on ...
	 * @param toCompareClass
	 * @return
	 */
	public static Class objectify(Class toCompareClass) {
		if(Integer.TYPE.equals(toCompareClass)) {
			return Integer.class;
		} else if(Long.TYPE.equals(toCompareClass)) {
			return Long.class;
		} else if(Short.TYPE.equals(toCompareClass)) {
			return Short.class;
		} else if(Float.TYPE.equals(toCompareClass)) {
			return Float.class;
		} else if(Double.TYPE.equals(toCompareClass)) {
			return Double.class;
		} else if(Byte.TYPE.equals(toCompareClass)) {
			return Byte.class;
		} else if(Character.TYPE.equals(toCompareClass)) {
			return Character.class;
		} else if(Boolean.TYPE.equals(toCompareClass)) {
			return Boolean.class;
		}
		return null;
	}

	/**
	 * Generates a map linking uppercased field name to lwoercased one from a list of properties objects
	 */
	public static Map getUppercasedMap(Property[] fields) {
		Map fieldNames = new HashMap();
		for(Property f : fields) {
			String name = f.getName();
			fieldNames.put(uppercaseFirst(name), name);
		}
		return fieldNames;
	}

	/**
	 * Build a map linking method names to their associated object.
	 * As a convenience, methods declared by Object class are excluded from the returned map
	 * @param methods object visible methods (public ones)
	 * @return a map linking their first-upcased letter name to the {@link Method} object
	 */
	public static Map getUppercasedMap(Method[] methods) {
		Map fieldNames = new HashMap();
		for(Method method : methods) {
			if(!method.getDeclaringClass().equals(Object.class)) {
				String name = method.getName();
				fieldNames.put(uppercaseFirst(name), method);
			}
		}
		return fieldNames;
	}

	public static String uppercaseFirst(String name) {
		return name.substring(0, 1).toUpperCase()+name.substring(1);
	}

	/**
	 * Convert a string into an object of the class it is supposed to come from.
	 * This method is expected to work only for String (quite logical, isn't ?) and classes providing either a constructor using String as an argument,
	 * or a valueOf method having String as an argument. Any other case will miserably fail (ie a NoFromStringConversionExists will be thrown)
	 * @param value input string value
	 * @param type expected output type
	 * @return an object of that type
	 */
	@SuppressWarnings("unchecked")
	public static  Type fromString(String value, Class type) {
		if(String.class.equals(type)) {
			return (Type) value.toString();
		} else if(type.isPrimitive()) {
			return (Type) fromString(value, objectify(type));
		} else if(Object.class.equals(type)) {
			return (Type) value;
		} else if(URI.class.equals(type)) {
			try {
				return (Type) new URI(value);
			} catch(URISyntaxException e) {
				throw new UnableToBuilddURIException("\""+value+"\" can't be transformed into an URI object", e);
			}
		} else if(Class.class.equals(type)) {
			return (Type) classFromString(value);
		} else {
			/* First check if a constructor exists */
			try {
				Constructor withString = type.getDeclaredConstructor(String.class);
				return withString.newInstance(value);
			} catch(Exception e) {
				/* This constructor does not seems to exists. Is there any chance a "valueOf" method exists (useful for numbers objects) ? */
				try {
					Method valueOf = type.getDeclaredMethod("valueOf", String.class);
					return (Type) valueOf.invoke(null, value);
				} catch (Exception e1) {
					/* Seems like the reply is no */
					throw new NoFromStringConversionExistsException(type, e, e1);
				}
			}
		}
	}

	/**
	 * Try to load given type class
	 * @param value
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static  Type classFromString(String value) {
		value = maybeObjectify(value);
		ClassLoader[] used = new ClassLoader[] {value.getClass().getClassLoader(), Utils.class.getClassLoader(), Thread.currentThread().getContextClassLoader()};
		for(ClassLoader c : used) {
			if(c!=null) {
				try {
					return (Type) c.loadClass(value);
				} catch (ClassNotFoundException e) {
					// nothing to do, a better exception will be built later
				}
			}
		}
		throw new UnableToLoadClassException(value, used);
	}

	/**
	 * Similarly to {@link #getUppercasedMap(Method[])}, this method produces a map linking name (in their initial case) to the method object used to call them
	 * @param methods
	 * @return
	 */
	public static Map getNameMap(Method[] methods) {
		Map methodsNames = new HashMap();
		for(Method method : methods) {
			if(!method.getDeclaringClass().equals(Object.class)) {
				String name = method.getName();
				methodsNames.put(name, method);
			}
		}
		return methodsNames;
	}

	/**
	 * Put all classes extended or implemented by this one (including itself) in a collection.
	 * WARNING Notice this method should not be renamed or refactored in any fashion, as it is used by ClassCollectionProperty to obtain a generic type
	 * object retpresenting a Collection>
	 * @param declaring
	 * @return
	 */
	public static Collection> allClassesOf(Class declaring) {
		Collection> returned = new HashSet>();
		if(declaring!=null) {
			if(!declaring.equals(Object.class)) {
				returned.add(declaring);
				returned.addAll(allClassesOf(declaring.getSuperclass()));
				for(Class i : declaring.getInterfaces()) {
					returned.addAll(allClassesOf(i));
				}
			}
		}
		return returned;
	}

	/**
	 * Remove from the given list of methods all methods declared in gaedo packages
	 * @param methods
	 * @return
	 */
	public static Method[] removeGaedoInternalMethodsFrom(Method[] methods) {
		String gaedoBasePackage = "com.dooapp.gaedo";
		Collection filtered = new ArrayList();
		for(Method m : methods) {
			if(m.getDeclaringClass().isAssignableFrom(Informer.class)) {
				// this is Informer#get(String) method
				if(m.getName().equals("get") && m.getParameterTypes().length==1)
					filtered.add(m);
			} else {
				// method not declared in informer superinterfaces, so it can be added
				filtered.add(m);
			}
		}
		return filtered.toArray(new Method[filtered.size()]);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy