juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject juneau git commit: Fuzzy arg matching.
Date Mon, 01 Jan 2018 14:49:03 GMT
Repository: juneau
Updated Branches:
  refs/heads/master 6e794947b -> 6ac075fc2


Fuzzy arg matching.

Project: http://git-wip-us.apache.org/repos/asf/juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/juneau/commit/6ac075fc
Tree: http://git-wip-us.apache.org/repos/asf/juneau/tree/6ac075fc
Diff: http://git-wip-us.apache.org/repos/asf/juneau/diff/6ac075fc

Branch: refs/heads/master
Commit: 6ac075fc2e14e2fa73058a5a12c6c91472e69ccb
Parents: 6e79494
Author: JamesBognar <jamesbognar@apache.org>
Authored: Mon Jan 1 09:48:59 2018 -0500
Committer: JamesBognar <jamesbognar@apache.org>
Committed: Mon Jan 1 09:48:59 2018 -0500

----------------------------------------------------------------------
 .../org/apache/juneau/utils/ClassUtilsTest.java |  62 ++++++++++
 .../java/org/apache/juneau/BeanContext.java     |  20 +--
 .../java/org/apache/juneau/BeanSession.java     |  20 +--
 .../main/java/org/apache/juneau/Context.java    |  40 +++---
 .../java/org/apache/juneau/PropertyStore.java   |  50 ++++----
 .../org/apache/juneau/internal/ClassUtils.java  | 124 +++++++++++++++----
 6 files changed, 241 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/juneau/blob/6ac075fc/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java
index dd268e2..e567bc5 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java
@@ -318,4 +318,66 @@ public class ClassUtilsTest {
 		int a1;
 		int b1;
 	}
+
+	//====================================================================================================
+	// Fuzzy constructor args
+	//====================================================================================================
+	@Test
+	public void newInstanceWithFuzzyArgs() throws Exception {
+		FA t = null;
+		
+		t = ClassUtils.newInstance(FA.class, FA.class, true);
+		assertEquals(1, t.c);
+
+		t = ClassUtils.newInstance(FA.class, FA.class, true, "foo");
+		assertEquals(2, t.c);
+
+		t = ClassUtils.newInstance(FA.class, FA.class, true, 123, "foo");
+		assertEquals(3, t.c);
+
+		t = ClassUtils.newInstance(FA.class, FA.class, true, "foo", 123);
+		assertEquals(3, t.c);
+	
+		FB t2 = null;
+		
+		try {
+			t2 = ClassUtils.newInstance(FB.class, FB.class, true);
+			fail();
+		} catch (Exception e) {
+			assertEquals("Could not instantiate class org.apache.juneau.utils.ClassUtilsTest$FB",
e.getMessage());
+		}
+
+		t2 = ClassUtils.newInstance(FB.class, FB.class, true, "foo");
+		assertEquals(1, t2.c);
+
+		t2 = ClassUtils.newInstance(FB.class, FB.class, true, 123, "foo");
+		assertEquals(1, t2.c);
+
+		t2 = ClassUtils.newInstance(FB.class, FB.class, true, "foo", 123);
+		assertEquals(1, t2.c);
+	}
+	
+	public static class FA {
+		int c;
+		
+		public FA() {
+			c = 1;
+		}
+		
+		public FA(String foo) {
+			c = 2;
+		}
+
+		public FA(int foo, String bar) {
+			c = 3;
+		}
+	}
+
+	public static class FB {
+		int c;
+		
+		public FB(String foo) {
+			c = 1;
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/juneau/blob/6ac075fc/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 4b76241..a0779f4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -1741,8 +1741,10 @@ public class BeanContext extends Context {
 	 * @param c2
 	 * 	The class to instantiate.
 	 * 	Can also be an instance of the class.
-	 * @param allowNoArgs 
-	 * 	If constructor with specified args cannot be found, use the no-args constructor.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	The arguments to pass to the constructor.
 	 * @return 
@@ -1750,8 +1752,8 @@ public class BeanContext extends Context {
 	 * @throws 
 	 * 	RuntimeException if constructor could not be found or called.
 	 */
-	public <T> T newInstance(Class<T> c, Object c2, boolean allowNoArgs, Object...args)
{
-		return ClassUtils.newInstance(c, c2, allowNoArgs, args);
+	public <T> T newInstance(Class<T> c, Object c2, boolean fuzzyArgs, Object...args)
{
+		return ClassUtils.newInstance(c, c2, fuzzyArgs, args);
 	}
 
 	/**
@@ -1765,8 +1767,10 @@ public class BeanContext extends Context {
 	 * @param c2
 	 * 	The class to instantiate.
 	 * 	Can also be an instance of the class.
-	 * @param allowNoArgs 
-	 * 	If constructor with specified args cannot be found, use the no-args constructor.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	The arguments to pass to the constructor.
 	 * @return 
@@ -1774,8 +1778,8 @@ public class BeanContext extends Context {
 	 * @throws 
 	 * 	RuntimeException if constructor could not be found or called.
 	 */
-	public <T> T newInstanceFromOuter(Object outer, Class<T> c, Object c2, boolean
allowNoArgs, Object...args) {
-		return ClassUtils.newInstanceFromOuter(outer, c, c2, allowNoArgs, args);
+	public <T> T newInstanceFromOuter(Object outer, Class<T> c, Object c2, boolean
fuzzyArgs, Object...args) {
+		return ClassUtils.newInstanceFromOuter(outer, c, c2, fuzzyArgs, args);
 	}
 	
 	/**

http://git-wip-us.apache.org/repos/asf/juneau/blob/6ac075fc/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index 34a9022..cd59eaa 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -1007,8 +1007,10 @@ public class BeanSession extends Session {
 	 * @param c2
 	 * 	The class to instantiate.
 	 * 	Can also be an instance of the class.
-	 * @param allowNoArgs 
-	 * 	If constructor with specified args cannot be found, use the no-args constructor.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	The arguments to pass to the constructor.
 	 * @return 
@@ -1016,8 +1018,8 @@ public class BeanSession extends Session {
 	 * @throws 
 	 * 	RuntimeException if constructor could not be found or called.
 	 */
-	public <T> T newInstance(Class<T> c, Object c2, boolean allowNoArgs, Object...args)
{
-		return ctx.newInstance(c, c2, allowNoArgs, args);
+	public <T> T newInstance(Class<T> c, Object c2, boolean fuzzyArgs, Object...args)
{
+		return ctx.newInstance(c, c2, fuzzyArgs, args);
 	}
 
 	/**
@@ -1031,8 +1033,10 @@ public class BeanSession extends Session {
 	 * @param c2
 	 * 	The class to instantiate.
 	 * 	Can also be an instance of the class.
-	 * @param allowNoArgs 
-	 * 	If constructor with specified args cannot be found, use the no-args constructor.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	The arguments to pass to the constructor.
 	 * @return 
@@ -1040,8 +1044,8 @@ public class BeanSession extends Session {
 	 * @throws 
 	 * 	RuntimeException if constructor could not be found or called.
 	 */
-	public <T> T newInstanceFromOuter(Object outer, Class<T> c, Object c2, boolean
allowNoArgs, Object...args) {
-		return ctx.newInstanceFromOuter(outer, c, c2, allowNoArgs, args);
+	public <T> T newInstanceFromOuter(Object outer, Class<T> c, Object c2, boolean
fuzzyArgs, Object...args) {
+		return ctx.newInstanceFromOuter(outer, c, c2, fuzzyArgs, args);
 	}
 	
 	/**

http://git-wip-us.apache.org/repos/asf/juneau/blob/6ac075fc/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
index 427f9a7..5d761e4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
@@ -263,15 +263,17 @@ public abstract class Context {
 	 * @param def 
 	 * 	The default value if the property doesn't exist.
 	 * 	<br>Can either be an instance of <code>T</code>, or a <code>Class&lt;?
<jk>extends</jk> T&gt;</code>.
-	 * @param allowNoArgs 
-	 * 	Look for no-arg constructors when instantiating a class.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	Arguments to pass to the constructor.
 	 * 	Constructors matching the arguments are always used before no-arg constructors.
 	 * @return A new property instance.
 	 */
-	public <T> T getInstanceProperty(String key, Class<T> type, Object def, boolean
allowNoArgs, Object...args) {
-		return propertyStore.getInstanceProperty(key, type, def, allowNoArgs, args);
+	public <T> T getInstanceProperty(String key, Class<T> type, Object def, boolean
fuzzyArgs, Object...args) {
+		return propertyStore.getInstanceProperty(key, type, def, fuzzyArgs, args);
 	}
 
 	/**
@@ -283,15 +285,17 @@ public abstract class Context {
 	 * @param def 
 	 * 	The default value if the property doesn't exist.
 	 * 	<br>Can either be an instance of <code>T</code>, or a <code>Class&lt;?
<jk>extends</jk> T&gt;</code>.
-	 * @param allowNoArgs 
-	 * 	Look for no-arg constructors when instantiating a class.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	Arguments to pass to the constructor.
 	 * 	Constructors matching the arguments are always used before no-arg constructors.
 	 * @return A new property instance.
 	 */
-	public <T> T getInstanceProperty(String key, Object outer, Class<T> type, Object
def, boolean allowNoArgs, Object...args) {
-		return propertyStore.getInstanceProperty(key, outer, type, def, allowNoArgs, args);
+	public <T> T getInstanceProperty(String key, Object outer, Class<T> type, Object
def, boolean fuzzyArgs, Object...args) {
+		return propertyStore.getInstanceProperty(key, outer, type, def, fuzzyArgs, args);
 	}
 
 	/**
@@ -312,15 +316,17 @@ public abstract class Context {
 	 * @param key The property name.
 	 * @param type The class type of the property.
 	 * @param def The default object to return if the property doesn't exist.
-	 * @param allowNoArgs 
-	 * 	Look for no-arg constructors when instantiating a class.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	Arguments to pass to the constructor.
 	 * 	Constructors matching the arguments are always used before no-arg constructors.
 	 * @return A new property instance.
 	 */
-	public <T> T[] getInstanceArrayProperty(String key, Class<T> type, T[] def,
boolean allowNoArgs, Object...args) {
-		return propertyStore.getInstanceArrayProperty(key, type, def, allowNoArgs, args);
+	public <T> T[] getInstanceArrayProperty(String key, Class<T> type, T[] def,
boolean fuzzyArgs, Object...args) {
+		return propertyStore.getInstanceArrayProperty(key, type, def, fuzzyArgs, args);
 	}
 
 	/**
@@ -330,15 +336,17 @@ public abstract class Context {
 	 * @param outer The outer object if the class we're instantiating is an inner class.
 	 * @param type The class type of the property.
 	 * @param def The default object to return if the property doesn't exist.
-	 * @param allowNoArgs 
-	 * 	Look for no-arg constructors when instantiating a class.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	Arguments to pass to the constructor.
 	 * 	Constructors matching the arguments are always used before no-arg constructors.
 	 * @return A new property instance.
 	 */
-	public <T> T[] getInstanceArrayProperty(String key, Object outer, Class<T> type,
T[] def, boolean allowNoArgs, Object...args) {
-		return propertyStore.getInstanceArrayProperty(key, outer, type, def, allowNoArgs, args);
+	public <T> T[] getInstanceArrayProperty(String key, Object outer, Class<T> type,
T[] def, boolean fuzzyArgs, Object...args) {
+		return propertyStore.getInstanceArrayProperty(key, outer, type, def, fuzzyArgs, args);
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/juneau/blob/6ac075fc/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStore.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStore.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStore.java
index cce39b6..39700e0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStore.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/PropertyStore.java
@@ -408,15 +408,17 @@ public final class PropertyStore {
 	 * @param def 
 	 * 	The default value if the property doesn't exist.
 	 * 	<br>Can either be an instance of <code>T</code>, or a <code>Class&lt;?
<jk>extends</jk> T&gt;</code>.
-	 * @param allowNoArgs 
-	 * 	Look for no-arg constructors when instantiating a class.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	Arguments to pass to the constructor.
 	 * 	Constructors matching the arguments are always used before no-arg constructors.
 	 * @return A new property instance.
 	 */
-	public <T> T getInstanceProperty(String key, Class<T> type, Object def, boolean
allowNoArgs, Object...args) {
-		return getInstanceProperty(key, null, type, def, allowNoArgs, args);
+	public <T> T getInstanceProperty(String key, Class<T> type, Object def, boolean
fuzzyArgs, Object...args) {
+		return getInstanceProperty(key, null, type, def, fuzzyArgs, args);
 	}
 
 	/**
@@ -428,21 +430,23 @@ public final class PropertyStore {
 	 * @param def 
 	 * 	The default value if the property doesn't exist.
 	 * 	<br>Can either be an instance of <code>T</code>, or a <code>Class&lt;?
<jk>extends</jk> T&gt;</code>.
-	 * @param allowNoArgs 
-	 * 	Look for no-arg constructors when instantiating a class.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	Arguments to pass to the constructor.
 	 * 	Constructors matching the arguments are always used before no-arg constructors.
 	 * @return A new property instance.
 	 */
-	public <T> T getInstanceProperty(String key, Object outer, Class<T> type, Object
def, boolean allowNoArgs, Object...args) {
+	public <T> T getInstanceProperty(String key, Object outer, Class<T> type, Object
def, boolean fuzzyArgs, Object...args) {
 		Property p = findProperty(key);
 		if (p != null)
-			return p.asInstance(outer, type, allowNoArgs, args);
+			return p.asInstance(outer, type, fuzzyArgs, args);
 		if (def == null)
 			return null;
 		if (def instanceof Class) 
-			return ClassUtils.newInstance(type, def, allowNoArgs, args);
+			return ClassUtils.newInstance(type, def, fuzzyArgs, args);
 		if (type.isInstance(def))
 			return (T)def;
 		throw new ConfigException("Could not instantiate property ''{0}'' as type ''{1}'' with
default value ''{2}''", key, type, def);
@@ -466,15 +470,17 @@ public final class PropertyStore {
 	 * @param key The property name.
 	 * @param type The class type of the property.
 	 * @param def The default object to return if the property doesn't exist.
-	 * @param allowNoArgs 
-	 * 	Look for no-arg constructors when instantiating a class.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	Arguments to pass to the constructor.
 	 * 	Constructors matching the arguments are always used before no-arg constructors.
 	 * @return A new property instance.
 	 */
-	public <T> T[] getInstanceArrayProperty(String key, Class<T> type, T[] def,
boolean allowNoArgs, Object...args) {
-		return getInstanceArrayProperty(key, null, type, def, allowNoArgs, args);
+	public <T> T[] getInstanceArrayProperty(String key, Class<T> type, T[] def,
boolean fuzzyArgs, Object...args) {
+		return getInstanceArrayProperty(key, null, type, def, fuzzyArgs, args);
 	}
 
 	/**
@@ -484,16 +490,18 @@ public final class PropertyStore {
 	 * @param outer The outer object if the class we're instantiating is an inner class.
 	 * @param type The class type of the property.
 	 * @param def The default object to return if the property doesn't exist.
-	 * @param allowNoArgs 
-	 * 	Look for no-arg constructors when instantiating a class.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	Arguments to pass to the constructor.
 	 * 	Constructors matching the arguments are always used before no-arg constructors.
 	 * @return A new property instance.
 	 */
-	public <T> T[] getInstanceArrayProperty(String key, Object outer, Class<T> type,
T[] def, boolean allowNoArgs, Object...args) {
+	public <T> T[] getInstanceArrayProperty(String key, Object outer, Class<T> type,
T[] def, boolean fuzzyArgs, Object...args) {
 		Property p = findProperty(key);
-		return p == null ? def : p.asInstanceArray(outer, type, allowNoArgs, args);
+		return p == null ? def : p.asInstanceArray(outer, type, fuzzyArgs, args);
 	}
 
 	/**
@@ -751,15 +759,15 @@ public final class PropertyStore {
 			}
 		}
 
-		public <T> T asInstance(Object outer, Class<T> iType, boolean allowNoArgs,
Object...args) {
+		public <T> T asInstance(Object outer, Class<T> iType, boolean fuzzyArgs, Object...args)
{
 			if (type == STRING) 
 				return ClassUtils.fromString(iType, value.toString());
 			else if (type == OBJECT || type == CLASS) 
-				return ClassUtils.newInstanceFromOuter(outer, iType, value, allowNoArgs, args);
+				return ClassUtils.newInstanceFromOuter(outer, iType, value, fuzzyArgs, args);
 			throw new ConfigException("Invalid property instantiation ''{0}'' to ''{1}'' on property
''{2}''", type, iType, name);
 		}
 
-		public <T> T[] asInstanceArray(Object outer, Class<T> eType, boolean allowNoArgs,
Object...args) {
+		public <T> T[] asInstanceArray(Object outer, Class<T> eType, boolean fuzzyArgs,
Object...args) {
 			if (value instanceof Collection) {
 				Collection<?> l = (Collection<?>)value;
 				Object t = Array.newInstance(eType, l.size());
@@ -771,7 +779,7 @@ public final class PropertyStore {
 					else if (type == SET_STRING || type == LIST_STRING) 
 						o2 = ClassUtils.fromString(eType, o.toString());
 					else if (type == SET_CLASS || type == LIST_CLASS || type == LIST_OBJECT)
-						o2 = ClassUtils.newInstanceFromOuter(outer, eType, o, allowNoArgs, args);
+						o2 = ClassUtils.newInstanceFromOuter(outer, eType, o, fuzzyArgs, args);
 					if (o2 == null)
 						throw new ConfigException("Invalid property conversion ''{0}'' to ''{1}[]'' on property
''{2}''", type, eType, name);
 					Array.set(t, i++, o2);

http://git-wip-us.apache.org/repos/asf/juneau/blob/6ac075fc/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
index 81758bb..594d9d1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
@@ -576,23 +576,42 @@ public final class ClassUtils {
 	 * Finds a public constructor with the specified parameters without throwing an exception.
 	 *
 	 * @param c The class to search for a constructor.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy-arg matching.
+	 * 	Find a constructor that best matches the specified args.
 	 * @param argTypes
 	 * 	The argument types in the constructor.
 	 * 	Can be subtypes of the actual constructor argument types.
 	 * @return The matching constructor, or <jk>null</jk> if constructor could not
be found.
 	 */
 	@SuppressWarnings("unchecked")
-	public static <T> Constructor<T> findPublicConstructor(Class<T> c, Class<?>...argTypes)
{
+	public static <T> Constructor<T> findPublicConstructor(Class<T> c, boolean
fuzzyArgs, Class<?>...argTypes) {
 		ConstructorCacheEntry cce = CONSTRUCTOR_CACHE.get(c);
 		if (cce != null && argsMatch(cce.paramTypes, argTypes)) 
 			return (Constructor<T>)cce.constructor;
+	
+		if (fuzzyArgs) {
+			int bestCount = -1;
+			Constructor<?> bestMatch = null;
+			for (Constructor<?> n : c.getConstructors()) {
+				int m = fuzzyArgsMatch(n.getParameterTypes(), argTypes);
+				if (m > bestCount) {
+					bestCount = m;
+					bestMatch = n;
+				}
+			}
+			if (bestCount >= 0) 
+				CONSTRUCTOR_CACHE.put(c, new ConstructorCacheEntry(c, bestMatch));
+			return (Constructor<T>)bestMatch;
+		} 
 		
 		for (Constructor<?> n : c.getConstructors()) {
-			if (isPublic(n) && argsMatch(n.getParameterTypes(), argTypes)) {
+			if (argsMatch(n.getParameterTypes(), argTypes)) {
 				CONSTRUCTOR_CACHE.put(c, new ConstructorCacheEntry(c, n));
 				return (Constructor<T>)n;
 			}
 		}
+
 		return null;
 	}
 	
@@ -623,6 +642,27 @@ public final class ClassUtils {
 		return false;
 	}
 	
+	/**
+	 * Returns a number representing the number of arguments that match the specified parameters.
+	 * 
+	 * @param paramTypes The parameters types specified on a method.
+	 * @param argTypes The class types of the arguments being passed to the method.
+	 * @return The number of matching arguments, or <code>-1</code> a parameter
was found that isn't in the list of args.
+	 */
+	public static int fuzzyArgsMatch(Class<?>[] paramTypes, Class<?>[] argTypes)
{
+		int matches = 0;
+		outer: for (Class<?> p : paramTypes) {
+			p = getWrapperIfPrimitive(p);
+			for (Class<?> a : argTypes) {
+				if (isParentClass(p, a)) {
+					matches++;
+					continue outer;				
+				}
+			}
+			return -1;
+		}
+		return matches;
+	}
 
 	/**
 	 * Finds the public constructor that can take in the specified arguments.
@@ -634,7 +674,36 @@ public final class ClassUtils {
 	 * 	arguments.
 	 */
 	public static <T> Constructor<T> findPublicConstructor(Class<T> c, Object...args)
{
-		return findPublicConstructor(c, getClasses(args));
+		return findPublicConstructor(c, false, getClasses(args));
+	}
+
+	/**
+	 * Finds the public constructor that can take in the specified arguments.
+	 *
+	 * @param c The class we're trying to construct.
+	 * @param args The argument types we want to pass into the constructor.
+	 * @return
+	 * 	The constructor, or <jk>null</jk> if a public constructor could not be found
that takes in the specified
+	 * 	arguments.
+	 */
+	public static <T> Constructor<T> findPublicConstructor(Class<T> c, Class<?>...args)
{
+		return findPublicConstructor(c, false, args);
+	}
+
+	/**
+	 * Finds the public constructor that can take in the specified arguments.
+	 *
+	 * @param c The class we're trying to construct.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy-arg matching.
+	 * 	Find a constructor that best matches the specified args.
+	 * @param args The arguments we want to pass into the constructor.
+	 * @return
+	 * 	The constructor, or <jk>null</jk> if a public constructor could not be found
that takes in the specified
+	 * 	arguments.
+	 */
+	public static <T> Constructor<T> findPublicConstructor(Class<T> c, boolean
fuzzyArgs, Object...args) {
+		return findPublicConstructor(c, fuzzyArgs, getClasses(args));
 	}
 
 	/**
@@ -718,8 +787,10 @@ public final class ClassUtils {
 	 * @param c2
 	 * 	The class to instantiate.
 	 * 	Can also be an instance of the class.
-	 * @param allowNoArgs 
-	 * 	If constructor with specified args cannot be found, use the no-args constructor.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	The arguments to pass to the constructor.
 	 * @return 
@@ -727,8 +798,8 @@ public final class ClassUtils {
 	 * @throws 
 	 * 	RuntimeException if constructor could not be found or called.
 	 */
-	public static <T> T newInstance(Class<T> c, Object c2, boolean allowNoArgs,
Object...args) {
-		return newInstanceFromOuter(null, c, c2, allowNoArgs, args);
+	public static <T> T newInstance(Class<T> c, Object c2, boolean fuzzyArgs, Object...args)
{
+		return newInstanceFromOuter(null, c, c2, fuzzyArgs, args);
 	}
 
 	/**
@@ -742,8 +813,10 @@ public final class ClassUtils {
 	 * @param c2
 	 * 	The class to instantiate.
 	 * 	Can also be an instance of the class.
-	 * @param allowNoArgs 
-	 * 	If constructor with specified args cannot be found, use the no-args constructor.
+	 * @param fuzzyArgs 
+	 * 	Use fuzzy constructor arg matching.  
+	 * 	<br>When <jk>true</jk>, constructor args can be in any order and extra
args are ignored.
+	 * 	<br>No-arg constructors are also used if no other constructors are found.
 	 * @param args 
 	 * 	The arguments to pass to the constructor.
 	 * @return 
@@ -752,7 +825,7 @@ public final class ClassUtils {
 	 * 	RuntimeException if constructor could not be found or called.
 	 */
 	@SuppressWarnings("unchecked")
-	public static <T> T newInstanceFromOuter(Object outer, Class<T> c, Object c2,
boolean allowNoArgs, Object...args) {
+	public static <T> T newInstanceFromOuter(Object outer, Class<T> c, Object c2,
boolean fuzzyArgs, Object...args) {
 		if (c2 == null)
 			return null;
 		if (c2 instanceof Class) {
@@ -760,22 +833,14 @@ public final class ClassUtils {
 				Class<?> c3 = (Class<?>)c2;
 				if (c3.isInterface() || isAbstract(c3))
 					return null;
-				Constructor<?> con = findPublicConstructor(c3, args);
-				if (con != null)
-					return (T)con.newInstance(args);
-				if (allowNoArgs && args.length != 0)
-					con = findPublicConstructor(c3);
+				Constructor<?> con = findPublicConstructor(c3, fuzzyArgs, args);
 				if (con != null)
-					return (T)con.newInstance();
+					return (T)con.newInstance(fuzzyArgs ? getMatchingArgs(con, args) : args);
 				if (outer != null) {
 					Object[] args2 = new AList<>().append(outer).appendAll(args).toArray();
-					con = findPublicConstructor(c3, args2);
+					con = findPublicConstructor(c3, fuzzyArgs, args2);
 					if (con != null)
-						return (T)con.newInstance(args2);
-					if (allowNoArgs && args.length != 0)
-						con = findPublicConstructor(c3);
-					if (con != null)
-						return (T)con.newInstance();
+						return (T)con.newInstance(fuzzyArgs ? getMatchingArgs(con, args) : args);
 				}
 				throw new FormattedRuntimeException("Could not instantiate class {0}.  Constructor not
found.", c.getName());
 			} catch (Exception e) {
@@ -788,6 +853,21 @@ public final class ClassUtils {
 		}
 	}
 
+	private static Object[] getMatchingArgs(Constructor<?> con, Object[] args) {
+		Class<?>[] paramTypes = con.getParameterTypes();
+		Object[] params = new Object[paramTypes.length];
+		for (int i = 0; i < paramTypes.length; i++) {
+			Class<?> pt = getWrapperIfPrimitive(paramTypes[i]);
+			for (int j = 0; j < args.length; j++) {
+				if (isParentClass(pt, args[j].getClass())) {
+					params[i] = args[j];
+					break;
+				}
+			}
+		}
+		return params;
+	}
+
 	/**
 	 * Returns all the fields in the specified class and all parent classes.
 	 *


Mime
View raw message