/* AngularBeans, CDI-AngularJS bridge Copyright (c) 2014, Bessem Hmidi. or third-party contributors as indicated by
* the @author tags or express copyright attribution statements applied by the authors. This copyrighted material is
* made available to anyone wishing to use, modify, copy, or redistribute it subject to the terms and conditions of the
* GNU Lesser General Public License, as published by the Free Software Foundation. This program is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. */
package angularBeans.util;
import static angularBeans.util.Accessors.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Named;
import org.boon.Pair;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import angularBeans.api.CORS;
import angularBeans.api.NGParamCast;
import angularBeans.api.http.Delete;
import angularBeans.api.http.Get;
import angularBeans.api.http.Post;
import angularBeans.api.http.Put;
import angularBeans.realtime.RealTime;
import java.beans.Introspector;
import java.lang.reflect.Array;
/**
* @author Bessem Hmidi
* @author Aymen Naili
*/
public abstract class CommonUtils {
/**
* used to obtain a bean java class from a bean name.
*/
public static final Map<String, Class> beanNamesHolder = new HashMap<>();
public static String getBeanName(Class targetClass) {
if (targetClass.isAnnotationPresent(Named.class)) {
Named named = (Named) targetClass.getAnnotation(Named.class);
if (!named.value().isEmpty()) {
return named.value();
}
}
String name = Introspector.decapitalize(targetClass.getSimpleName());
beanNamesHolder.put(name, targetClass);
return name;
}
public static String obtainGetter(Field field) {
String name = capitalize(field.getName());
if (field.getType().equals(Boolean.class) || field.getType().equals(boolean.class)) {
return BOOLEAN_GETTER_PREFIX + name;
} else {
return GETTER_PREFIX + name;
}
}
public static String obtainSetter(Field field) {
String name = capitalize(field.getName());
return SETTER_PREFIX + name;
}
public static JsonElement parse(String message) {
if (!message.startsWith("{")) {
return new JsonPrimitive(message);
}
JsonParser parser = new JsonParser();
return parser.parse(message);
}
/**
* Create a wrapper object for one of the primitive Java types from a string.
* Basically it calls {@code x.parseX(value)} after checking for
* {@code null} and empty argument.
* <p> For a {@code null} or empty value, {@code null} is returned.
* @param value String to convert
* @param type Type to convert to.
* @return Instance of the corresponding wrapper class or {@code null}
* @throws ArithmeticException if {@code value} cannot be parsed
* @throws IllegalArgumentException if {@code value} is not one of: primitive type,
* wrapper type, String, collection
*/
public static Object convertFromString(String value, Class type) {
if (isNullOrEmpty(value) || type.equals(byte[].class) || type.equals(Byte[].class)) {
return null;
}
if(String.class.equals(type)){
return value;
}
if (type.equals(int.class) || type.equals(Integer.class)) {
return Integer.parseInt(value);
}
if (type.equals(float.class) || type.equals(Float.class)) {
return Float.parseFloat(value);
}
if (type.equals(boolean.class) || type.equals(Boolean.class)) {
return Boolean.parseBoolean(value);
}
if (type.equals(double.class) || type.equals(Double.class)) {
return Double.parseDouble(value);
}
if (type.equals(byte.class) || type.equals(Byte.class)) {
return Byte.parseByte(value);
}
if (type.equals(long.class) || type.equals(Long.class)) {
return Long.parseLong(value);
}
if (type.equals(short.class) || type.equals(Short.class)) {
return Short.parseShort(value);
}
throw new IllegalArgumentException("unknown primitive type :"+type.getCanonicalName());
}
public static boolean isSetter(Method m) {
if (m == null) {
return false;
}
return m.getName().startsWith(SETTER_PREFIX) && returnsVoid(m)
&& hasOneParameter(m);
}
public static boolean isGetter(Method m) {
if (m == null) {
return false;
}
if (returnsVoid(m)) {
return false;
}
if (isHttpAnnotated(m)
|| m.isAnnotationPresent(RealTime.class)
|| m.isAnnotationPresent(CORS.class)) {
return false;
}
return hasNoParameters(m)
&& m.getName().startsWith(GETTER_PREFIX)
|| returnsBoolean(m) && m.getName().startsWith(BOOLEAN_GETTER_PREFIX);
}
public static boolean hasSetter(Class clazz, String fieldName) {
String setterName = SETTER_PREFIX + capitalize(fieldName);
setterName = setterName.trim();
for (Method m : clazz.getDeclaredMethods()) {
if (m.getName().equals(setterName) && isSetter(m)) {
return true;
}
}
return false;
}
public static String obtainFieldNameFromAccessor(String methodName) {
String fieldName;
if (methodName.startsWith(GETTER_PREFIX) || methodName.startsWith(SETTER_PREFIX)) {
fieldName = methodName.substring(3);
} else if (methodName.startsWith(BOOLEAN_GETTER_PREFIX)) {
fieldName = methodName.substring(2);
} else {
throw new IllegalArgumentException("Unable to obtain field name from method '"+methodName+"'.");
}
return Introspector.decapitalize(fieldName);
}
private static boolean isHttpAnnotated(Method m) {
if (m == null) {
return false;
}
return m.isAnnotationPresent(Get.class)
|| m.isAnnotationPresent(Post.class)
|| m.isAnnotationPresent(Put.class)
|| m.isAnnotationPresent(Delete.class);
}
private static boolean returnsBoolean(Method m) {
return m.getReturnType().equals(boolean.class) || m.getReturnType().equals(Boolean.class);
}
private static boolean returnsVoid(Method m) {
return m.getReturnType().equals(Void.class) || (m.getReturnType().equals(void.class));
}
private static boolean hasNoParameters(Method m) {
return m.getParameterTypes().length == 0;
}
private static boolean hasOneParameter(Method m) {
return m.getParameterTypes().length == 1;
}
private static String capitalize(String name) {
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
/**
* Check if the parameter is null or empty. If {@code o} is neither
* a String, an array or a Collection it is regarded as non-empty.
*
* @param <T> class type of tested object.
* @param o parameter to check.
* @return true if the parameter is {@code null} or empty, false otherwise.
*/
private static <T> Boolean isNullOrEmpty(final T o) {
if (o == null) {
return true;
}
if (o instanceof String) {
return "".equals(((String) o).trim());
}
if (o.getClass().isArray()) {
return Array.getLength(o) == 0;
}
if (o instanceof Collection<?>) {
return ((Collection<?>) o).isEmpty();
}
return false;
}
/**
* Get class method in accordance with the parameters informed
*
* @param clazz
* Source class
* @param methodName
* Method name
* @param paramSize
* Number of parameters for the method to be caught
* @return Method
* Class method
*/
public static Method getMethod(Class clazz, String methodName, int paramSize) {
for (Method mt: clazz.getMethods()) {
if (mt.getName().equals(methodName) && mt.getGenericParameterTypes().length == paramSize && !Modifier.isVolatile(mt.getModifiers())) {
return mt;
}
}
return null;
}
/**
* Returns the Map with the names and indexes defined in NGParamCast
*
* @param m
* Method to parse
* @return
* Map with indexes and names of types
*/
public static Pair<Boolean, Map<Integer, String>> getParamCastMap(Method m) {
if (m.isAnnotationPresent(NGParamCast.class)) {
Map<Integer, String> mParam = new HashMap<>();
NGParamCast ngCast = m.getAnnotation(NGParamCast.class);
boolean required = ngCast.required();
String[] params = ngCast.param();
if (params != null && params.length > 0) {
for (String param: params) {
param = param.trim();
if (param.contains("{") && param.contains("}")) {
int idxIni = param.indexOf("{");
String paramName = param.substring(0, idxIni).trim();
String[] paramIndex = param.substring(idxIni + 1, param.indexOf("}")).split(",");
for (String idx: paramIndex) {
mParam.put(Integer.parseInt(idx.trim()), paramName);
}
} else {
if (param.length() > 0) {
mParam.put(0, param);
}
}
}
}
return new Pair<>(required, mParam);
}
return null;
}
/**
*
* Returns the type of NGParamType defined in the implemented class
*
* @param service
* Class instantiated
* @param paramName
* Parameter name
* @param required
* Parameter required or not
* @return
* Parameter type instantiated in NGParamType
*/
public static Type getParamType(Object service, String paramName, boolean required) {
if (paramName != null && paramName.length() > 0) {
try {
Field field = service.getClass().getDeclaredField(paramName);
field.setAccessible(true);
return ((NGParamType<?>) field.get(service)).getType();
}
catch (Exception e) {
if (required) {
e.printStackTrace();
}
}
}
return null;
}
/**
* Returns the primitive base type of json
* @param element
* JSON element
* @return
* Primitive class of element
*/
public static Class getPrimitiveClass(JsonElement element) {
if (element.getAsJsonPrimitive().isBoolean()) {
return Boolean.class;
}
if (element.getAsJsonPrimitive().isNumber()) {
if (element.getAsString().contains(".")) {
return Double.class;
}
return Long.class;
}
return String.class;
}
}