/* Classes.java


	Purpose: Utilities to handle Class
	Description:
	History:
	 2001/4/19, Tom M. Yeh: Created.


Copyright (C) 2001 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
	This program is distributed under LGPL Version 2.1 in the hope that
	it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.lang;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zkoss.math.BigDecimals;
import org.zkoss.math.BigIntegers;
import org.zkoss.mesg.MCommon;
import org.zkoss.mesg.Messages;
import org.zkoss.util.Cache;
import org.zkoss.util.FastReadCache;
import org.zkoss.util.IllegalSyntaxException;

/**
 * Utilities to handle java.lang.Class
 *
 * @author tomyeh
 */
public class Classes {
	private static final Logger log = LoggerFactory.getLogger(Classes.class);

	private static final Object NOT_FOUND = new Object();

	private static String _contextClassLoaderName = null;

	/**
	 * Instantiates a new instance of the specified class with
	 * the specified arguments and argument types.
	 *
	 * <p>Note only public constructors are searched.
	 *
	 * @param cls the class of the instance to create
	 * @param argTypes the argument types of the constructor to invoke
	 * @param args the arguments to initialize the instance
	 * @return the new instance
	 *
	 * @exception NoSuchMethodException if a matching method is not found
	 * @exception InstantiationException if the class that declares the
	 * underlying constructor represents an abstract class
	 * @exception InvocationTargetException if the underlying constructor
	 * throws an exception
	 * @see #newInstance(String, Class[], Object[])
	 */
	public static final
	Object newInstance(Class<?> cls, Class<?>[] argTypes, Object[] args)
	throws NoSuchMethodException, InstantiationException,
	InvocationTargetException, IllegalAccessException {
 		return cls.getConstructor(argTypes).newInstance(args);
	}
	/**
	 * Instantiates a new instance of the specified class with the
	 * specified argument.
	 *
	 * <p>It searches all constructors for the first one that matches
	 * the specified arguments.
	 * @since 3.0.1
	 */
	public static final
	Object newInstance(Class<?> cls, Object[] args)
	throws NoSuchMethodException, InstantiationException,
	InvocationTargetException, IllegalAccessException {
		if (args == null || args.length == 0)
			return cls.newInstance();

		final Constructor[] cxs = cls.getConstructors();
		Constructor cx = match(cxs, args, false);
		if (cx == null)
			cx = match(cxs, args, true);
		if (cx != null)
			return cx.newInstance(args);

		throw new NoSuchMethodException(cls.getName()+": no constructor for "+Objects.toString(args));
	}
	/**
	 * @param loosely whether to match Long with Integer and so on.
	 */
	private static
	Constructor match(Constructor[] cxs, Object[] args, boolean loosely) {
		for (int j = 0; j < cxs.length; ++j)
			if (matched(cxs[j].getParameterTypes(), args, loosely))
				return cxs[j];
		return null;
	}
	/**
	 * @param loosely whether to match Long with Integer and so on.
	 */
	private static
	Method match(Class<?> cls, String name, Object[] args, boolean loosely) {
		final Method[] ms = cls.getMethods();
		for (int j = 0; j < ms.length; ++j) {
			if (!ms[j].getName().equals(name)
			|| !matched(ms[j].getParameterTypes(), args, loosely))
				continue; //not found; next

			if (Modifier.isPublic(ms[j].getDeclaringClass().getModifiers()))
				return ms[j]; //found
			try {
				return getMethodInPublic(
					cls, ms[j].getName(), ms[j].getParameterTypes());
			} catch (NoSuchMethodException ex) { //not found; next
			}
		}
		return null;
	}
	private static boolean matched(Class[] types, Object[] args, boolean loosely) {
		if (types.length == args.length) {
			final Object[] argcvt = loosely ? new Object[args.length]: args;
			boolean cvted = false;
			for (int k = args.length;;) {
				if (--k < 0) {
					if (cvted)
						System.arraycopy(argcvt, 0, args, 0, args.length);
						//copy converted only if all matched
					return true;
				}

				final Object arg = argcvt[k] = args[k];
				final Class type = types[k];
				if (arg == null)
					if (type.isPrimitive()) break; //mismatch
					else continue; //matched

				if (type.isInstance(arg) || (type.isPrimitive()
				&& Primitives.toWrapper(type).isInstance(arg)))
					continue; //matched

				if (loosely) {
					argcvt[k] = looselyCast(type, arg);
					if (argcvt[k] != null) {
						cvted = true;
						continue; //matched
					}
				}
				break; //mismatch
			}
		}
		return false;
	}
	private static Object looselyCast(Class type, Object arg) {
		if (type == Integer.class || type == int.class) {
			if (arg instanceof Number)
				return ((Number) arg).intValue();
		} else if (type == Long.class || type == long.class) {
			if (arg instanceof Number)
				return ((Number) arg).longValue();
		} else if (type == Double.class || type == double.class) {
			if (arg instanceof Number)
				return ((Number) arg).doubleValue();
		} else if (type == Short.class || type == short.class) {
			if (arg instanceof Number)
				return ((Number) arg).shortValue();
		} else if (type == Float.class || type == float.class) {
			if (arg instanceof Number)
				return ((Number) arg).floatValue();
		} else if (type == Byte.class || type == byte.class) {
			if (arg instanceof Number)
				return ((Number) arg).byteValue();
		}
		return null; //not castable
	}

	/**
	 * Instantiates a new instance of the specified class name
	 * with the specified arguments.
	 *
	 * <p>It uses Class.forName to get the class.
	 *
	 * @param clsName the class name of the instance to create
	 * @param argTypes the argument types of the constructor to invoke
	 * @param args the arguments to initialize the instance
	 * @return the new instance
	 *
	 * @exception NoSuchMethodException if a matching method is not found
	 * @exception InstantiationException if the class that declares the
	 * underlying constructor represents an abstract class
	 * @exception InvocationTargetException if the underlying constructor
	 * throws an exception
	 * @exception ClassNotFoundException if the specified class name is not a class
	 * @see #newInstance(Class, Class[], Object[])
	 */
	public static final Object
	newInstance(String clsName, Class<?>[] argTypes, Object[] args)
	throws NoSuchMethodException, InstantiationException,
	InvocationTargetException, ClassNotFoundException, IllegalAccessException {
	 	return newInstance(Class.forName(clsName), argTypes, args);
	}
	/**
	 * Creates and initializes a new instance of the specified class name
	 * with the specified arguments, by use of {@link #forNameByThread}.
	 *
	 * <p>It uses {@link #forNameByThread} to get the class.
	 *
	 * @param clsName the class name of the instance to create
	 * @param argTypes the argument types of the constructor to invoke
	 * @param args the arguments to initialize the instance
	 * @return the new instance
	 *
	 * @exception NoSuchMethodException if a matching method is not found
	 * @exception InstantiationException if the class that declares the
	 * underlying constructor represents an abstract class
	 * @exception InvocationTargetException if the underlying constructor
	 * throws an exception
	 * @exception ClassNotFoundException if the specified class name is not a class
	 * @see #newInstance(Class, Class[], Object[])
	 */
	public static final Object
	newInstanceByThread(String clsName, Class<?>[] argTypes, Object[] args)
	throws NoSuchMethodException, InstantiationException,
	InvocationTargetException, ClassNotFoundException, IllegalAccessException {
	 	return newInstance(forNameByThread(clsName), argTypes, args);
	}
	/**
	 * Creates and initializes a new instance of the specified class name
	 * with default constructor, by use of {@link #forNameByThread}.
	 */
	public static final Object newInstanceByThread(String clsName)
	throws NoSuchMethodException, InstantiationException,
	InvocationTargetException, ClassNotFoundException, IllegalAccessException {
		return newInstance(forNameByThread(clsName), null, null);
	}
	/**
	 * Returns the Class object of the specified class name, using
	 * the current thread's context class loader and the class will be initialized by default.
	 * <p>It first tries Thread.currentThread().getContextClassLoader(),
	 * and then {@link Classes}'s class loader if not found.
	 *
	 * <p>In additions, it handles the primitive types, such as int and double.
	 *
	 * @param clsName fully qualified name of the desired class
	 * @return the Class object representing the desired class
	 * @exception ClassNotFoundException if the class cannot be located by the specified class loader
	 * @see #forNameByThread(String, boolean)
	 */
	public static final Class<?> forNameByThread(String clsName)
			throws ClassNotFoundException {
		return forNameByThread(clsName, true);
	}

	/**
	 * Returns the Class object of the specified class name, using
	 * the current thread's context class loader.
	 * <p>It first tries Thread.currentThread().getContextClassLoader(),
	 * and then {@link Classes}'s class loader if not found.
	 *
	 * <p>In additions, it handles the primitive types, such as int and double.
	 *
	 * @param clsName fully qualified name of the desired class
	 * @param initialize if {@code true} the class will be initialized.
	 * @return the Class object representing the desired class
	 * @exception ClassNotFoundException if the class cannot be located by the specified class loader
	 * @since 10.0.0
	 * @see #forNameByThread(String)
	 */
	public static final Class<?> forNameByThread(String clsName, boolean initialize)
			throws ClassNotFoundException {
		clsName = toInternalForm(clsName);
		final Class<?> cls = Primitives.toClass(clsName);
		if (cls != null)
			return cls;

		// ZK-3762: Use the default class loader first if the property is not ready
		ClassLoader cl = _contextClassLoaderName == null
				? Thread.currentThread().getContextClassLoader()
				: getContextClassLoaderForName(clsName);
		if (cl != null)
			try {
				return Class.forName(clsName, initialize, cl);
			} catch (ClassNotFoundException ex) { //ignore and try the other
			}
		return Class.forName(clsName);
	}

	/** Returns whether the specified class exists for the current thread's
	 * context class loader.
	 * @param clsnm the class name to test
	 * @since 3.0.7
	 */
	public static final boolean existsByThread(String clsnm) {
		try {
			forNameByThread(clsnm);
			return true;
		} catch (Throwable ex) {
			return false;
		}
	}

	/**
	 * Change class name to internal form (e.g. byte[] -&gt; [B]). If already in
	 * internal form, then just return it.
	 */
	public static final String toInternalForm(String clsName) {
		final int k = clsName.indexOf('[');
		if (k <= 0) { //not an array, or already in internal form
			return clsName;	//just return
		}

		//component class
		final String elm = clsName.substring(0, k).trim();
		if (elm.length() == 0)
			throw new IllegalArgumentException("Not a legal class name: \""+clsName+'"');

		//array depth
		boolean leftb = false;
		final String stub = clsName.substring(k);
		final StringBuffer sb = new StringBuffer(128);
		for (int j = 0; j < stub.length(); j++) {
			final char ch = stub.charAt(j);
			if (ch == '[') {
				if (leftb)
					throw new IllegalArgumentException("Not a legal class name: \""+clsName+'"');
				leftb = true;
				sb.append('[');
			} else if (ch == ']') {
				if (!leftb)
					throw new IllegalArgumentException("Not a legal class name: \""+clsName+'"');
				leftb = false;
			}
		}
		if (leftb)
			throw new IllegalArgumentException("Not a legal class name: \""+clsName+'"');

		final char code = Primitives.getNotation(elm);
		if (code != (char)0) {//primitive array
			sb.append(code);
		} else {//object array
			sb.append('L').append(elm).append(';');
		}
		return sb.toString();
	}

	/**
	 * Gets the topmost interface of the specified class or interface that
	 * implements or extends the specified interface.
	 * For example, if A extends B, and C implements A,
	 * then getTopInterface(C, B) returns A.
	 *
	 * <p>The interfaces implemented by the specified class is checked first,
	 * and then the subclass.
	 *
	 * @param cls the class or interface
	 * @param subIF the sub-interface
	 * @return the topmost interface extending subIF, or null if subIF
	 * is not implemented by cls
	 */
	public static Class<?> getTopmostInterface(Class<?> cls, Class<?> subIF) {
		if (cls.isInterface())
			return subIF.isAssignableFrom(cls) ? cls: null;

		while (cls != null) {
			final Class<?>[] ifs = cls.getInterfaces();
			for (int j = 0; j < ifs.length; ++j)
				if (subIF.isAssignableFrom(ifs[j]))
					return ifs[j];

			cls = cls.getSuperclass();
		}
		return null;
	}
	/** Returns all interfaces that are implemented by the specified class.
	 * <p>Unlike {@link Class#getInterfaces()}, it recursively searches
	 * for all derived classes.
	 */
	public static Class<?>[] getAllInterfaces(Class<?> cls) {
		final List<Class<?>> l = new LinkedList<>();
		while (cls != null) {
			final Class<?>[] ifs = cls.getInterfaces();
			Collections.addAll(l, ifs);

			cls = cls.getSuperclass();
		}
		final int sz = l.size();
		return l.toArray(new Class<?>[sz]);
	}		

	/**
	 * Tests whether a class contains the specified method.
	 * Only public methods are tested.
	 *
	 * @param cls the class to test
	 * @param name the method name
	 * @param paramTypes the list of parameter types
	 * @return true if it contains the method
	 */
	public static final boolean containsMethod
	(Class<?> cls, String name, Class<?>[] paramTypes) {
		try {
			cls.getMethod(name, paramTypes);
			return true;
		} catch (NoSuchMethodException ex) {//no found
			return false;
		}
	}

	/** Corrects a string to a valid Java name.
	 * Currently, it only removes '-' and capitalizes the succeeding
	 * character. Example, 'field-name' becomes 'fieldName'.
	 */
	public final static String correctFieldName(String name) {
		int j = name.indexOf('-');
		if (j < 0)
			return name; //nothing to change

		for (final var sb = new StringBuilder(name);;) {
			sb.deleteCharAt(j);
			if (sb.length() == j)
				return sb.toString();

			sb.setCharAt(j, Character.toUpperCase(sb.charAt(j)));

			j = sb.indexOf("-", j);
			if (j < 0)
				return sb.toString();
		}
	}

	/**
	 * Convert an attribute name, returned by toAttributeName, to
	 * a method name.
	 *
	 * <p>toMethodName("true", "is") =&gt; "isTrue"<br>
	 * toMethodName("true", "") =&gt; "true"
	 *
	 * @param attrName the attribute name
	 * @param prefix the prefix; one of is, get and set
	 * @return the method name
	 * @see #toAttributeName
	 */
	public static final String toMethodName(String attrName, String prefix) {
		if (prefix.isEmpty())
			return attrName;

		var sb = new StringBuilder(prefix);
		char[] buf = attrName.toCharArray();
		buf[0] = Character.toUpperCase(buf[0]);
		return sb.append(buf).toString();
	}

	/**
	 * Tests if a method name is an attribute, i.e., prefixing with is,
	 * get or set. Caller could then test if it is a setter or getter
	 * by charAt(0)=='s'.
	 *
	 * <p>Note 'set' is considered as an attribute, whose name is an
	 * empty string.
	 *
	 * @param methodName the method name to test
	 * @return true if it is setter or getter
	 */
	public static final boolean isAttribute(String methodName) {
		int len = methodName.length();
		if (len < 2)
			return false;

		int j;
		switch (methodName.charAt(0)) {
		case 's':
		case 'g':
			if (len<3 || methodName.charAt(1)!='e' || methodName.charAt(2)!='t')
				return false;
			j = 3;
			break;
		case 'i':
			if (methodName.charAt(1)!='s')
				return false;
			j = 2;
			break;
		default:
			return false;
		}
		return j==len || Character.isUpperCase(methodName.charAt(j));
	}

	/**
	 * Converts a method name to an attribute name by removing the prefix
	 * is, get or set, or null if it doesn't start with is, get or set.
	 *
	 * <p>The code is optimized for better performance.
	 *
	 * @param methodName the method name
	 * @return the attribute name; null if it is not an attribute name
	 * @see #toMethodName
	 */
	public static final String toAttributeName(String methodName) {
		int len = methodName.length();
		if (len < 2)
			return null;

		int j;
		switch (methodName.charAt(0)) {
		case 's':
		case 'g':
			if (len<3 || methodName.charAt(1)!='e' || methodName.charAt(2)!='t')
				return null;
			j = 3;
			break;
		case 'i':
			if (methodName.charAt(1)!='s')
				return null;
			j = 2;
			break;
		default:
			return null;
		}
		if (j==len || Character.isUpperCase(methodName.charAt(j))) {
			char[] buf = new char[len - j];
			if (buf.length>0) {
				methodName.getChars(j, len, buf, 0);
				buf[0] = Character.toLowerCase(buf[0]);
			}
			return new String(buf);
		}
		return null;
	}

	//--Support Class--
	/**The method info class used for {@link #parseMethod(String signature)}.
	 * This info describe the method return type, method name and two collections for
	 * arguments type and arguments name;
	 */
	public static class MethodInfo {
		/** The return type (class name), or null if no specified. */
		public String returnType;
		public String method;
		public String[] argTypes;
		public String[] argNames;
		public String throwsEx;
		
		//constructor
		protected MethodInfo(String r, String m, String[] argTs, String[] argNs, String tEx) {
			returnType = r;
			method = m;
			argTypes = argTs;
			argNames = argNs;
			throwsEx = tEx;
		}
	}
	/**
	 * Gets the method information from a signature. 
	 * It returns a method info with the return type, method name and two collections 
	 * of arguments type and arguments name.
	 *
	 * @param signature the method signature.
	 * @return MethodInfo The method information including return type, method name
	 *			and two collections for argument type and arguments name.
	 */
	public static final MethodInfo parseMethod(String signature) 
	throws IllegalSyntaxException {
		int len = signature.length();
		int j = Strings.skipWhitespaces(signature, 0);
		int k = Strings.anyOf(signature, "( \t\n\r", j);
		k = Strings.skipWhitespaces(signature, k);
		if (k >= len)
			throw new IllegalSyntaxException(signature);
		
		String returnType = null;
		char cc = signature.charAt(k);
		if (cc != '(') {	
			//skip the return type
			returnType = signature.substring(j, k).trim();
			//
			j = k;
			k = signature.indexOf('(', j + 1);
			if (k < 0)
				throw new IllegalSyntaxException(signature);	
		}
		String method = signature.substring(j, k).trim();
		
		Collection<String> argTypes = new LinkedList<>();
		Collection<String> argNames = new LinkedList<>();
		do {
			j = Strings.skipWhitespaces(signature, k + 1);
			if (signature.charAt(j) == ')') break;
			k = Strings.anyOf(signature, ",) \t\n\r", j);
			k = Strings.skipWhitespaces(signature, k);
			if (k >= len)
				throw new IllegalSyntaxException(signature);
			argTypes.add(signature.substring(j, k).trim());

			cc = signature.charAt(k);
			if (cc != ',' && cc != ')') { //parameter name found
				k = Strings.anyOf(signature, ",) \t\n\r", j = k);
				k = Strings.skipWhitespaces(signature, k);
				argNames.add(signature.substring(j, k).trim());

				k = Strings.anyOf(signature, ",)", k);
				if (k >= len)
					throw new IllegalSyntaxException(signature);
			} else {
				argNames.add(""); //no name specified
			}
		} while (signature.charAt(k) == ',');

		assert argTypes.size() == argNames.size();

		//process throws ...
		String strThrows = "throws";
		String tEx = null;
		j = signature.indexOf(strThrows, k);
		if (j >= k && j < len) { //got throws
			k = signature.indexOf(';', j);
			if (k >= 0) 
				tEx = signature.substring(j + strThrows.length(), k).trim();
			else
				tEx = signature.substring(j + strThrows.length(), len).trim();
		}
	
		return new MethodInfo(returnType, method, 
					argTypes.toArray(new String[argTypes.size()]), 
					argNames.toArray(new String[argNames.size()]), 
					tEx);
	}
	
	/**
	 * Gets the method based on the signature with a class resolver.
	 * It also returns the parameter names to the params list.
	 *
	 * <p>Like {@link #getMethodInPublic(Class, String, Class[])}, it returns
	 * only public method in a public class/interface.
	 *
	 * <p>For example, "find(java.lang.String name)" will return
	 * the method with one String-typed argument and params will hold "name".
	 * The return type is optional (actually ignored).
	 *
	 * <p>If params is null, the parameter names are not returned and
	 * the signature could be simplified as "find(java.lang.String)".
	 *
	 * <p>A cache mechanism is implemented, so you don't need to cache it
	 * again in the caller.
	 *
	 * @param cls the class to look
	 * @param signature the method signature; the return type is optional.<br/>
	 * Notice that the argument's type must be a full-qualified class name,
	 * unless its package is java.lang or it can be resolved by <code>resolver</code>.
	 * @param params the collection to hold the parameter names returned;
	 * null means no parameter names to return
	 * @param resolver the class resolver used to resolve the class specified
	 * in the signature. Ignored if null.
	 * @since 6.0.0
	 */
	public static final Method
	getMethodBySignature(Class<?> cls, String signature, Collection<String> params,
	ClassResolver resolver)
	throws NoSuchMethodException, ClassNotFoundException {
		MethodInfo mi = parseMethod(signature);

		LinkedList<Class<?>> argTypes = new LinkedList<Class<?>>();
		for (int i = 0; i < mi.argTypes.length; i++) {
			final String clsnm = mi.argTypes[i];
			argTypes.add(getClassOfSignature(resolver, clsnm));
			if (params != null)
				params.add(mi.argNames[i]);	//param name found
		}
		
		return getMethodInPublic(cls, mi.method,
			argTypes.toArray(new Class<?>[argTypes.size()]));
	}
	/**
	 * Gets the method based on the signature. It also returns the parameter
	 * names to the params list.
	 *
	 * <p>Like {@link #getMethodInPublic(Class, String, Class[])}, it returns
	 * only public method in a public class/interface.
	 *
	 * <p>For example, "find(java.lang.String name)" will return
	 * the method with one String-typed argument and params will hold "name".
	 * The return type is optional (actually ignored).
	 *
	 * <p>If params is null, the parameter names are not returned and
	 * the signature could be simplified as "find(java.lang.String)".
	 *
	 * <p>A cache mechanism is implemented, so you don't need to cache it
	 * again in the caller.
	 *
	 * @param cls the class to look
	 * @param signature the method signature; the return type is optional<br/>
	 * Notice that the argument's type must be a full-qualified class name,
	 * unless its package is java.lang.
	 * @param params the collection to hold the parameter names returned;
	 * null means no parameter names to return
	 */
	public static final Method
	getMethodBySignature(Class<?> cls, String signature, Collection<String> params)
	throws NoSuchMethodException, ClassNotFoundException {
		return getMethodBySignature(cls, signature, params, null);
	}
	/** Resolves a class for the method signature.
	 * This method will try java.lang.X if X is not found.
	 */
	private static final
	Class getClassOfSignature(ClassResolver resolver, String clsnm)
	throws ClassNotFoundException {
		try {
			return resolver != null ?
				resolver.resolveClass(clsnm): forNameByThread(clsnm);
		} catch (ClassNotFoundException ex) {
			if (clsnm == null || clsnm.indexOf('.') >= 0)
				throw ex;
			try {
				return forNameByThread("java.lang." + clsnm);
			} catch (Throwable t) {
				throw ex;
			}
		}
	}

	/**
	 * Gets the method that is declared in a public class/interface.
	 *
	 * <p>Class.getMethod returns a public method but the class itself
	 * might not be public. However, in many cases, that class
	 * also implements a public interface or class.
	 *
	 * <p>This method will search all its public classes to look for
	 * the method that is 'real' public.
	 *
	 * <p>NoSuchMethodException is thrown if no public 
	 * class/interface is found to have the method.
	 */
	public static final Method
	getMethodInPublic(Class<?> cls, String name, Class<?>[] argTypes)
	throws NoSuchMethodException {
		final Method m = cls.getMethod(name, argTypes);
		if (Modifier.isPublic(m.getDeclaringClass().getModifiers()))
			return m;

		final Class<?>[] clses = cls.getInterfaces();
		for (int j = 0; j< clses.length; ++j)
			try {
				return getMethodInPublic(clses[j], name, argTypes);
			} catch (NoSuchMethodException ex) { //ignore it
			}

		final Class<?> basecls = cls.getSuperclass();
		if (basecls != null)
			try {
				return getMethodInPublic(basecls, name, argTypes);
			} catch (NoSuchMethodException ex) { //ignore it
			}

		throw newNoSuchMethodException(cls, name, argTypes);
	}
	private static NoSuchMethodException newNoSuchMethodException(Class cls,
	String name, Object[] args) {
		return new NoSuchMethodException(cls.getName()+": no method called "+name+" for "+Objects.toString(args));
	}

