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

jodd.bean.BeanUtilUtil Maven / Gradle / Ivy

// Copyright (c) 2003-2014, Jodd Team (jodd.org). All Rights Reserved.

package jodd.bean;

import jodd.introspector.Getter;
import jodd.introspector.Introspector;
import jodd.introspector.Setter;
import jodd.typeconverter.TypeConverterManager;
import jodd.typeconverter.TypeConverterManagerBean;
import jodd.util.ReflectUtil;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.List;

/**
 * Various bean property utilities that makes writings of {@link BeanUtil} classes easy.
 */
class BeanUtilUtil {

	protected Introspector introspector = JoddBean.introspector;
	protected TypeConverterManagerBean typeConverterManager = TypeConverterManager.getDefaultTypeConverterManager();

	/**
	 * Sets {@link Introspector introspector} implementation.
	 */
	public void setIntrospector(Introspector introspector) {
		this.introspector = introspector;
	}

	/**
	 * Returns {@link Introspector introspector} implementation.
	 */
	public Introspector getIntrospector() {
		return introspector;
	}

	/**
	 * Sets {@link TypeConverterManagerBean type converter manager} implementation.
	 */
	public void setTypeConverterManager(TypeConverterManagerBean typeConverterManager) {
		this.typeConverterManager = typeConverterManager;
	}

	/**
	 * Returns {@link TypeConverterManagerBean type converter manager} implementation.
	 */
	public TypeConverterManagerBean getTypeConverterManager() {
		return typeConverterManager;
	}

	/**
	 * Converts object to destination type. Invoked before the
	 * value is set into destination. Throws TypeConversionException
	 * if conversion fails.
	 */
	@SuppressWarnings("unchecked")
	protected Object convertType(Object value, Class type) {
		return typeConverterManager.convertType(value, type);
	}

	/**
	 * Convert to collection.
	 */
	protected Object convertToCollection(Object value, Class destinationType, Class componentType) {
		return typeConverterManager.convertToCollection(value, destinationType, componentType);
	}

	
	// ---------------------------------------------------------------- accessors

	/**
	 * Invokes setter, but first converts type to match the setter type.
	 */
	protected Object invokeSetter(Setter setter, BeanProperty bp, Object value) {
		try {
			Class type = setter.getSetterRawType();

			if (ReflectUtil.isTypeOf(type, Collection.class)) {
				Class componentType = setter.getSetterRawComponentType();

				value = convertToCollection(value, type, componentType);
			} else {
				// no collections
				value = convertType(value, type);
			}

			setter.invokeSetter(bp.bean, value);
		} catch (Exception ex) {
			if (bp.silent) {
				return null;
			}
			throw new BeanException("Setter failed: " + setter, ex);
		}
		return value;
	}

	// ---------------------------------------------------------------- forced

	/**
	 * Returns the element of an array forced. If value is null, it will be instantiated.
	 * If not the last part of indexed bean property, array will be expanded to the index if necessary.
	 */
	protected Object arrayForcedGet(BeanProperty bp, Object array, int index) {
		Class componentType = array.getClass().getComponentType();
		if (bp.last == false) {
			array = ensureArraySize(bp, array, componentType, index);
		}
		Object value = Array.get(array, index);
		if (value == null) {
			try {
				value = ReflectUtil.newInstance(componentType);
			} catch (Exception ex) {
				if (bp.silent) {
					return null;
				}
				throw new BeanException("Invalid array element: " + bp.name + '[' + index + ']', bp, ex);
			}
			Array.set(array, index, value);
		}
		return value;
	}

	/**
	 * Sets the array element forced. If index is greater then arrays length, array will be expanded to the index.
	 * If speed is critical, it is better to allocate an array with proper size before using this method. 
	 */
	protected void arrayForcedSet(BeanProperty bp, Object array, int index, Object value) {
		Class componentType = array.getClass().getComponentType();
		array = ensureArraySize(bp, array, componentType, index);
		value = convertType(value, componentType);
		Array.set(array, index, value);
	}


