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

com.googlecode.jmapper.util.ClassesManager Maven / Gradle / Ivy

Go to download

JMapper Framework is a java bean mapper based on javassist. JMapper exposes interesting features as relational mapping, dynamic conversions and more

There is a newer version: 1.6.4
Show newest version
/**
 * Copyright (C) 2012 - 2016 Alessandro Vurro.
 *
 * Licensed 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 com.googlecode.jmapper.util;

import static com.googlecode.jmapper.operations.NestedMappingHandler.isNestedMapping;
import static com.googlecode.jmapper.util.AutoBoxing.boxingOperations;
import static com.googlecode.jmapper.util.AutoBoxing.unBoxingOperations;
import static com.googlecode.jmapper.util.FilesManager.isPath;
import static com.googlecode.jmapper.util.GeneralUtility.collectionIsAssignableFrom;
import static com.googlecode.jmapper.util.GeneralUtility.enrichList;
import static com.googlecode.jmapper.util.GeneralUtility.getMethod;
import static com.googlecode.jmapper.util.GeneralUtility.isAccessModifier;
import static com.googlecode.jmapper.util.GeneralUtility.isBoolean;
import static com.googlecode.jmapper.util.GeneralUtility.isEmpty;
import static com.googlecode.jmapper.util.GeneralUtility.isNull;
import static com.googlecode.jmapper.util.GeneralUtility.mGet;
import static com.googlecode.jmapper.util.GeneralUtility.mSet;
import static com.googlecode.jmapper.util.GeneralUtility.mapIsAssignableFrom;
import static com.googlecode.jmapper.util.GeneralUtility.toList;
import static com.googlecode.jmapper.util.GeneralUtility.write;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.googlecode.jmapper.annotations.Annotation;
import com.googlecode.jmapper.config.Constants;
import com.googlecode.jmapper.config.Error;
import com.googlecode.jmapper.enums.ChooseConfig;
import com.googlecode.jmapper.operations.beans.MappedField;
import com.googlecode.jmapper.xml.XML;
/**
 * Utility class that allows you to manage classes.
 * @author Alessandro Vurro
 */
public final class ClassesManager {

	private ClassesManager() { }
	
	/**
	 * this method verify that the istruction: 
	 * 

destination.putAll(source)

is permitted * * @param destination destination field * @param source source field * @return true if the istruction destination.putAll(source) is permitted */ public static boolean isPutAllPermitted(Field destination,Field source){ boolean isFirst = true; boolean isAddAllFunction = false; boolean isPutAllFunction = true; return isAssignableFrom(getGenericString(destination), getGenericString(source), destination.getType(), source.getType(), isFirst, isAddAllFunction, isPutAllFunction); } /** * this method verify that the istruction: *

destination.addAll(source)

is permitted * * @param destination destination field * @param source source field * @return true if the istruction destination.addAll(source) is permitted */ public static boolean isAddAllPermitted(Field destination,Field source){ boolean isFirst = true; boolean isAddAllFunction = true; boolean isPutAllFunction = false; return isAssignableFrom(getGenericString(destination), getGenericString(source), destination.getType(), source.getType(), isFirst, isAddAllFunction, isPutAllFunction); } /** * this method verify that the instruction: *

destination = source *

is permitted, checking their generics also * * @param destination of type {@link MappedField} * @param source of type {@link MappedField} * @return true if destination is assignable from source */ public static boolean isAssignableFrom(MappedField destination,MappedField source) { return isAssignableFrom(destination.getValue(), source.getValue()); } /** * this method verify that the instruction: *

destination = source *

is permitted, checking their generics also * * @param destination destination field * @param source source field * @return true if destination is assignable from source */ public static boolean isAssignableFrom(Field destination,Field source) { boolean isFirst = true; boolean isAddAllFunction = false; boolean isPutAllFunction = false; return isAssignableFrom(getGenericString(destination), getGenericString(source), destination.getType(),source.getType(),isFirst, isAddAllFunction, isPutAllFunction); } /** * Returns true if destination is assignable from source analyzing autoboxing also. * @param destination destination class * @param source source class * @return true if destination is assignable from source analyzing autoboxing also. */ public static boolean isAssignableFrom(Class destination,Class source){ return destination.isAssignableFrom(source) || isBoxing(destination,source) || isUnBoxing(destination,source); } /** * Method used from {@link ClassesManager#isAssignableFrom(Field, Field)},{@link ClassesManager#isAddAllPermitted(Field, Field)} and * {@link ClassesManager#isPutAllPermitted(Field, Field)} methods * @param genericD generic item * @param genericS generic item * @param classD class type of Destination * @param classS class type of Source * @param isFirst true if is first interaction, false otherwise * @param isAddAllFunction true if is an addAll operation, false otherwise * @param isPutAllFunction true if is a putAll operation, false otherwise * @return true if destination field is assignable from source field, false otherwise */ private static boolean isAssignableFrom(String genericD,String genericS,Class classD,Class classS,boolean isFirst, boolean isAddAllFunction,boolean isPutAllFunction){ try{ int dStartBracket = genericD.indexOf("<"); int sStartBracket = genericS.indexOf("<"); int dEndBracket = genericD.lastIndexOf(">"); int sEndBracket = genericS.lastIndexOf(">"); // if there aren't generics if(dStartBracket==-1 && sStartBracket==-1 && dEndBracket==-1 && sEndBracket==-1) if(isFirst) return functionsAreAllowed(isAddAllFunction, isPutAllFunction, classD, classS); else{ genericD = "?".equals(genericD)?"java.lang.Object":genericD; genericS = "?".equals(genericS)?"java.lang.Object":genericS; return isAssignableFrom(Class.forName(genericD),Class.forName(genericS)); } // destination class String dBeforeBracket = ""; // source class String sBeforeBracket = ""; // destination class defined in the generic String dAfterBracket = ""; // source class defined in the generic String sAfterBracket = ""; // if generics exists if(dStartBracket!=-1 && dEndBracket!=-1){ // destination class dBeforeBracket = genericD.substring(0, dStartBracket).trim(); // destination class defined in the generic dAfterBracket = genericD.substring(dStartBracket+1,dEndBracket); } // if generics exists if(sStartBracket!=-1 && sEndBracket!=-1){ // source class sBeforeBracket = genericS.substring(0, sStartBracket).trim(); // source class defined in the generic sAfterBracket = genericS.substring(sStartBracket+1,sEndBracket); } if(isEmpty(dBeforeBracket) && !isEmpty(sBeforeBracket)) dBeforeBracket = genericD; if(!isEmpty(dBeforeBracket) && isEmpty(sBeforeBracket)) sBeforeBracket = genericS; boolean isAssignableFrom = false; if(!isEmpty(dBeforeBracket) && !isEmpty(sBeforeBracket)) isAssignableFrom = isFirst?functionsAreAllowed(isAddAllFunction, isPutAllFunction, classD, classS): isAssignableFrom(Class.forName(dBeforeBracket),Class.forName(sBeforeBracket)); if(!isEmpty(dAfterBracket) && !isEmpty(sAfterBracket)){ if(isAddAllFunction) return isAssignableFrom && isAssignableFrom(dAfterBracket, sAfterBracket, null, null, false, false, false); if(isPutAllFunction){ int dSplitIndex = pairSplitIndex(dAfterBracket); String dKey = dAfterBracket.substring(0, dSplitIndex).trim(); String dValue = dAfterBracket.substring(dSplitIndex+1).trim(); int sSplitIndex = pairSplitIndex(sAfterBracket); String sKey = sAfterBracket.substring(0, sSplitIndex).trim(); String sValue = sAfterBracket.substring(sSplitIndex+1).trim(); return isAssignableFrom && isAssignableFrom(dKey, sKey, null, null, false, false, false) && isAssignableFrom(dValue, sValue, null, null, false, false, false); } return isAssignableFrom && dAfterBracket.equals(sAfterBracket); } return isAssignableFrom; }catch (Exception e) { return false; } } /** * Returns true if the function to check is allowed. * @param isAddAllFunction true if addAll method is to check * @param isPutAllFunction true if putAll method is to check * @param classD destination class * @param classS source class * @return true if the function to check is allowed */ private static boolean functionsAreAllowed(boolean isAddAllFunction, boolean isPutAllFunction,Class classD,Class classS) { if(isAddAllFunction) return collectionIsAssignableFrom(classD) && collectionIsAssignableFrom(classS); if(isPutAllFunction) return mapIsAssignableFrom(classD) && mapIsAssignableFrom(classS); return isAssignableFrom(classD,classS); } /** * Returns true if is an unboxing operation, false otherwise. * @param destination the primitive Class * @param source the Wrapper Class * @return true if is an unboxing operation, false otherwise */ public static boolean isUnBoxing(Class destination,Class source){ return isAutoboxingOperation(unBoxingOperations,destination,source); } /** * Returns true if is a boxing operation, false otherwise. * @param destination the Wrapper Class * @param source the primitive Class * @return true if is a boxing operation, false otherwise */ public static boolean isBoxing(Class destination,Class source){ return isAutoboxingOperation(boxingOperations,destination,source); } /** * @param map Map that contains autoboxing operations, see {@link AutoBoxing#unBoxingOperations} and {@link AutoBoxing#boxingOperations} * @param destination class type of Destination * @param source class type of Source * @return true if operation between destination and source rappresents a map operation */ private static boolean isAutoboxingOperation( HashMap map,Class destination,Class source){ String[] names = map.get(destination.getName()); if(names != null) for (String name : names) if(name.equals(source.getName())) return true; return false; } /** * @param str string to split * @return pair split index */ private static int pairSplitIndex(String str){ int openBracket = 0; int closedBracket = 0; char[] array = str.toCharArray(); for(int i = 0; i < str.length(); i++){ char it = array[i]; if(it=='<')openBracket++; if(it=='>')closedBracket++; if(it==',' && (openBracket - closedBracket) == 0)return i; } return 0; } /** * Splits the fieldDescription to obtain his class type,generics inclusive. * @param field field to check * @return returns a string that specified the structure of the field, including its generic */ public static String getGenericString(Field field){ String fieldDescription = field.toGenericString(); List splitResult = new ArrayList(); char[] charResult = fieldDescription.toCharArray(); boolean isFinished = false; int separatorIndex = fieldDescription.indexOf(" "); int previousIndex = 0; while(!isFinished){ // if previous character is "," don't cut the string int position = separatorIndex-1; char specialChar = charResult[position]; boolean isSpecialChar = true; if(specialChar!=',' && specialChar != '?'){ if(specialChar == 's'){ String specialString = null; try{ specialString = fieldDescription.substring(position - "extends".length(), position+1); if(isNull(specialString) || !" extends".equals(specialString)) isSpecialChar = false; }catch(IndexOutOfBoundsException e){ isSpecialChar = false; } }else isSpecialChar = false; } if(!isSpecialChar){ splitResult.add(fieldDescription.substring(previousIndex, separatorIndex)); previousIndex = separatorIndex+1; } separatorIndex = fieldDescription.indexOf(" ",separatorIndex+1); if(separatorIndex == -1)isFinished = true; } for (String description : splitResult) if(!isAccessModifier(description)) return description; return null; } /** * Returns true if destination and source have the same structure. * @param destination destination field * @param source source field * @return returns true if destination and source have the same structure */ public static boolean areEqual(Field destination,Field source){ return getGenericString(destination).equals(getGenericString(source)); } /** * Returns the name of mapper that identifies the destination and source classes. * * @param destination class of Destination * @param source class of Source * @param resource a resource that represents an xml path or a content * @return Returns a string containing the names of the classes passed as input */ public static String mapperClassName(Class destination, Class source, String resource){ String className = destination.getName().replaceAll("\\.","") + source.getName().replaceAll("\\.",""); if(isEmpty(resource)) return className; if(!isPath(resource)) return write(className, String.valueOf(resource.hashCode())); String[]dep = resource.split("\\\\"); if(dep.length<=1)dep = resource.split("/"); String xml = dep[dep.length-1]; return write(className, xml.replaceAll("\\.","").replaceAll(" ","")); } /** * This method returns the name of the field whose name matches with regex. * @param aClass a class to control * @param regex field name * @return true if exists a field with this name in aClass, false otherwise */ public static String fieldName(Class aClass,String regex){ if(isNestedMapping(regex)) return regex; String result = null; for(Class clazz: getAllsuperClasses(aClass)) if(!isNull(result = getFieldName(clazz, regex))) return result; return result; } /** * This method returns the name of the field whose name matches with regex. * @param aClass class to check * @param regex regex used to find the field * @return the field name if exists, null otherwise */ private static String getFieldName(Class aClass,String regex){ for (Field field : aClass.getDeclaredFields()) if(field.getName().matches(regex)) return field.getName(); return null; } /** * returns true if almost one class is configured, false otherwise. * @param dClass class to verify * @param sClass class to verify * @param xml xml to check * @return true if almost one class is configured, false otherwise. */ public static boolean areMappedObjects(Class dClass,Class sClass,XML xml){ return isMapped(dClass,xml) || isMapped(sClass,xml); } /** * Returns true if the class is configured in annotation or xml, false otherwise. * @param aClass a class * @param xml xml to check * @return true if the class is configured in annotation or xml, false otherwise */ private static boolean isMapped(Class aClass,XML xml){ return xml.isInheritedMapped(aClass) || Annotation.isInheritedMapped(aClass); } /** * Returns a list with the class passed in input plus his superclasses. * @param aClass class to check * @return a classes list */ public static List> getAllsuperClasses(Class aClass){ List> result = new ArrayList>(); result.add(aClass); Class superclass = aClass.getSuperclass(); while(!isNull(superclass) && superclass != Object.class){ result.add(superclass); superclass = superclass.getSuperclass(); } return result; } /** * Returns a List of aClass fields and all fields of its super classes. * @param aClass class to handle * @return a list of aClass fields */ public static List getListOfFields(Class aClass){ List listOfFields = new ArrayList(); for (Class clazz : getAllsuperClasses(aClass)) enrichList(listOfFields, clazz.getDeclaredFields()); return getFilteredFields(listOfFields); } /** * It exclude from list all synthetic fields and serialVersionUID. * @param listOfFields list to check * @return filtered list */ private static List getFilteredFields(List listOfFields){ List fitleredFields = new ArrayList(); for (Field field : listOfFields) if(!field.isSynthetic() && !"serialVersionUID".equals(field.getName())) fitleredFields.add(field); return fitleredFields; } /** * Returns all methods that belongs to aClass. * @param aClass class to check * @return list of methods */ public static List getAllMethods(Class aClass){ List listOfMethods = toList(aClass.getDeclaredMethods()); Class superclass = aClass.getSuperclass(); while(superclass != Object.class){ listOfMethods = getMethods(listOfMethods, superclass); superclass = superclass.getSuperclass(); } return listOfMethods; } /** * Used in a recursive context, retuns a list with the existingMethod plus eventually classToCheck's methods * @param existingMethods list of existing methods * @param classToCheck class to check * @return an enriched list */ private static List getMethods(List existingMethods, Class classToCheck){ List result = new ArrayList(existingMethods); for (Method methodToCheck : classToCheck.getDeclaredMethods()) for (Method method : existingMethods) if(!method.getName().equals(methodToCheck.getName())) result.add(methodToCheck); return result; } /** * Returns a field with a specific name from class given as input. * * @param clazz class to handle * @param regex name of field to retrieve * @return field if exist, null otherwise */ public static Field retrieveField(Class clazz, String regex){ for (Field field : getListOfFields(clazz)) if(field.getName().equals(regex)) return field; return null; } /** * Verifies that the accessor methods are compliant with the naming convention. * @param clazz a class to check * @param fields fields to control */ public static void verifiesAccessorMethods(Class clazz, MappedField... fields){ verifyGetterMethods(clazz, fields); verifySetterMethods(clazz, fields); } /** * Verifies that the getter methods are compliant with the naming convention. * @param clazz a class to check * @param fields fields to control */ public static void verifyGetterMethods(Class clazz, MappedField... fields){ for (MappedField field : fields) { String fieldName = field.getName(); Class fieldType = field.getType(); // find custom get first String customGet = field.getMethod(); if(!isNull(customGet) && !customGet.equals(Constants.DEFAULT_ACCESSOR_VALUE)) try{ clazz.getMethod(customGet); continue; }catch(Exception e) { Error.customMethod("get", customGet, clazz); } String methodName = getMethod(fieldType,fieldName); try{ clazz.getMethod(methodName); }catch(Exception e) { if(!isBoolean(fieldType)) Error.method(methodName, fieldName, clazz); try { //in case of boolean field i try to find get method methodName = (mGet(fieldName)); clazz.getMethod(methodName); } catch (Exception e1) { Error.method(methodName, fieldName, clazz); } } // store the getMethod name field.getMethod(methodName); } } /** * Find and store setter methods. * @param clazz a class to check * @param fields fields to control */ public static void findSetterMethods(Class clazz, MappedField... fields){ try{verifySetterMethods(clazz, fields); }catch(Exception e){} } /** * Verifies that the setter methods are compliant with the naming convention. * @param clazz a class to check * @param fields fields to control */ public static void verifySetterMethods(Class clazz, MappedField... fields){ String methodName = null; String fieldName = null; Class fieldType = null; try{for (MappedField field : fields) { fieldName = field.getName(); fieldType = field.getType(); // find custom set first String customSet = field.setMethod(); if(!isNull(customSet) && !customSet.equals(Constants.DEFAULT_ACCESSOR_VALUE)) try{ clazz.getMethod(customSet,fieldType); // store the setMethod name field.setMethod(customSet); continue; }catch(Exception e) { Error.customMethod("set", customSet, clazz); } methodName = mSet(fieldName); clazz.getMethod(methodName,fieldType); // store the setMethod name field.setMethod(methodName); } }catch(Exception e) { Error.method(methodName, fieldName, clazz); } } /** * returns the location of the configuration, null if both classes are configured. * @param dItem class to analyze * @param sItem class to analyze * @param xml mapping xml * @return the location of the configuration, null if both classes are configured. */ public static ChooseConfig configChosen(ClassdItem,ClasssItem,XML xml){ return isMapped(dItem,xml) && isMapped(sItem,xml)?null: isMapped(dItem,xml)?ChooseConfig.DESTINATION:ChooseConfig.SOURCE; } /** * If the generics written is ? returns the Object class name. * @param structure generics string * @return the content of this generics string */ private static String obtainGenericContent(String structure){ String item = structure.substring(structure.indexOf("<")+1, structure.indexOf(">")); int internalGeneric = item.indexOf("<"); if(internalGeneric != -1) item = item.substring(0, internalGeneric); return "?".equals(item)?"java.lang.Object":item; } /** * Extracts the value of a field from an object.
* Example: *
MyClass { *
private String aField; *
get and set... *
} *
*
String aFieldValue = getFieldValue(new MyClass("example"),"aField"); *
assertEqual("example",aFieldValue);
* @param obj used to obtain relative class * @param fieldName field name * @param used to avoid explicit cast * @return the value of a field from an object */ @SuppressWarnings("unchecked") public static T getFieldValue(Object obj,String fieldName){ try { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); return (T) field.get(obj); } catch (Exception e) { return null;} } /** * Extracts the generic class from the type of Mappedfield given as input.
* Example: *
MyClass { *
List<String> aList; *
get and set... *
} *
*
Field aField = MyClass.class.getDeclaredField("aList"); *
Class<?> generic = getCollectionItemClass(aField); *
assertEqual(generic,String.class);
* @param generic a Field * @return a Class contained in the class type of the field, returns null if no generics */ public static Class getCollectionItemClass(MappedField generic) { return getCollectionItemClass(generic.getValue()); } /** * Extracts the generic class from the type of field given as input.
* Example: *
MyClass { *
List<String> aList; *
get and set... *
} *
*
Field aField = MyClass.class.getDeclaredField("aList"); *
Class<?> generic = getCollectionItemClass(aField); *
assertEqual(generic,String.class);
* @param generic a Field * @return a Class contained in the class type of the field, returns null if no generics */ public static Class getCollectionItemClass(Field generic) { String item = obtainGenericContent(getGenericString(generic)); try { return Class.forName(item); } catch (Exception e) { return null; } } /** * Extracts the generic class from the type of Mappedfield given as input.
* Example: *
MyClass { *
Map<String, Integer> aMap; *
get and set... *
} *
*
Field aField = MyClass.class.getDeclaredField("aMap"); *
Class<?> generic = getGenericMapKeyItem(aField); *
assertEqual(generic,String.class);
* @param generic a Field * @return a Class contained in the class type of the field */ public static Class getGenericMapKeyItem(MappedField generic) { return getGenericMapKeyItem(generic.getValue()); } /** * Extracts the generic class from the type of Mappedfield given as input.
* Example: *
MyClass { *
Map<String, Integer> aMap; *
get and set... *
} *
*
Field aField = MyClass.class.getDeclaredField("aMap"); *
Class<?> generic = getGenericMapKeyItem(aField); *
assertEqual(generic,String.class);
* @param generic a Field * @return a Class contained in the class type of the field */ public static Class getGenericMapKeyItem(Field generic) { String item = obtainGenericContent(getGenericString(generic)); try { return Class.forName(item.split(",")[0].trim()); } catch (Exception e) { return null; } } /** * Extracts the generic class from the type of Mappedfield given as input.
* Example: *
MyClass { *
Map<String, Integer> aMap; *
get and set... *
} *
*
Field aField = MyClass.class.getGenericMapValueItem("aMap"); *
Class<?> generic = getGenericMapKeyItem(aField); *
assertEqual(generic,Integer.class);
* @param generic a Field * @return a Class contained in the class type of the field */ public static Class getGenericMapValueItem(MappedField generic) { return getGenericMapValueItem(generic.getValue()); } /** * Extracts the generic class from the type of field given as input.
* Example: *
MyClass { *
Map<String, Integer> aMap; *
get and set... *
} *
*
Field aField = MyClass.class.getGenericMapValueItem("aMap"); *
Class<?> generic = getGenericMapKeyItem(aField); *
assertEqual(generic,Integer.class);
* @param generic a Field * @return a Class contained in the class type of the field */ public static Class getGenericMapValueItem(Field generic) { String item = obtainGenericContent(getGenericString(generic)); try { return Class.forName(item.split(",")[1].trim()); } catch (Exception e) { return null; } } /** * Extracts the generic class from the type of field given as input.
* Example: *
MyClass { *
MyObj[] anArray; *
get and set... *
} *
*
Field aField = MyClass.class.getDeclaredField("anArray"); *
Class<?> item = getArrayItemClass(aField); *
assertEqual(item,MyObj.class);
* @param field a Field * @return a Class contained in the class type of the field */ public static Class getArrayItemClass(MappedField field) { return field.getType().getComponentType(); } /** * Retrieves (from a field of map type) the key and value classes. * * @param field to analyze * @param key key class * @param value value class */ public static void getKeyValueClasses(Field field,Class key, Class value){ if(!mapIsAssignableFrom(field.getType())) throw new IllegalArgumentException("the field is not a map"); String generic = field.toGenericString(); String[] pair = generic.substring(generic.indexOf("<")+1, generic.indexOf(">")).split(", "); try { key = Class.forName(pair[0].trim()); value = Class.forName(pair[1].trim()); } catch (ClassNotFoundException e) { key = null; value = null; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy