Advertisement
Guest User

Untitled

a guest
Nov 12th, 2019
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 6.77 KB | None | 0 0
  1. package com.granum.bpm.model.reflection.impl;
  2.  
  3. import com.granum.bpm.common.model.CommonModel;
  4. import com.granum.bpm.model.reflection.FieldsUpdater;
  5. import lombok.SneakyThrows;
  6. import lombok.extern.slf4j.Slf4j;
  7. import org.apache.logging.log4j.util.Strings;
  8. import org.springframework.stereotype.Component;
  9.  
  10. import java.lang.reflect.Method;
  11. import java.util.Arrays;
  12. import java.util.Collection;
  13. import java.util.HashSet;
  14. import java.util.Optional;
  15. import java.util.Set;
  16.  
  17. @Component
  18. @Slf4j
  19. @SuppressWarnings("unchecked")
  20. public class FieldsUpdaterImpl implements FieldsUpdater {
  21.  
  22.     public <T extends CommonModel> void updateEntity(T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
  23.         if (modified == null || db == null)
  24.             return;
  25.  
  26.         boolean result = false;
  27.  
  28.         final Class<? extends CommonModel> dbClass = db.getClass();
  29.         final Method[] methods = dbClass.getMethods();
  30.  
  31.         if (handledClasses.contains(dbClass)) {
  32.             log.info("Entity class [{}] has been already updated", dbClass.getSimpleName());
  33.  
  34.             return;
  35.         }
  36.  
  37.         handledClasses.add(dbClass);
  38.  
  39.         final String handledClassesStr = String.join(", ", handledClasses.stream().map(Class::getSimpleName).toArray(String[]::new));
  40.  
  41.         log.info(" *** Update entity {}, id [{}]. HC: [{}]", db.getClass().getSimpleName(), db.getId(), handledClassesStr);
  42.  
  43.         for (Method method : methods) {
  44.             try {
  45.                 if (isFieldUpdated(method, methods, db, modified, handledClasses) && !result)
  46.                     result = true;
  47.  
  48.             } catch (RuntimeException ignored) { }
  49.         }
  50.  
  51.         handledClasses.remove(dbClass);
  52.     }
  53.  
  54.     @SneakyThrows
  55.     private <T extends CommonModel> boolean isFieldUpdated(Method method, Method[] methods, T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
  56.         if (!checkIfCanHandleMethod(method))
  57.             return false;
  58.  
  59.         log.info("Update field via getter [{}] for [{}]", method.getName(), db.getClass().getSimpleName());
  60.  
  61.         // Коллекции
  62.         if (getAllParentClassesAndInterfaces(method.getReturnType()).contains(Collection.class))
  63.             return handleCollection(method, methods, db, modified, handledClasses);
  64.  
  65.         // Вложенная сущность
  66.         else if (getAllParentClassesAndInterfaces(method.getReturnType()).contains(CommonModel.class))
  67.             return handleInner(method, methods, db, modified, handledClasses);
  68.  
  69.         // Текущая сущность
  70.         else
  71.             return handleEntity(method, methods, db, modified, handledClasses);
  72.     }
  73.  
  74.     @SneakyThrows
  75.     private <T extends CommonModel> boolean handleCollection(Method method, Method[] methods, T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
  76.         Collection<CommonModel> dbCollection = (Collection<CommonModel>) method.invoke(db);
  77.         Collection<CommonModel> modifiedCollection = (Collection<CommonModel>) modified.getClass().getMethod(method.getName()).invoke(modified);
  78.  
  79.         if (dbCollection == null || modifiedCollection == null)
  80.             return false;
  81.  
  82.         for (CommonModel dbEntity : dbCollection) {
  83.             if (dbEntity == null)
  84.                 continue;
  85.  
  86.             modifiedCollection
  87.                     .stream()
  88.                     .filter(modifiedEntity -> entitiesAreEqualsById(dbEntity, modifiedEntity))
  89.                     .forEach(modifiedEntity -> updateEntity(dbEntity, modifiedEntity, handledClasses));
  90.         }
  91.  
  92.         return true;
  93.     }
  94.  
  95.     @SneakyThrows
  96.     private <T extends CommonModel> boolean handleInner(Method method, Method[] methods, T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
  97.         CommonModel dbInner = (CommonModel) method.invoke(db);
  98.         CommonModel modifiedInner = (CommonModel) modified.getClass().getMethod(method.getName()).invoke(modified);
  99.         updateEntity(dbInner, modifiedInner, handledClasses);
  100.  
  101.         return true;
  102.     }
  103.  
  104.     @SneakyThrows
  105.     private <T extends CommonModel> boolean handleEntity(Method method, Method[] methods, T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
  106.         Optional<Method> setterOptional = Arrays.stream(methods).filter(m -> m.getName().equals(String.format("set%s", method.getName().replaceFirst("get", "")))).findFirst();
  107.  
  108.         if (!setterOptional.isPresent())
  109.             return false;
  110.  
  111.         Method getterDb = method;
  112.         Method getterModified = Arrays.stream(modified.getClass().getMethods()).filter(m -> m.getName().equals(getterDb.getName())).findAny().get();
  113.         Method setterDb = setterOptional.get();
  114.  
  115.         if (getterDb.invoke(db) == null || getterModified.invoke(modified) == null)
  116.             return false;
  117.  
  118.         setterDb.invoke(db, getterModified.invoke(modified));
  119.  
  120.         return true;
  121.     }
  122.  
  123.     private boolean checkIfCanHandleMethod(Method method) {
  124.         if (method.getName().equals("getId"))
  125.             return false;
  126.  
  127.         if (!method.getName().startsWith("get"))
  128.             return false;
  129.  
  130.         if (method.getParameterTypes().length != 0)
  131.             return false;
  132.  
  133.         if (void.class.equals(method.getReturnType()) || Class.class.equals(method.getReturnType()))
  134.             return false;
  135.  
  136.         return true;
  137.     }
  138.  
  139.     private Set<Class<?>> getAllParentClassesAndInterfaces(Class<?> clazz) {
  140.         Set<Class<?>> result = new HashSet<>();
  141.  
  142.         Class<?> c = clazz;
  143.         while (c != null) {
  144.             result.add(c);
  145.             c = c.getSuperclass();
  146.         }
  147.  
  148.         if (clazz.getInterfaces().length != 0)
  149.             Arrays.stream(clazz.getInterfaces()).map(cc -> (Class<?>) cc).forEach(result::add);
  150.  
  151.         return result;
  152.     }
  153.  
  154.     private Optional<Method> getMethodIfExists(String methodName, Class<? extends CommonModel> clazz) {
  155.         return Arrays.stream(clazz.getMethods()).filter(method -> method.getName().equals(methodName)).findFirst();
  156.     }
  157.  
  158.     @SneakyThrows
  159.     private <T extends CommonModel> boolean entitiesAreEqualsById(T e1, T e2) {
  160.         String dbId = e1.getId();
  161.         String modifiedId = e2.getId();
  162.  
  163.         // Костыль под number
  164.         if (Strings.isEmpty(modifiedId)) {
  165.             Optional<Method> numberOptional = getMethodIfExists("getNumber", e1.getClass());
  166.  
  167.             if (numberOptional.isPresent()) {
  168.                 Method dbNumber = numberOptional.get();
  169.                 Method modifiedNumber = Arrays.stream(e2.getClass().getMethods()).filter(m -> m.getName().equals(dbNumber.getName())).findAny().get();
  170.  
  171.                 dbId = (String) dbNumber.invoke(e1);
  172.                 modifiedId = (String) modifiedNumber.invoke(e2);
  173.             }
  174.         }
  175.  
  176.         return modifiedId.equals(dbId);
  177.     }
  178. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement