From 8e59380f2fcd6774c3746f0ec3e16fda099fd872 Mon Sep 17 00:00:00 2001 From: Romain Manni-Bucau Date: Wed, 31 Dec 2025 14:50:48 +0100 Subject: [PATCH 1/3] [XBEAN-453] try to explicit the parameter types matched instead of using ... --- .../apache/xbean/recipe/ReflectionUtil.java | 88 ++++++++++++------- .../apache/xbean/recipe/ObjectRecipeTest.java | 31 +++++++ 2 files changed, 89 insertions(+), 30 deletions(-) diff --git a/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java b/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java index ca16f32d..fee91e0a 100644 --- a/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java +++ b/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; @@ -601,7 +602,9 @@ public static ConstructorFactory findConstructor(Class typeClass, List p boolean useNoArgConstructor = false; // verify parameter names and types are the same length if (parameterNames != null) { - if (!hasParameterTypes) parameterTypes = Collections.nCopies(parameterNames.size(), null); + if (!hasParameterTypes) { + parameterTypes = Collections.nCopies(parameterNames.size(), Object.class); + } if (parameterNames.size() != parameterTypes.size()) { throw new ConstructionException("Invalid ObjectRecipe: recipe has " + parameterNames.size() + " parameter names and " + parameterTypes.size() + " parameter types"); @@ -616,11 +619,14 @@ public static ConstructorFactory findConstructor(Class typeClass, List p // get all methods sorted so that the methods with the most constructor args are first - List constructors = new ArrayList(Arrays.asList(typeClass.getConstructors())); - constructors.addAll(Arrays.asList(typeClass.getDeclaredConstructors())); + List constructors = new ArrayList(Arrays.asList(typeClass.getDeclaredConstructors())); Collections.sort(constructors, new Comparator() { public int compare(Constructor constructor1, Constructor constructor2) { - return constructor2.getParameterTypes().length - constructor1.getParameterTypes().length; + int diff = constructor2.getParameterTypes().length - constructor1.getParameterTypes().length; + if (diff == 0) { // prefer public over private + return visibilityLevel(constructor1.getModifiers()) - visibilityLevel(constructor2.getModifiers()); + } + return diff; } }); @@ -635,7 +641,7 @@ public int compare(Constructor constructor1, Constructor constructor2) { if (constructor.getParameterTypes().length != parameterTypes.size()) { if (matchLevel < 1) { matchLevel = 1; - missException = new MissingFactoryMethodException("Constructor has " + constructor.getParameterTypes().length + " arugments " + + missException = new MissingFactoryMethodException("Constructor has " + constructor.getParameterTypes().length + " arguments " + "but expected " + parameterTypes.size() + " arguments: " + constructor); } continue; @@ -686,11 +692,26 @@ public int compare(Constructor constructor1, Constructor constructor2) { if (missException != null) { throw missException; - } else { - StringBuffer buffer = new StringBuffer("Unable to find a valid constructor: "); - buffer.append("public void ").append(typeClass.getName()).append(toParameterList(parameterTypes)); - throw new ConstructionException(buffer.toString()); } + + StringBuilder buffer = new StringBuilder("Unable to find a valid constructor: "); + buffer.append("public void ").append(typeClass.getName()).append(toParameterList(parameterTypes)); + throw new ConstructionException(buffer.toString()); + } + + private static int visibilityLevel(int modifiers) { + if (Modifier.isPrivate(modifiers)) { + return 3; + } + if (Modifier.isProtected(modifiers)) { + return 2; + } + // 1 = package + if (Modifier.isPublic(modifiers)) { + return 0; + } + // unlikely + return 4; } public static StaticFactory findStaticFactory(Class typeClass, String factoryMethod, List> parameterTypes, Set