	@SuppressWarnings({"SuspiciousSystemArraycopy"})
	protected Object ensureArraySize(BeanProperty bp, Object array, Class componentType, int index) {
		int len = Array.getLength(array);
		if (index >= len) {
			Object newArray = Array.newInstance(componentType, index + 1);
			System.arraycopy(array, 0, newArray, 0, len);

			Setter setter = bp.getSetter(true);
			if (setter == null) {
				// no point to check for bp.silent, throws NPE later
				throw new BeanException("Setter or field not found: " + bp.name, bp);
			}

			newArray = invokeSetter(setter, bp, newArray);

			array = newArray;
		}
		return array;
	}

	@SuppressWarnings({"unchecked"})
	protected void ensureListSize(List list, int size) {
		int len = list.size();
		while (size >= len) {
			list.add(null);
			len++;
		}
	}

	// ---------------------------------------------------------------- index

	/**
	 * Finds the very first next dot. Ignores dots between index brackets.
	 * Returns -1 when dot is not found.
	 */
	protected int indexOfDot(String name) {
		int ndx = 0;
		int len = name.length();

		boolean insideBracket = false;

		while (ndx < len) {
			char c = name.charAt(ndx);

			if (insideBracket) {
				if (c == ']') {
					insideBracket = false;
				}
			} else {
				if (c == '.') {
					return ndx;
				}
				if (c == '[') {
					insideBracket = true;
				}
			}
			ndx++;
		}
		return -1;
	}


	/**
	 * Extract index string from non-nested property name.
	 * If index is found, it is stripped from bean property name.
	 * If no index is found, it returns null.
	 */
	protected String extractIndex(BeanProperty bp) {
		bp.index = null;
		String name = bp.name;
		int lastNdx = name.length() - 1;
		if (lastNdx < 0) {
			return null;
		}
		if (name.charAt(lastNdx) == ']') {
			int leftBracketNdx = name.lastIndexOf('[');
			if (leftBracketNdx != -1) {
				bp.setName(name.substring(0, leftBracketNdx));
				bp.index = name.substring(leftBracketNdx + 1, lastNdx);
				return bp.index;
			}
		}
		return null;
	}

	protected int parseInt(String indexString, BeanProperty bp) {
		try {
			return Integer.parseInt(indexString);
		} catch (NumberFormatException nfex) {
			// no point to use bp.silent, as will throw exception
			throw new BeanException("Invalid index: " + indexString, bp, nfex);
		}
	}

	// ---------------------------------------------------------------- create property

	/**
	 * Creates new instance for current property name through its setter.
	 * It uses default constructor!
	 */
	protected Object createBeanProperty(BeanProperty bp) {
		Setter setter = bp.getSetter(true);
		if (setter == null) {
			return null;
		}

		Class type = setter.getSetterRawType();

		Object newInstance;
		try {
			newInstance = ReflectUtil.newInstance(type);
		} catch (Exception ex) {
			if (bp.silent) {
				return null;
			}
			throw new BeanException("Invalid property: " + bp.name, bp, ex);
		}

		newInstance = invokeSetter(setter, bp, newInstance);

		return newInstance;
	}

	// ---------------------------------------------------------------- generic and type

	/**
	 * Extracts generic component type of a property. Returns Object.class
	 * when property does not have component.
	 */
	protected Class extractGenericComponentType(Getter getter) {
		Class componentType = null;

		if (getter != null) {
			componentType = getter.getGetterRawComponentType();
		}

		if (componentType == null) {
			componentType = Object.class;
		}
		return componentType;
	}

	/**
	 * Converts Map index to key type. If conversion fails, original value will be returned.
	 */
	protected Object convertIndexToMapKey(Getter getter, Object index) {
		Class indexType = null;

		if (getter != null) {
			indexType = getter.getGetterRawKeyComponentType();
		}

		// check if set
		if (indexType == null) {
			indexType = Object.class;	// marker for no generic type
		}

		if (indexType == Object.class) {
			return index;
		}

		try {
			return convertType(index, indexType);
		} catch (Exception ignore) {
			return index;
		}
	}

	/**
	 * Extracts type of current property.
	 */
	protected Class extractType(BeanProperty bp) {
		Getter getter = bp.getGetter(bp.declared);
		if (getter != null) {
			if (bp.index != null) {
				Class type = getter.getGetterRawComponentType();
				return type == null ? Object.class : type;
			}
			return getter.getGetterRawType();
		}

		return null;	// this should not happens
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy