Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.granum.bpm.model.reflection.impl;
- import com.granum.bpm.common.model.CommonModel;
- import com.granum.bpm.model.reflection.FieldsUpdater;
- import lombok.SneakyThrows;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.logging.log4j.util.Strings;
- import org.springframework.stereotype.Component;
- import java.lang.reflect.Method;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.HashSet;
- import java.util.Optional;
- import java.util.Set;
- @Component
- @Slf4j
- @SuppressWarnings("unchecked")
- public class FieldsUpdaterImpl implements FieldsUpdater {
- public <T extends CommonModel> void updateEntity(T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
- if (modified == null || db == null)
- return;
- boolean result = false;
- final Class<? extends CommonModel> dbClass = db.getClass();
- final Method[] methods = dbClass.getMethods();
- if (handledClasses.contains(dbClass)) {
- log.info("Entity class [{}] has been already updated", dbClass.getSimpleName());
- return;
- }
- handledClasses.add(dbClass);
- final String handledClassesStr = String.join(", ", handledClasses.stream().map(Class::getSimpleName).toArray(String[]::new));
- log.info(" *** Update entity {}, id [{}]. HC: [{}]", db.getClass().getSimpleName(), db.getId(), handledClassesStr);
- for (Method method : methods) {
- try {
- if (isFieldUpdated(method, methods, db, modified, handledClasses) && !result)
- result = true;
- } catch (RuntimeException ignored) { }
- }
- handledClasses.remove(dbClass);
- }
- @SneakyThrows
- private <T extends CommonModel> boolean isFieldUpdated(Method method, Method[] methods, T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
- if (!checkIfCanHandleMethod(method))
- return false;
- log.info("Update field via getter [{}] for [{}]", method.getName(), db.getClass().getSimpleName());
- // Коллекции
- if (getAllParentClassesAndInterfaces(method.getReturnType()).contains(Collection.class))
- return handleCollection(method, methods, db, modified, handledClasses);
- // Вложенная сущность
- else if (getAllParentClassesAndInterfaces(method.getReturnType()).contains(CommonModel.class))
- return handleInner(method, methods, db, modified, handledClasses);
- // Текущая сущность
- else
- return handleEntity(method, methods, db, modified, handledClasses);
- }
- @SneakyThrows
- private <T extends CommonModel> boolean handleCollection(Method method, Method[] methods, T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
- Collection<CommonModel> dbCollection = (Collection<CommonModel>) method.invoke(db);
- Collection<CommonModel> modifiedCollection = (Collection<CommonModel>) modified.getClass().getMethod(method.getName()).invoke(modified);
- if (dbCollection == null || modifiedCollection == null)
- return false;
- for (CommonModel dbEntity : dbCollection) {
- if (dbEntity == null)
- continue;
- modifiedCollection
- .stream()
- .filter(modifiedEntity -> entitiesAreEqualsById(dbEntity, modifiedEntity))
- .forEach(modifiedEntity -> updateEntity(dbEntity, modifiedEntity, handledClasses));
- }
- return true;
- }
- @SneakyThrows
- private <T extends CommonModel> boolean handleInner(Method method, Method[] methods, T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
- CommonModel dbInner = (CommonModel) method.invoke(db);
- CommonModel modifiedInner = (CommonModel) modified.getClass().getMethod(method.getName()).invoke(modified);
- updateEntity(dbInner, modifiedInner, handledClasses);
- return true;
- }
- @SneakyThrows
- private <T extends CommonModel> boolean handleEntity(Method method, Method[] methods, T db, T modified, Set<Class<? extends CommonModel>> handledClasses) {
- Optional<Method> setterOptional = Arrays.stream(methods).filter(m -> m.getName().equals(String.format("set%s", method.getName().replaceFirst("get", "")))).findFirst();
- if (!setterOptional.isPresent())
- return false;
- Method getterDb = method;
- Method getterModified = Arrays.stream(modified.getClass().getMethods()).filter(m -> m.getName().equals(getterDb.getName())).findAny().get();
- Method setterDb = setterOptional.get();
- if (getterDb.invoke(db) == null || getterModified.invoke(modified) == null)
- return false;
- setterDb.invoke(db, getterModified.invoke(modified));
- return true;
- }
- private boolean checkIfCanHandleMethod(Method method) {
- if (method.getName().equals("getId"))
- return false;
- if (!method.getName().startsWith("get"))
- return false;
- if (method.getParameterTypes().length != 0)
- return false;
- if (void.class.equals(method.getReturnType()) || Class.class.equals(method.getReturnType()))
- return false;
- return true;
- }
- private Set<Class<?>> getAllParentClassesAndInterfaces(Class<?> clazz) {
- Set<Class<?>> result = new HashSet<>();
- Class<?> c = clazz;
- while (c != null) {
- result.add(c);
- c = c.getSuperclass();
- }
- if (clazz.getInterfaces().length != 0)
- Arrays.stream(clazz.getInterfaces()).map(cc -> (Class<?>) cc).forEach(result::add);
- return result;
- }
- private Optional<Method> getMethodIfExists(String methodName, Class<? extends CommonModel> clazz) {
- return Arrays.stream(clazz.getMethods()).filter(method -> method.getName().equals(methodName)).findFirst();
- }
- @SneakyThrows
- private <T extends CommonModel> boolean entitiesAreEqualsById(T e1, T e2) {
- String dbId = e1.getId();
- String modifiedId = e2.getId();
- // Костыль под number
- if (Strings.isEmpty(modifiedId)) {
- Optional<Method> numberOptional = getMethodIfExists("getNumber", e1.getClass());
- if (numberOptional.isPresent()) {
- Method dbNumber = numberOptional.get();
- Method modifiedNumber = Arrays.stream(e2.getClass().getMethods()).filter(m -> m.getName().equals(dbNumber.getName())).findAny().get();
- dbId = (String) dbNumber.invoke(e1);
- modifiedId = (String) modifiedNumber.invoke(e2);
- }
- }
- return modifiedId.equals(dbId);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement