The main target for us was to come up with a solution, where we can perform two
task
1) Dynamically getting database relationship structure using Hibernate classes [ i.e. POJO ]
2) Dynamically perform recursive insertion/updation on database till end of relationship hierarchy without using single hardcode value
After much, discussions we explored Reflection APIs of JAVA using which we can use any field of any class, invoke any method of any class without even knowing class name,method name,field names. We built our entire solution around these features only.
As, we are using Hibernate POJOs to represent our database entity we used those Hibernate POJOs to use reflection API. Hibernate POJOs represents MANY side of a relationship using SET. i.e. POJO representing ONE side of relation will have a method, which is returning SET of MANY side. in example shown in problem statment above, Java class [ POJO ] representing DEPARTMENT will have a SET which provides information about all EMPLOYEE working under that department.
In our solution, we got an Object of master table using Hibernate methods [ call it OLD_OBJ ]. We made second copy of that object. [ call it NEW_OBJ]. we updated status of OLD_OBJ as INACTIVE record. all updations required was made to NEW_OBJ . Using reflection API, we got all childs of OLD_OBJ [i.e. SET of child ]. For all child we set the parent as NEW_OBJ by calling their respective methods using reflection. [ again, the updation will be taken place by same formule, i.e. DISABLE old record, create new copy and update new record] . We recursively did this operation till the end of database relation heirarchy.
This is merely 150 lines of code but it updates all tables in hierarchy whenever required [ in our case there are 17 tables which take part in 1-M relationship ]. We are contributing the solution just to show the power of Java reflection API so that this might be used whenever required.
1) Dynamically getting database relationship structure using Hibernate classes [ i.e. POJO ]
2) Dynamically perform recursive insertion/updation on database till end of relationship hierarchy without using single hardcode value
After much, discussions we explored Reflection APIs of JAVA using which we can use any field of any class, invoke any method of any class without even knowing class name,method name,field names. We built our entire solution around these features only.
As, we are using Hibernate POJOs to represent our database entity we used those Hibernate POJOs to use reflection API. Hibernate POJOs represents MANY side of a relationship using SET. i.e. POJO representing ONE side of relation will have a method, which is returning SET of MANY side. in example shown in problem statment above, Java class [ POJO ] representing DEPARTMENT will have a SET which provides information about all EMPLOYEE working under that department.
In our solution, we got an Object of master table using Hibernate methods [ call it OLD_OBJ ]. We made second copy of that object. [ call it NEW_OBJ]. we updated status of OLD_OBJ as INACTIVE record. all updations required was made to NEW_OBJ . Using reflection API, we got all childs of OLD_OBJ [i.e. SET of child ]. For all child we set the parent as NEW_OBJ by calling their respective methods using reflection. [ again, the updation will be taken place by same formule, i.e. DISABLE old record, create new copy and update new record] . We recursively did this operation till the end of database relation heirarchy.
This is merely 150 lines of code but it updates all tables in hierarchy whenever required [ in our case there are 17 tables which take part in 1-M relationship ]. We are contributing the solution just to show the power of Java reflection API so that this might be used whenever required.
/** * =============================================================== * SNIPLET FOR RECURSIVE INSERTION/UPDATION AND METHOD INVOCATION * =============================================================== **/ //FINDING OUT CLASS TYPE OF POJO Class classType = oldObject.getClass(); //FINDING OUT ALL METHODS OF THE POJO i.e. OLD_OBJ Method allMethods[] = classType.getDeclaredMethods(); try { logger.info("Start of method txGetChildObjects in InsertarGenericoServiceImpl"); //LOOPING THROUGH ALL THE METHODS for (int aMethod = 0; aMethod < classType.getDeclaredMethods().length; aMethod++) { //GETTING CURRENT METHOD Method currentMethodObj = allMethods[aMethod]; //FINDING OUT NAME OF CHILD CLASS String nameOfChildClass = currentMethodObj.getName().substring(3, currentMethodObj.getName().length() - 1); //IF THE METHOD IS RETURNING SET i.e. IT IS A METHOD WHICH IS GIVING US CHILD OF CURRENT PARENT //AND WE ARE IN OUR RELATIONSHIP HIERARCHY. if (currentMethodObj.getReturnType().getName().equalsIgnoreCase(ConstantesMITSeguros.CLASS_SET) && nameOfChildClass.startsWith(ConstantesMITSeguros.TRVTSG)) { //GETTING CLASS NAME String className = currentMethodObj.getName().substring(3, currentMethodObj.getName().length() - 1); //COPYING THE NAME TO USE IT FURTHUR String parentClass = parentName; //GETTING ALL CHILDREN BY INVOKING METHOD RETURNING SET Set child = (Set) currentMethodObj.invoke(oldObject, null); //ITERATING THROUGH CHILDRENT Iterator childIterator = child.iterator(); int iteratorCounter = 0; while (childIterator.hasNext() && iteratorCounter < child.size()) { iteratorCounter++; //GETTING CURRENT CHILD AND A CREATING COPY OF THAT CHILD Object currentChild = childIterator.next(); Object copyOfChild = currentChild.getClass().newInstance(); Class childClassType = currentChild.getClass(); //GETTING STATUS OF CURRENT OBJECT THROGH METHOD RETURNING STATUS OF THE RECORD //TO SET THE RECORD ACTIVE FLAG AS TRUE OR FALSE BigDecimal inactivo = (BigDecimal) (childClassType.getMethod(ConstantesMITSeguros.GET_INACTIVO, new Class[] {}).invoke(currentChild, new Object[] {})); BigDecimal inactivoCode = new BigDecimal(0); //IF THE RECORD IS AVTIVE if (inactivo.equals(inactivoCode)) { //COPY OBJECT this.copyObject(currentChild, copyOfChild); //INVOKE INACTIVO METHOD FOR CURRENT CHILD childClassType.getMethod(ConstantesMITSeguros.SET_INACTIVO, new Class[] { BigDecimal.class }).invoke(currentChild, new Object[] { new BigDecimal(1) }); //UPDATE OLD OBJECT insertarGenericoDAO.txUpdateGenerico(currentChild); //NOW SET PARENT FOR CURRENT CHILD AS NEW_OBJ String methodToCall = ConstantesMITSeguros.SET + parentClass; childClassType.getMethod(methodToCall, new Class[] { Class.forName(packagePath + ConstantesMITSeguros.DOT + parentClass) }).invoke(copyOfChild, new Object[] { newObject }); //NOW INSERT NEW OBJECT insertarGenericoDAO.txInsertarGenerico(copyOfChild); //DO THE PROCEDURE IN RECURSIVE MANNER this.txRecursiveInsertUpdateChildObjects(copyOfChild, copyOfChild, packagePath, className); } } } } logger.info("End of txGetChildObjects in InsertarGenericoServiceImpl"); } catch (Exception e) { logger.error("Error in txGetChildObjects in InsertarGenericoServiceImpl " + e.getMessage()); throw new BusinessException("Exception thrown from txGetChildObjects in InsertarGenericoServiceImpl " + e.getMessage()); } /** * =============================================================== * SNIPLET FOR COPYING HIBERNATE OBJECTS USING REFLECTION API * =============================================================== **/ //GETTING ALL METHODS OF OLD_OBJ REPRESNTING DATABASE TABLE ROW Method[] allMethods = oldObject.getClass().getDeclaredMethods(); logger.info("start of copyObject method in InsertarGenericoServiceImpl "); //LOOP THROUGH THE METHODS for (int methodCntr = 0; (methodCntr < allMethods.length); methodCntr++) { //FIND OUT IF THEY ARE GETTER METHODS if (allMethods[methodCntr].getName().substring(0, 3).equalsIgnoreCase("get")) { try { //TAKE CURRENT METHOD Method currentMethod = allMethods[methodCntr]; //GETTING SETTER METHOD RELAVANT TO CURRENT GETTER METHOD String methodToCall = ConstantesMITSeguros.SET+ currentMethod.getName().substring(3, currentMethod.getName().length()); //FINDING OUT CLASS FOR NEW_OBJ Class newObjectClass = newObject.getClass(); //INVOKING GETTER METHOD ON OLD_OBJ Object returnResult = currentMethod.invoke(oldObject, new Object[] {}); //INVOKING SETTER METHOD ON NEW_OBJ AND SET THE VALUES WHICH WE RECEIVED USING GETTER OF OLD_OBJ newObjectClass.getMethod(methodToCall, new Class[] { currentMethod.getReturnType() }).invoke(newObject, new Object[] { returnResult }); //IF THE RETURN TYPE IS SET i.e MANY SIDE OF A RELATION if (currentMethod.getReturnType().getName().equalsIgnoreCase(ConstantesMITSeguros.CLASS_SET)) { Class oldObjectClass = oldObject.getClass(); oldObjectClass.getMethod(methodToCall, new Class[] { currentMethod.getReturnType() }).invoke(oldObject, new Object[] { null }); } } catch (Exception e) { logger.error("Error in copyObject in InsertarGenericoServiceImpl " + e.getMessage()); throw new BusinessException("Exception thrown from copyObject in InsertarGenericoServiceImpl " + e.getMessage()); } } }