	/** Gets one of the close method by specifying the arguments, rather
	 * than the argument types. It actually calls {@link #getCloseMethod}.
	 */
	public static final
	Method getMethodByObject(Class<?> cls, String name, Object[] args)
	throws NoSuchMethodException {
		if (args == null)
			return getMethodInPublic(cls, name, null);

		Method mtd = match(cls, name, args, false);
		if (mtd == null) {
			mtd = match(cls, name, args, true);
			if (mtd == null)
				throw newNoSuchMethodException(cls, name, args);
		}
		return mtd;
	}
	/**
	 * Gets one of the close methods -- a close method is a method
	 * with the same name and the compatible argument type.
	 * By compatible we mean the real method's argument type is
	 * the same as or a superclass of the specified one.
	 *
	 * <p>It might not be the best fit one, unless there is a method
	 * whose argument types are exactly argTypes.
	 *
	 * <p>You might specify the exact number in argTypes. If any of them is
	 * unknown, use null. Example, in the following, the first argument could
	 * be anything and the second is anything deriving from MyClass:<br>
	 * <code>new Class[] {null, MyClass.class}</code>
	 *
	 * <p>Note: if an argument accepts int, then Integer is considered
	 * as compatible (unlike Class.getMethod). So are long, byte...
	 *
	 * <p>A cache mechanism is implemented, so you don't need to cache it
	 * again in the caller.
	 *
	 * @param cls the class to locate the method
	 * @param name the method name
	 * @param argTypes an array of the argument classes;
	 * null to denote no argument at all (i.e., exact match).
	 * Any argTypes[i] could be null to denote any class.
	 * @return the method
	 * @exception NoSuchMethodException if the method is not found
	 */
	public static final Method
	getCloseMethod(Class<?> cls, String name, Class<?>[] argTypes)
	throws NoSuchMethodException {
		if (argTypes == null || argTypes.length == 0)
			return getMethodInPublic(cls, name, null);

		final AOInfo aoi = new AOInfo(cls, name, argTypes, 0);
		Object m = _closms.get(aoi);
		if( m == NOT_FOUND)
			throw newNoSuchMethodException(cls, name, argTypes);
		
		if (m != null) 
			return (Method) m;
		
		try{
			m = myGetCloseMethod(cls, name, argTypes, false);
		}catch(NoSuchMethodException ex){
			_closms.put(aoi, NOT_FOUND);
			throw ex;
		}
		_closms.put(aoi, m);
		return (Method) m;
	}
	/**
	 * Like {@link #getCloseMethod} to get a 'close' method, but
	 * it look for subclass of the argument (instead of superclass).
	 * In other words, it looks for the method whose argument type is
	 * the same as or a subclass of the specified one.
	 */
	public static final Method
	getCloseMethodBySubclass(Class<?> cls, String name, Class<?>[] argTypes)
	throws NoSuchMethodException {
		if (argTypes == null || argTypes.length == 0)
			return getMethodInPublic(cls, name, null);

		final AOInfo aoi = new AOInfo(cls, name, argTypes, B_BY_SUBCLASS);
		Object m = _closms.get(aoi);
		if( m == NOT_FOUND)
			throw newNoSuchMethodException(cls, name, argTypes);
		
		if (m != null) 
			return (Method) m;

		try{
			m = myGetCloseMethod(cls, name, argTypes, true);
		}catch(NoSuchMethodException ex){
			_closms.put(aoi, NOT_FOUND);
			throw ex;
		}
		_closms.put(aoi, m);
		return (Method) m;
	}
	private static Cache<AOInfo, Object> _closms = new FastReadCache<AOInfo, Object>(
		Library.getIntProperty("org.zkoss.lang.Classes.methods.cache.maxSize", 600),
		4*60*60*1000);
	private static final
	Method myGetCloseMethod(final Class<?> cls, final String name,
	final Class<?>[] argTypes, final boolean bySubclass)
	throws NoSuchMethodException {
//		assert argTypes != null: "Caller shall handle null";
		for (int j = 0;; ++j) {
			if (j == argTypes.length) {//all argTypes[j] non-null
				try {
					return getMethodInPublic(cls, name, argTypes);
				} catch (NoSuchMethodException ex) { //ignore it
					break;
				}
			}
			if (argTypes[j] == null) //special handling required
				break;
		}

		final Method [] ms = cls.getMethods();
		for (int j = 0; j < ms.length; ++j) {
			if (!ms[j].getName().equals(name))
				continue;

			final Class<?>[] mTypes = ms[j].getParameterTypes();
			if (mTypes.length != argTypes.length)
				continue; //not matched

			final boolean bPublic =
				Modifier.isPublic(ms[j].getDeclaringClass().getModifiers());
			for (int k = 0;; ++k) {
				if (k == argTypes.length) { //all matched
					if (bPublic)
						return ms[j];
					try {
						return getMethodInPublic(
							cls, ms[j].getName(), ms[j].getParameterTypes());
					} catch (NoSuchMethodException ex) {
					}
					break;//not match; look for next
				}

				final Class<?> argType = argTypes[k], mType = mTypes[k];
				if (argType == null
				|| (!bySubclass && mType.isAssignableFrom(argType))
				|| (bySubclass && argType.isAssignableFrom(mType)))
					continue; //match

				final Class<?> c = Primitives.toPrimitive(argType);
				if (c == null || !c.equals(mType))
					break; //not match
			}
		}
		throw newNoSuchMethodException(cls, name, argTypes);
	}

	/** Returns all close methods that match the specified condition, or
	 * a zero-length array if none is found.
	 * <p>Unlike {@link #getCloseMethod}, we don't cache the searched result,
	 * and it won't throw any exception.
	 */
	public static final
	Method[] getCloseMethods(Class<?> cls, String name, Class<?>[] argTypes) {
		if (argTypes == null || argTypes.length == 0) {
			try {
				return new Method[] {getMethodInPublic(cls, name, null)};
			} catch (NoSuchMethodException ex) {
				return new Method[0];
			}
		}
		return myGetCloseMethods(cls, name, argTypes, false);
	}
	/**
	 * Like {@link #getCloseMethods} to get all 'close' methods, but
	 * it look for subclass of the argument (instead of superclass).
	 * In other words, it looks for the method whose argument type is
	 * the same as or a subclass of the specified one.
	 */
	public static final
	Method[] getCloseMethodsBySubclass(Class<?> cls, String name, Class<?>[] argTypes) {
		if (argTypes == null || argTypes.length == 0)
			return getCloseMethods(cls, name, null);
		return myGetCloseMethods(cls, name, argTypes, true);
	}
	private static final Method[]
	myGetCloseMethods(final Class<?> cls, final String name,
	final Class<?>[] argTypes, final boolean bySubclass) {
//		assert argTypes != null: "Caller shall handle null";
		final List<Method> mtds = new LinkedList<Method>();
		final Method [] ms = cls.getMethods();
		for (int j = 0; j < ms.length; ++j) {
			if (!ms[j].getName().equals(name))
				continue;

			final Class<?>[] mTypes = ms[j].getParameterTypes();
			if (mTypes.length != argTypes.length)
				continue; //not matched

			final boolean bPublic =
				Modifier.isPublic(ms[j].getDeclaringClass().getModifiers());
			for (int k = 0;; ++k) {
				if (k == argTypes.length) { //all matched
					if (bPublic) {
						mtds.add(ms[j]);
					} else {
						try {
							mtds.add(getMethodInPublic(
							cls, ms[j].getName(), ms[j].getParameterTypes()));
						} catch (NoSuchMethodException ex) { //ignore; not add
						}
					}
					break; //found; next method
				}

				final Class<?> argType = argTypes[k], mType = mTypes[k];
				if (argType == null
				|| (!bySubclass && mType.isAssignableFrom(argType))
				|| (bySubclass && argType.isAssignableFrom(mType)))
					continue; //match one argument

				final Class<?> c = Primitives.toPrimitive(argType);
				if (c == null || !c.equals(mType))
					break; //not match; next method
			}
		}
		return mtds.toArray(new Method[mtds.size()]);
	}

	/**
	 * Search the get method; not imply B_METHODONLY.
	 */
	public static final int B_GET=0; //must be 0
	/**
	 * Search the set method; not imply B_METHODONLY.
	 */
	public static final int B_SET=1; //must be 1
	/**
	 * Only search for public methods or fields.
	 */
	public static final int B_PUBLIC_ONLY=0x0002;
	/**
	 * Only search for methods; excluding fields.
	 */
	public static final int B_METHOD_ONLY=0x0004;

	/** Used by {@link #getCloseMethodBySubclass} to distinguish
	 * {@link #getCloseMethod}.
	 */
	private static final int B_BY_SUBCLASS = 0x1000;

	/**
	 * Gets the specified accessible object, either a method or a field, by
	 * searching the specified name.
	 *
	 * <p>The search sequence is: (assume field name is body)&gt;<br>
	 * getBody(...)<br>
	 * isBody(...)<br>
	 * body(...)<br>
	 * body
	 *
	 * <p>If B_SET is specified, setBody(...) is searched instead of
	 * getBody(...) and isBody(...). The field is searched only if
	 * argsType.length is 0 or 1.
	 *
	 * <p>Note: it uses {@link #getCloseMethod} to get the method.
	 *
	 * <p>A cache mechanism is implemented, so you don't need to cache it
	 * again in the caller.
	 *
	 * @param cls the class to find
	 * @param name the name of the accessible object
	 * @param argTypes the parameter type of the method to find
	 * @param flags a combination of B_xxx or zero
	 * @return the accessible object; either Field or Method
	 * @exception NoSuchMethodException if neither the set method of
	 *   specified field nor the field itself not found
	 * @exception SecurityException if access to the information is denied
	 */
	public static final AccessibleObject
	getAccessibleObject(Class<?> cls, String name, Class<?>[] argTypes, int flags)
	throws NoSuchMethodException {
		final AOInfo aoi = new AOInfo(cls, name, argTypes, flags);
		AccessibleObject ao = _acsos.get(aoi);
		if (ao != null)
			return ao;

		ao = myGetAcsObj(cls, name, argTypes, flags);
		_acsos.put(aoi, ao);
		return ao;
	}
	private static Cache<AOInfo, AccessibleObject> _acsos = new FastReadCache<AOInfo, AccessibleObject>(
		Library.getIntProperty("org.zkoss.lang.Classes.methods.cache.maxSize", 600),
		4*60*60*1000);
	private static final AccessibleObject
	myGetAcsObj(Class<?> cls, String name, Class<?>[] argTypes, int flags)
	throws NoSuchMethodException {
		//try public set/get
		final String decoratedName =
			toMethodName(name, (flags&B_SET) != 0 ? "set": "get");
		try {
			return getCloseMethod(cls, decoratedName, argTypes);
		} catch (NoSuchMethodException ex) { //ignore
		}

		//try public is
		String isMethodName = null;
		if ((flags&B_SET) == 0)
			try {
				isMethodName = toMethodName(name, "is");
				return getCloseMethod(cls, isMethodName, argTypes);
			} catch (NoSuchMethodException ex) { //ignore
			}

		//try public same
		try {
			return getCloseMethod(cls, name, argTypes);
		} catch (NoSuchMethodException ex) {
			if ((flags & (B_PUBLIC_ONLY|B_METHOD_ONLY))
					  ==(B_PUBLIC_ONLY|B_METHOD_ONLY))
				throw ex;
		}

		if ((flags & B_PUBLIC_ONLY) == 0) {
			//try any set/get
			try {
				return getAnyMethod(cls, decoratedName, argTypes);
			} catch (NoSuchMethodException ex) { //ignore
			}

			//try any is
			if ((flags&B_SET) == 0)
				try {
					return getAnyMethod(cls, isMethodName, argTypes);
				} catch (NoSuchMethodException ex) { //ignore
				}

			//try any same
			try {
				return getAnyMethod(cls, name, argTypes);
			} catch (NoSuchMethodException ex) {
				if ((flags & B_METHOD_ONLY) != 0)
					throw ex;
			}
		}

		if (argTypes != null && argTypes.length > 1)
			throw newNoSuchMethodException(cls, name, argTypes);

		try {
			//try public field
			try {
				return cls.getField(name);
			} catch (NoSuchFieldException ex) { //ignore
				if ((flags & B_PUBLIC_ONLY) != 0)
					throw ex;
			}

			//try any field
			return getAnyField(cls, name);
		} catch (NoSuchFieldException ex) { //ignore
			throw newNoSuchMethodException(cls, name, argTypes);
		}
	}
	/** The information of the access object. */
	private static class AOInfo {
		private Class<?> cls;
		private String name;
		private Class<?>[] argTypes;
		private int flags;
		private AOInfo(Class<?> cls, String name, Class<?>[] argTypes, int flags) {
			this.cls = cls;
			this.name = name;
			this.argTypes = argTypes;
			this.flags = flags;
		}
		public int hashCode() {
			return cls.hashCode() + name.hashCode() + flags;
		}
		public boolean equals(Object o) {
			if (this == o) return true;
			if (!(o instanceof AOInfo))
				return false;

			AOInfo aoi = (AOInfo)o;
			int len =  argTypes != null ? argTypes.length: 0;
			int len2 = aoi.argTypes != null ? aoi.argTypes.length: 0;
			if (len != len2)
				return false;

			if (flags != aoi.flags || !cls.equals(aoi.cls)
			|| !name.equals(aoi.name))
				return false;

			for (int j = 0; j < len; ++j)
				if (!Objects.equals(argTypes[j], aoi.argTypes[j]))
					return false;
			return true;
		}
	}

	/**
	 * Gets the specified method by searching all methods including
	 * <i>any</i> access control and any base class.
	 * Note: you rarely need to call this method. In most cases,
	 * Class.getMethod, {@link #getCloseMethod}, and
	 * {@link #getMethodInPublic} are what you need.
	 *
	 * <p>The search sequence is: this class's methods, and then
	 * the superclass's methods.
	 *
	 * <p>Note: public methods don't be treated different. If the caller
	 * wants to search public methods first, it has to call Class.getMethod
	 * first.
	 *
	 * @param cls the class to search
	 * @param name the method name
	 * @param argTypes the parameter array of types
	 * @return the Method object
	 * @exception NoSuchMethodException if a matching method is not found.
	 * @exception SecurityException if access to the information is denied.
	 * @see #getAccessibleObject(Class, String, Class[], int)
	 * @see #getAnyField(Class, String)
	 */
	public static final Method
	getAnyMethod(Class<?> cls, String name, Class<?>[] argTypes)
	throws NoSuchMethodException {
		try {
			return cls.getDeclaredMethod(name, argTypes);
		} catch (NoSuchMethodException ex) {
			final Class<?>[] clses = cls.getInterfaces();
			for (int j = 0; j< clses.length; ++j)
				try {
					return getAnyMethod(clses[j], name, argTypes);
				} catch (NoSuchMethodException e2) { //ignore it
				}

			cls = cls.getSuperclass();
			if (cls == null)
				throw ex;
			return getAnyMethod(cls, name, argTypes);
		}
	}

	/**
	 * Gets the specified field by searching all fields including
	 * any access control and any base class.
	 * The search sequence is: this class's fields, and then
	 * the superclass's fields.
	 *
	 * <p>Note: public fields don't be treated different. If the caller
	 * wants to search public fields first, it has to call Class.getField
	 * first.
	 *
	 * @param cls the class to search
	 * @param name the field name
	 * @return the Field object
	 * @exception NoSuchFieldException if a matching field is not found.
	 * @exception SecurityException if access to the information is denied.
	 * @see #getAccessibleObject(Class, String, Class[], int)
	 * @see #getAnyMethod(Class, String, Class[])
	 */
	public static final Field getAnyField(Class<?> cls, String name)
	throws NoSuchFieldException {
		for (;;) {
			try {
				return cls.getDeclaredField(name);
			} catch (NoSuchFieldException ex) {
				cls = cls.getSuperclass();
				if (cls == null)
					throw ex;
			}
		}
	}

	/**
	 * Searches thru each element of the specified array of classes, and
	 * returns classes that are super-classes (or equal) of
	 * the specified class.
	 *
	 * @param cls the specified class; null is not allowed
	 * @param clsToCheck the class array to check; null is acceptable
	 * @return a subset of clsToCheck that are super-class of cls;
	 * null if no one qualified
	 */
	public static final Class<?>[] getSuperClasses(Class<?> cls, Class<?>[] clsToCheck) {
		if (clsToCheck!=null) {
			int[] hits = new int[clsToCheck.length];
			int no = 0;
			for (int j=0; j<clsToCheck.length; ++j)
				if (clsToCheck[j].isAssignableFrom(cls))
					hits[no++] = j;

			if (no != clsToCheck.length) {
				if (no == 0)
					return null;
				Class<?>[] exc = new Class[no];
				for (int j=0; j<no; ++j)
					exc[j] = clsToCheck[hits[j]];
				return exc;
			}
		}
		return clsToCheck;
	}

	/**
	 * Check whether the specified class is a primitive or a primitive wrapper.
	 */
	public static final boolean isPrimitiveWrapper(Class<?> cls) {
		return Objects.equals(cls.getPackage(), Boolean.class.getPackage())
			&& (cls.equals(Boolean.class) || cls.equals(Byte.class)
				|| cls.equals(Character.class) || cls.equals(Double.class)
				|| cls.equals(Float.class) || cls.equals(Integer.class)
				|| cls.equals(Long.class) || cls.equals(Short.class));
	}
	/** Checks whether the specified class is a numeric class.
	 *
	 * @param extend whether to consider Date, char, boolean, Character
	 * and Boolean as a numeric object.
	 */
	public static final boolean isNumeric(Class<?> cls, boolean extend) {
		if (cls.isPrimitive())
			return extend ||
				(!cls.equals(char.class) && !cls.equals(boolean.class));

		if (Number.class.isAssignableFrom(cls))
			return true;

		return extend &&
			(cls.equals(Date.class) || cls.equals(Boolean.class)
			|| cls.equals(Character.class));
	}

