Author: gnodet
Date: Tue Jul 31 17:10:06 2012
New Revision: 1367681
URL: http://svn.apache.org/viewvc?rev=1367681&view=rev
Log:
[ARIES-894] Unable to access public methods overriden/implemented in a
protected class
Modified:
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java
aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java
aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/utils/ReflectionUtilsTest.java
Modified:
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
URL:
http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java?rev=1367681&r1=1367680&r2=1367681&view=diff
==============================================================================
---
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
(original)
+++
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
Tue Jul 31 17:10:06 2012
@@ -18,8 +18,6 @@
*/
package org.apache.aries.blueprint.container;
-import static org.apache.aries.blueprint.utils.ReflectionUtils.getRealCause;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -57,6 +55,9 @@ import org.osgi.service.blueprint.reflec
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static
org.apache.aries.blueprint.utils.ReflectionUtils.getPublicMethods;
+import static org.apache.aries.blueprint.utils.ReflectionUtils.getRealCause;
+
/**
* A <code>Recipe</code> to create POJOs.
*
@@ -344,7 +345,7 @@ public class BeanRecipe extends Abstract
private Map<Method, List<Object>> findMatchingMethods(Class type, String
name, boolean instance, List<Object> args, List<ReifiedType> types) {
Map<Method, List<Object>> matches = new HashMap<Method,
List<Object>>();
// Get constructors
- List<Method> methods = new
ArrayList<Method>(Arrays.asList(type.getMethods()));
+ List<Method> methods = getPublicMethods(type);
// Discard any signature with wrong cardinality
for (Iterator<Method> it = methods.iterator(); it.hasNext();) {
Method mth = it.next();
Modified:
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java
URL:
http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java?rev=1367681&r1=1367680&r2=1367681&view=diff
==============================================================================
---
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java
(original)
+++
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/utils/ReflectionUtils.java
Tue Jul 31 17:10:06 2012
@@ -40,9 +40,9 @@ import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
-import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
import org.apache.aries.blueprint.container.GenericType;
import org.apache.aries.blueprint.di.ExecutionContext;
+import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
import org.osgi.framework.BundleReference;
import org.osgi.service.blueprint.container.ComponentDefinitionException;
@@ -110,21 +110,73 @@ public class ReflectionUtils {
public static Method getLifecycleMethod(Class clazz, String name) {
if (name != null) {
- try {
- Method method = clazz.getMethod(name);
- if (Void.TYPE.equals(method.getReturnType())) {
+ for (Method method : getPublicMethods(clazz)) {
+ if (method.getName().equals(name)
+ && method.getParameterTypes().length == 0
+ && Void.TYPE.equals(method.getReturnType())) {
return method;
}
- } catch (NoSuchMethodException e) {
- // fall thru
}
}
return null;
}
-
+
+ public static List<Method> getPublicMethods(Class clazz) {
+ ArrayList<Method> methods = new ArrayList<Method>();
+ doGetPublicMethods(clazz, methods);
+ return methods;
+ }
+
+ private static void doGetPublicMethods(Class clazz, ArrayList<Method>
methods) {
+ Class parent = clazz.getSuperclass();
+ if (parent != null) {
+ doGetPublicMethods(parent, methods);
+ }
+ for (Class interf : clazz.getInterfaces()) {
+ doGetPublicMethods(interf, methods);
+ }
+ if (Modifier.isPublic(clazz.getModifiers())) {
+ for (Method mth : clazz.getMethods()) {
+ removeByNameAndSignature(methods, mth);
+ methods.add(mth);
+ }
+ }
+ }
+
+ private static void removeByNameAndSignature(ArrayList<Method> methods,
Method toRemove) {
+ for (int i = 0; i < methods.size(); i++) {
+ Method m = methods.get(i);
+ if (m != null &&
+ m.getReturnType() == toRemove.getReturnType() &&
+ m.getName() == toRemove.getName() &&
+ arrayContentsEq(m.getParameterTypes(),
+ toRemove.getParameterTypes())) {
+ methods.remove(i--);
+ }
+ }
+ }
+
+ private static boolean arrayContentsEq(Object[] a1, Object[] a2) {
+ if (a1 == null) {
+ return a2 == null || a2.length == 0;
+ }
+ if (a2 == null) {
+ return a1.length == 0;
+ }
+ if (a1.length != a2.length) {
+ return false;
+ }
+ for (int i = 0; i < a1.length; i++) {
+ if (a1[i] != a2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static List<Method> findCompatibleMethods(Class clazz, String name,
Class[] paramTypes) {
List<Method> methods = new ArrayList<Method>();
- for (Method method : clazz.getMethods()) {
+ for (Method method : getPublicMethods(clazz)) {
Class[] methodParams = method.getParameterTypes();
if (name.equals(method.getName()) &&
Void.TYPE.equals(method.getReturnType()) && methodParams.length ==
paramTypes.length && !method.isBridge()) {
boolean assignable = true;
@@ -154,7 +206,7 @@ public class ReflectionUtils {
Map<String,List<Method>> setters = new HashMap<String,
List<Method>>();
Set<String> illegalProperties = new HashSet<String>();
- for (Method method : clazz.getMethods()) {
+ for (Method method : getPublicMethods(clazz)) {
if (Modifier.isStatic(method.getModifiers()) ||
method.isBridge()) continue;
String name = method.getName();
@@ -519,7 +571,8 @@ public class ReflectionUtils {
builder.append(wcl.get());
}
-
+
+ builder.append(")");
return builder.toString();
}
}
Modified:
aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java
URL:
http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java?rev=1367681&r1=1367680&r2=1367681&view=diff
==============================================================================
---
aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java
(original)
+++
aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/container/BeanRecipeTest.java
Tue Jul 31 17:10:06 2012
@@ -26,7 +26,10 @@ import java.util.List;
import java.util.Set;
import org.apache.aries.blueprint.di.ExecutionContext;
+import org.apache.aries.blueprint.di.PassThroughRecipe;
import org.junit.Test;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+
import static org.junit.Assert.*;
public class BeanRecipeTest {
@@ -65,6 +68,56 @@ public class BeanRecipeTest {
public ExampleService(Example<String> e) {}
}
+ static public interface A {
+ String getA();
+ void setA(String a);
+ }
+ static public interface B extends A {
+ String getB();
+ void setB(String b);
+ void init();
+ }
+ static public class C implements B {
+ String a = "a", b = "b", c = "c";
+ public String getA() {
+ return a;
+ }
+ public void setA(String a) {
+ this.a = a;
+ }
+ public String getB() {
+ return b;
+ }
+ public void setB(String b) {
+ this.b = b;
+ }
+ public String getC() {
+ return c;
+ }
+ public void setC(String c) {
+ this.c = c;
+ }
+ public void init() {
+ }
+ }
+ static public class Factory {
+ public B create() {
+ return new D();
+ }
+ private class D extends C {
+ String d = "d";
+ public String getD() {
+ return d;
+ }
+ public void setD(String d) {
+ this.d = d;
+ }
+ public void init() {
+ }
+ }
+ }
+
+
@Test
public void parameterWithGenerics() throws Exception {
BlueprintContainerImpl container = new BlueprintContainerImpl(null,
null, null, null, null, null, null);
@@ -139,8 +192,83 @@ public class BeanRecipeTest {
assertEquals(2, methods.size());
assertFalse(methods.contains(Middle.class.getMethod("getBasic",
int.class)));
}
-
- private Set<Method> applyStaticHidingRules(Collection<Method> methods) {
+
+ @Test
+ public void protectedClassAccess() throws Exception {
+ BlueprintContainerImpl container = new BlueprintContainerImpl(null,
null, null, null, null, null, null);
+ BeanRecipe recipe = new BeanRecipe("a", container, null, false);
+ recipe.setFactoryComponent(new PassThroughRecipe("factory", new
Factory().create()));
+ recipe.setFactoryMethod("getA");
+ ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+ assertNotNull(recipe.create());
+
+ recipe = new BeanRecipe("b", container, null, false);
+ recipe.setFactoryComponent(new PassThroughRecipe("factory", new
Factory().create()));
+ recipe.setFactoryMethod("getB");
+ ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+ assertNotNull(recipe.create());
+
+ recipe = new BeanRecipe("c", container, null, false);
+ recipe.setFactoryComponent(new PassThroughRecipe("factory", new
Factory().create()));
+ recipe.setFactoryMethod("getC");
+ ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+ assertNotNull(recipe.create());
+
+ recipe = new BeanRecipe("d", container, null, false);
+ recipe.setFactoryComponent(new PassThroughRecipe("factory", new
Factory().create()));
+ recipe.setFactoryMethod("getD");
+ ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+ try {
+ assertNotNull(recipe.create());
+ fail("Should have thrown an exception");
+ } catch (ComponentDefinitionException e) {
+ // ok
+ }
+
+ recipe = new BeanRecipe("a", container, null, false);
+ recipe.setFactoryComponent(new PassThroughRecipe("factory", new
Factory()));
+ recipe.setFactoryMethod("create");
+ recipe.setProperty("a", "a");
+ ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+ assertNotNull(recipe.create());
+
+ recipe = new BeanRecipe("b", container, null, false);
+ recipe.setFactoryComponent(new PassThroughRecipe("factory", new
Factory()));
+ recipe.setFactoryMethod("create");
+ recipe.setProperty("b", "b");
+ ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+ assertNotNull(recipe.create());
+
+ recipe = new BeanRecipe("c", container, null, false);
+ recipe.setFactoryComponent(new PassThroughRecipe("factory", new
Factory()));
+ recipe.setFactoryMethod("create");
+ recipe.setProperty("c", "c");
+ ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+ assertNotNull(recipe.create());
+
+ recipe = new BeanRecipe("d", container, null, false);
+ recipe.setFactoryComponent(new PassThroughRecipe("factory", new
Factory()));
+ recipe.setFactoryMethod("create");
+ recipe.setProperty("d", "d");
+ ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+ try {
+ assertNotNull(recipe.create());
+ fail("Should have thrown an exception");
+ } catch (ComponentDefinitionException e) {
+ // ok
+ }
+
+ recipe = new BeanRecipe("a", container, null, false);
+ recipe.setFactoryComponent(new PassThroughRecipe("factory", new
Factory()));
+ recipe.setFactoryMethod("create");
+ recipe.setInitMethod("init");
+ ExecutionContext.Holder.setContext(new BlueprintRepository(container));
+ assertNotNull(recipe.create());
+
+ }
+
+
+ private Set<Method> applyStaticHidingRules(Collection<Method> methods) {
try {
Method m =
BeanRecipe.class.getDeclaredMethod("applyStaticHidingRules", Collection.class);
m.setAccessible(true);
Modified:
aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/utils/ReflectionUtilsTest.java
URL:
http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/utils/ReflectionUtilsTest.java?rev=1367681&r1=1367680&r2=1367681&view=diff
==============================================================================
---
aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/utils/ReflectionUtilsTest.java
(original)
+++
aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/utils/ReflectionUtilsTest.java
Tue Jul 31 17:10:06 2012
@@ -52,7 +52,7 @@ public class ReflectionUtilsTest {
},
ExtendedBlueprintContainer.class);
- static class GetterOnly {
+ public static class GetterOnly {
public String getValue() { return "test"; }
}
@@ -109,7 +109,7 @@ public class ReflectionUtilsTest {
assertEquals("test", sut[1].get(new GetterOnly(), mockBlueprint));
}
- static class SetterOnly {
+ public static class SetterOnly {
private String f;
public void setField(String val) { f = val; }
@@ -131,7 +131,7 @@ public class ReflectionUtilsTest {
assertEquals("trial", so.retrieve());
}
- static class SetterAndGetter {
+ public static class SetterAndGetter {
private String f;
public void setField(String val) { f = val; }
@@ -198,7 +198,7 @@ public class ReflectionUtilsTest {
assertEquals("predicament", sut[2].get(fap, mockBlueprint));
}
- static class OverloadedSetters {
+ public static class OverloadedSetters {
public Object field;
public void setField(String val) { field = val; }
@@ -229,7 +229,7 @@ public class ReflectionUtilsTest {
sut[1].set(new OverloadedSetters(), new Inconvertible(),
mockBlueprint);
}
- static class MultipleMatchesByConversion {
+ public static class MultipleMatchesByConversion {
public void setField(String s) {}
public void setField(List<String> list) {}
}
@@ -240,8 +240,8 @@ public class ReflectionUtilsTest {
sut[1].set(new MultipleMatchesByConversion(), new HashSet<String>(),
mockBlueprint);
}
-
- static class MultipleMatchesByType {
+
+ public static class MultipleMatchesByType {
public void setField(List<String> list) {}
public void setField(Queue<String> list) {}
@@ -265,8 +265,8 @@ public class ReflectionUtilsTest {
sut[2].set(new MultipleMatchesByType(), new ArrayList<String>(),
mockBlueprint);
assertEquals(2, MultipleMatchesByType.field);
}
-
- static class NullSetterDisambiguation {
+
+ public static class NullSetterDisambiguation {
public static int field;
public void setField(int i) { field = i; }