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

org.onetwo.common.reflect.BeanToMapConvertor Maven / Gradle / Ivy

There is a newer version: 4.7.2
Show newest version
package org.onetwo.common.reflect;

import java.beans.PropertyDescriptor;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;

import org.onetwo.common.utils.CUtils;
import org.onetwo.common.utils.LangUtils;
import org.onetwo.common.utils.StringUtils;

public class BeanToMapConvertor {
	
	static public class DefaultPropertyAcceptor implements BiFunction {

		@Override
		public Boolean apply(PropertyDescriptor prop, Object val) {
			String clsName = prop.getPropertyType().getName();
			if(clsName.startsWith("groovy.lang.MetaClass") ){
				return false;
			}
			return val!=null;
		}
		
	}

	private String listOpener = "[";
	private String listCloser = "]";
	private String propertyAccesor = ".";
	private String prefix = "";
	private BiFunction propertyAcceptor = new DefaultPropertyAcceptor();
	private Function valueConvertor;
	private Function flatableObject;
	private Set> valueTypes = new HashSet>(LangUtils.getSimpleClass());
	private boolean freezed;

	public void freeze(){
		this.checkFreezed();
		this.freezed = true;
	}
	public void checkFreezed(){
		if(this.freezed){
			throw new UnsupportedOperationException("object has freezed!");
		}
	}
	
	public void setPropertyAccesor(String propertyAccesor) {
		this.checkFreezed();
		this.propertyAccesor = propertyAccesor;
	}
	public void setPrefix(String prefix) {
		this.checkFreezed();
		this.prefix = prefix;
	}
	public void setPropertyAcceptor(
			BiFunction propertyAcceptor) {
		this.checkFreezed();
		this.propertyAcceptor = propertyAcceptor;
	}
	public void setValueConvertor(Function valueConvertor) {
		this.checkFreezed();
		this.valueConvertor = valueConvertor;
	}
	public void setFlatableObject(Function flatableObject) {
		this.checkFreezed();
		this.flatableObject = flatableObject;
	}
	/***
	 * 简单反射对象的propertyName为key, propertyValue为value
	 * @param obj
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Map toMap(final Object obj){
//		return ReflectUtils.toMap(obj, propertyAcceptor, valueConvertor);
		if (obj == null)
			return Collections.emptyMap();
		
		if(obj.getClass().isArray())
			return CUtils.asMap((Object[])obj);
		
		if(obj instanceof Map)
			return (Map)obj;
		
		PropertyDescriptor[] props = ReflectUtils.desribProperties(obj.getClass());
		if (props == null || props.length == 0)
			return Collections.emptyMap();
		Map rsMap = new HashMap<>();
		Object val = null;
		for (PropertyDescriptor prop : props) {
			val = ReflectUtils.getProperty(obj, prop);
			if (propertyAcceptor==null || propertyAcceptor.apply(prop, val)){
				if(valueConvertor!=null)
					val = valueConvertor.apply(val);
				rsMap.put(prop.getName(), val);
			}
		}
		return rsMap;
	}
	
	/***
	 * 递归解释嵌套对象
	 */
	public Map toFlatMap(final Object obj){
		final Map params = new HashMap<>();
		toFlatMap(params, obj);
		return params;
	}
	
	public BeanToMapConvertor addValueType(Class clazz){
		this.checkFreezed();
		this.valueTypes.add(clazz);
		return this;
	}
	

	public boolean isMappableValue(Object value){
		if(value==null)
			return true;
		return valueTypes.contains(value.getClass()) || (flatableObject!=null && !flatableObject.apply(value));
//		return valueTypes.contains(value.getClass());
	}

	public void toFlatMap(final Map params, final Object obj){
		flatObject(prefix, obj, (k, v)->params.put(k, v));
	}
	
	@SuppressWarnings("unchecked")
	public  void flatObject(final String prefixName, final Object obj, ValuePutter valuePutter){
		if(isMappableValue(obj)){
			valuePutter.put(prefixName, obj);
		}else if(Map.class.isInstance(obj)){
			String mapPrefixName = prefixName;
			if(StringUtils.isNotBlank(prefixName)){
				mapPrefixName = prefixName+this.propertyAccesor;
			}
			for(Entry entry : ((Map)obj).entrySet()){
				if(isMappableValue(entry.getValue())){
					valuePutter.put(mapPrefixName+entry.getKey(), entry.getValue());
				}else{
					flatObject(mapPrefixName+entry.getKey(), entry.getValue(), valuePutter);
				}
			}
		}else if(LangUtils.isMultiple(obj)){
			List list = LangUtils.asList(obj);
			int index = 0;
			for(Object o : list){
				String listPrefixName = prefixName + this.listOpener+index+this.listCloser;
				if(isMappableValue(o)){
					valuePutter.put(listPrefixName, o);
				}else{
					flatObject(listPrefixName, o, valuePutter);
				}
				index++;
			}
		}else{
			/*if(flatableObject==null || !flatableObject.apply(obj)){
				valuePutter.put(prefixName, obj);
				return ;
			}*/
			ReflectUtils.listProperties(obj.getClass(), prop-> {
				Object val = ReflectUtils.getProperty(obj, prop);
				if (propertyAcceptor==null || propertyAcceptor.apply(prop, val)){
					if(valueConvertor!=null){
						val = valueConvertor.apply(val);
					}
					if(StringUtils.isBlank(prefixName)){
						flatObject(prop.getName(), val, valuePutter);
					}else{
						flatObject(prefixName+propertyAccesor+prop.getName(), val, valuePutter);
					}
				}
			});
		}
	}

	public static interface ValuePutter {
		void put(String key, Object value);
	}

	public static class BeanToMapBuilder {
		public static BeanToMapBuilder newBuilder(){
			return new BeanToMapBuilder();
		}
		private BeanToMapConvertor beanToFlatMap = new BeanToMapConvertor();


		public BeanToMapBuilder propertyAcceptor(BiFunction propertyAcceptor) {
			beanToFlatMap.setPropertyAcceptor(propertyAcceptor);
			return this;
		}

		public BeanToMapBuilder flatableObject(Function flatableObject) {
			beanToFlatMap.setFlatableObject(flatableObject);
			return this;
		}

		public BeanToMapBuilder valueConvertor(Function valueConvertor) {
			beanToFlatMap.setValueConvertor(valueConvertor);
			return this;
		}

		public BeanToMapBuilder prefix(String prefix) {
			beanToFlatMap.setPrefix(prefix);
			return this;
		}
		
		/*public Map toMap(Object obj){
			return beanToFlatMap.toMap(obj);
		}
		
		public Map toFlatMap(Object obj){
			return beanToFlatMap.toFlatMap(obj);
		}*/
		public BeanToMapConvertor build(){
			this.beanToFlatMap.freeze();
			return beanToFlatMap;
		}
	}
	
	
}