	/** Converts an object to the specified class.
	 * It is the same as coerce(cls, val, true).
	 *
	 * @param val the value.
	 * @exception ClassCastException if failed to convert
	 * @see #coerce(Class, Object, boolean)
	 */
	public static Object coerce(Class<?> cls, Object val)
	throws ClassCastException {
		if (cls.isInstance(val))
			return val;

		if (String.class == cls) {
			return Objects.toString(val);
		} else if (BigDecimal.class == cls) {
			if (val == null) {
				return null;
			} else if (val instanceof Double) {
				// B65-ZK-1944: Use String constructor to get the predictable value
				return new BigDecimal(Double.toString((Double)val));
			} else if (val instanceof Float) {
				// B65-ZK-1944: Use  String constructor to get the predictable value
				return new BigDecimal(Float.toString((Float)val));
			} else if (val instanceof BigInteger) {
				return new BigDecimal((BigInteger)val);
			} else if (val instanceof Number) {
				return BigDecimals.toBigDecimal(((Number)val).intValue());
			} else if (val instanceof String) {
				return new BigDecimal((String)val);
			} else if (val instanceof Date) {
				return new BigDecimal(((Date)val).getTime());
			}
		} else if (Integer.class == cls || int.class == cls) {
			if (val == null) {
				return Integer.class == cls ? null: Objects.ZERO_INTEGER;
			} else if (val instanceof Integer) { //int.class
				return val;
			} else if (val instanceof Number) {
				return ((Number) val).intValue();
			} else if (val instanceof String) {
				return Integer.valueOf((String) val);
			}
		} else if (Boolean.class == cls || boolean.class == cls) {
			if (val == null) {
				return Boolean.class == cls ? null: Boolean.FALSE;
			} else if (val instanceof Boolean) { //boolean.class
				return val;
			} else if (val instanceof String) {
				return Boolean.valueOf((String)val);
			} else if (val instanceof BigDecimal) {
				return ((BigDecimal) val).signum() != 0;
			} else if (val instanceof BigInteger) {
				return ((BigInteger) val).signum() != 0;
			} else if (val instanceof Number) {
				return ((Number) val).intValue() != 0;
			} else {
				return Boolean.TRUE; //non-null is true
			}
		} else if (Short.class == cls || short.class == cls) {
			if (val == null) {
				return Short.class == cls ? null: Objects.ZERO_SHORT;
			} else if (val instanceof Short) { //short.class
				return val;
			} else if (val instanceof Number) {
				return ((Number) val).shortValue();
			} else if (val instanceof String) {
				return Short.valueOf((String) val);
			}
		} else if (Long.class == cls || long.class == cls) {
			if (val == null) {
				return Long.class == cls ? null: Objects.ZERO_LONG;
			} else if (val instanceof Long) { //long.class
				return val;
			} else if (val instanceof Number) {
				return ((Number) val).longValue();
			} else if (val instanceof String) {
				return Long.valueOf((String) val);
			} else if (val instanceof Date) {
				return ((Date) val).getTime();
			}
		} else if (Double.class == cls || double.class == cls) {
			if (val == null) {
				return Double.class == cls ? null: Objects.ZERO_DOUBLE;
			} else if (val instanceof Double) { //double.class
				return val;
			} else if (val instanceof Number) {
				return ((Number) val).doubleValue();
			} else if (val instanceof String) {
				return Double.valueOf((String)val);
			} else if (val instanceof Date) {
				return ((Date) val).getTime();
			}
		} else if (BigInteger.class == cls) {
			if (val == null) {
				return null;
			} else if (val instanceof Integer) {
				return BigIntegers.toBigInteger((Integer)val);
			} else if (val instanceof Short) {
				return BigIntegers.toBigInteger((Short)val);
			} else if (val instanceof Byte) {
				return BigIntegers.toBigInteger((Byte)val);
			} else if (val instanceof Number) {
				return BigIntegers.toBigInteger(((Number)val).longValue());
			} else if (val instanceof String) {
				return new BigInteger((String)val);
			} else if (val instanceof Date) {
				return BigIntegers.toBigInteger(((Date)val).getTime());
			}
		} else if (Float.class == cls || float.class == cls) {
			if (val == null) {
				return Float.class == cls ? null: Objects.ZERO_FLOAT;
			} else if (val instanceof Float) { //float.class
				return val;
			} else if (val instanceof Number) {
				return new Float(((Number)val).floatValue());
			} else if (val instanceof String) {
				return new Float((String)val);
			} else if (val instanceof Date) {
				return new Float(((Date)val).getTime());
			}
		} else if (Byte.class == cls || byte.class == cls) {
			if (val == null) {
				return Byte.class == cls ? null: Objects.ZERO_BYTE;
			} else if (val instanceof Byte) { //byte.class
				return val;
			} else if (val instanceof Number) {
				return new Byte(((Number)val).byteValue());
			} else if (val instanceof String) {
				return new Byte((String)val);
			}
		} else if (Character.class == cls || char.class == cls) {
			if (val == null) {
				return Character.class == cls ? null: Objects.NULL_CHARACTER;
			} else if (val instanceof Character) { //character.class
				return val;
			} else if (val instanceof Number) {
				return new Character((char)((Number)val).shortValue());
			} else if (val instanceof String) {
				final String s = (String)val;
				return s.length() > 0 ? new Character(s.charAt(0)): Objects.NULL_CHARACTER;
			}
		} else if (Date.class == cls) {
			if (val == null) {
				return null;
			} else if (val instanceof Number) {
				return new Date(((Number)val).longValue());
			}
		} else if (Number.class == cls) {
			if (val == null) {
				return null;
			} else if (val instanceof String) {
				return new BigDecimal((String)val);
			} else if (val instanceof Date) {
				return new BigDecimal(((Date)val).getTime());
			}
		} else {
			if (val == null) {
				return null;
			} else {
				try {
					return newInstance(cls, new Object[] {val});
				} catch (Exception ex) {
					final ClassCastException t =
						new ClassCastException(
							Messages.get(MCommon.CLASS_NOT_COMPATIABLE,
							new Object[] {val.getClass(), cls}));
					t.initCause(ex);
					throw t;
				}
			}
		}

		throw new ClassCastException(
			Messages.get(MCommon.CLASS_NOT_COMPATIABLE, new Object[] {
					val+"("+val.getClass().getName()+")",
				cls}));
	}
	/** Converts to the specified type.
	 *
	 * @param nullable whether the result could be null.
	 * If false, 0 is used for number, the default constructor is used
	 * for others. {@link #coerce(Class, Object)} is a special case that
	 * is equivalent to nullable=true.
	 * @exception ClassCastException if failed to convert
	 */
	public static Object coerce(Class<?> cls, Object val, boolean nullable)
	throws ClassCastException {
		if (nullable || val != null)
			return coerce(cls, val);

		if (BigDecimal.class == cls) {
			return Objects.ZERO_BIG_DECIMAL;
		} else if (Integer.class == cls || int.class == cls) {
			return Objects.ZERO_INTEGER;
		} else if (Boolean.class == cls || boolean.class == cls) {
			return Boolean.FALSE;
		} else if (Short.class == cls || short.class == cls) {
			return Objects.ZERO_SHORT;
		} else if (Long.class == cls || long.class == cls) {
			return Objects.ZERO_LONG;
		} else if (Double.class == cls || double.class == cls) {
			return Objects.ZERO_DOUBLE;
		} else if (Byte.class == cls || byte.class == cls) {
			return Objects.ZERO_BYTE;
		} else if (BigInteger.class == cls) {
			return Objects.ZERO_BIG_INTEGER;
		} else if (Float.class == cls || float.class == cls) {
			return Objects.ZERO_FLOAT;
		} else if (Character.class == cls || char.class == cls) {
			return Objects.NULL_CHARACTER;
		} else {
			try {
				return newInstance(cls, new Object[] {val});
			} catch (Exception ex) {
				final ClassCastException t =
					new ClassCastException(
						Messages.get(MCommon.CLASS_NOT_COMPATIABLE,
						new Object[] {"null", cls}));
				t.initCause(ex);
				throw t;
			}
		}
	}

	// a thread-safe statically object for lazy initialized.
	private static class LazyInitializationHolder {
		private static ContextClassLoaderFactory instance;
		static {
			ContextClassLoaderFactory factory = null;
			try {
				if (!Strings.isEmpty(_contextClassLoaderName))
					factory = (ContextClassLoaderFactory) newInstanceByThread(_contextClassLoaderName);
				else factory = new ThreadBasedContextClassLoaderFactory();
			} catch (Exception e) {
				log.warn("", e);
				if (factory == null)
					factory = new ThreadBasedContextClassLoaderFactory();
			}
			instance = factory;
		}
	}


	private static class ThreadBasedContextClassLoaderFactory
			implements ContextClassLoaderFactory {

		public ClassLoader getContextClassLoader(Class<?> reference) {
			return Thread.currentThread().getContextClassLoader();
		}

		public ClassLoader getContextClassLoaderForName(String className) {
			return Thread.currentThread().getContextClassLoader();
		}
	}

	/**
	 * Returns the context ClassLoader for the reference class.
	 * <p>Default: return from the current thread.
	 * <br/>
	 * Or specify the library property of <code>org.zkoss.lang.contextClassLoader.class</code>
	 * in zk.xml to provide a customized class loader.
	 * </p>
	 * @param reference the reference class where it is invoked from.
	 * @since 8.0.2
	 */
	public static ClassLoader getContextClassLoader(Class<?> reference) {
		return LazyInitializationHolder.instance.getContextClassLoader(reference);
	}

	/**
	 * Returns the context ClassLoader for the given class name
	 * <p>Default: return from the current thread.
	 * <br/>
	 * Or specify the library property of <code>org.zkoss.lang.contextClassLoader.class</code>
	 * in zk.xml to provide a customized class loader.
	 * </p>
	 * @param className the class name to be loaded by the returned class loader
	 * @since 8.5.1
	 */
	public static ClassLoader getContextClassLoaderForName(String className) {
		// Avoid loading "org.zkoss.lang.contextClassLoader.class" looping
		if (LazyInitializationHolder.instance == null)
			return Thread.currentThread().getContextClassLoader();
		return LazyInitializationHolder.instance.getContextClassLoaderForName(className);
	}

	/**
	 * Sets the customized context ClassLoader name by the library property
	 * of <code>org.zkoss.lang.contextClassLoader.class</code>.
	 * It is intended to be called by ZK internally.
	 * @since 8.5.1
	 */
	public static void configureContextClassLoader() {
		_contextClassLoaderName = Library.getProperty("org.zkoss.lang.contextClassLoader.class", "");
	}
}
