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

step.core.dynamicbeans.DynamicBeanResolver Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (C) 2020, exense GmbH
 *  
 * This file is part of STEP
 *  
 * STEP is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *  
 * STEP 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 Affero General Public License for more details.
 *  
 * You should have received a copy of the GNU Affero General Public License
 * along with STEP.  If not, see .
 ******************************************************************************/
package step.core.dynamicbeans;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@SuppressWarnings("rawtypes")
public class DynamicBeanResolver {
	
	private static final Logger logger = LoggerFactory.getLogger(DynamicBeanResolver.class);
	
	private final DynamicValueResolver valueResolver;

	private final Map,BeanInfo> beanInfoCache = new ConcurrentHashMap<>();

	public DynamicBeanResolver(DynamicValueResolver valueResolver) {
		super();
		this.valueResolver = valueResolver;
	}

	public void evaluate(Object o, Map bindings) {
		if(o!=null) {
			Class clazz = o.getClass();
			
			try {
				BeanInfo beanInfo = beanInfoCache.get(clazz);
				if(beanInfo==null) {
					beanInfo = Introspector.getBeanInfo(clazz, Object.class);
					beanInfoCache.put(clazz, beanInfo);
				}

				// Handle public fields
				for (Field field:clazz.getFields()) {
					int modifiers = field.getModifiers();
					if(!Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers)) {
						if(field.getType().equals(DynamicValue.class)) {
							Object value = field.get(o);
							evaluateDynamicValue(bindings, (DynamicValue) value);
						} else if(field.isAnnotationPresent(ContainsDynamicValues.class)) {
							Object value = field.get(o);
							recursivelyEvaluateValue(bindings, value);
						}
					}
				}

				// Handle fields with getter / setter
				for(PropertyDescriptor descriptor:beanInfo.getPropertyDescriptors()) {
					Method method = descriptor.getReadMethod();
					if(method!=null) {
						if(method.getReturnType().equals(DynamicValue.class)) {
							Object value = method.invoke(o);
							evaluateDynamicValue(bindings, (DynamicValue) value);
						} else if(method.isAnnotationPresent(ContainsDynamicValues.class)) {
							Object value = method.invoke(o);
							recursivelyEvaluateValue(bindings, value);
						}
					}
				}
			} catch (Exception e) {
				if(logger.isDebugEnabled()) {
					logger.debug("Error while evaluating object: "+ o, e);
				}
			}			
		}
	}

	private void recursivelyEvaluateValue(Map bindings, Object value) {
		if (value instanceof  List) {
			List l = (List) value;
			l.forEach(v -> evaluate(v, bindings));
		} else {
			evaluate(value, bindings);
		}
	}

	private void evaluateDynamicValue(Map bindings, DynamicValue value) {
		if(value!=null) {
			valueResolver.evaluate(value, bindings);
			evaluate(value.get(), bindings);
		}
	}

	public  T cloneDynamicValues(T o) {
		if(o!=null) {
			try {
				Class clazz = o.getClass();
				@SuppressWarnings("unchecked")
				T out = (T) clazz.getConstructor().newInstance();
				if (List.class.isAssignableFrom(clazz)) {
					List l = (List) o;
					List outList = (List) out;
					l.forEach(c -> outList.add(cloneDynamicValues(c)));
				} else {
					BeanInfo beanInfo = beanInfoCache.get(clazz);
					if (beanInfo == null) {
						beanInfo = Introspector.getBeanInfo(clazz, Object.class);
						beanInfoCache.put(clazz, beanInfo);
					}

					// Handle public fields
					for (Field field:clazz.getFields()) {
						int modifiers = field.getModifiers();
						if(!Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers)) {
							Object oldValue = field.get(o);
							Object newValue = cloneDynamicValue(field, oldValue);
							field.set(out, newValue);
						}
					}

					// Handle fields with getters / setters
					for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
						Method method = descriptor.getReadMethod();
						if (method != null) {
							Object oldValue = method.invoke(o);
							Object newValue = cloneDynamicValue(method, oldValue);
							Method writeMethod = descriptor.getWriteMethod();
							if (writeMethod != null) {
								descriptor.getWriteMethod().invoke(out, newValue);
							}
						}
					}
				}
				return out;
			} catch (Exception e) {
				throw new RuntimeException("Error while cloning object "+ o,e);
			} 
		} else {
			return null;
		}
	}

	private Object cloneDynamicValue(AccessibleObject fieldOrMethod, Object oldValue) {
		Object newValue;
		if (oldValue != null) {
			if (oldValue instanceof DynamicValue) {
				DynamicValue dynamicValue = (DynamicValue) oldValue;
				newValue = dynamicValue.cloneValue();
			} else if (fieldOrMethod.isAnnotationPresent(ContainsDynamicValues.class)) {
				newValue = cloneDynamicValues(oldValue);
			} else {
				newValue = oldValue;
			}
		} else {
			newValue = null;
		}
		return newValue;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy