357903: Add support for BeanDefinitionRegistryPostProcessor
 - Integrated registry post processor support from Spring 4.3.x
 - Updated test framework with regard to Java 1.8
 - Replaced fest-assert with AssertJ as it is up-to-date and supports OSGi

Signed-off-by: Olaf Otto <olaf@x100.de>
diff --git a/core/src/main/java/org/eclipse/gemini/blueprint/context/support/AbstractDelegatedExecutionApplicationContext.java b/core/src/main/java/org/eclipse/gemini/blueprint/context/support/AbstractDelegatedExecutionApplicationContext.java
index f6476cf..915ca2e 100644
--- a/core/src/main/java/org/eclipse/gemini/blueprint/context/support/AbstractDelegatedExecutionApplicationContext.java
+++ b/core/src/main/java/org/eclipse/gemini/blueprint/context/support/AbstractDelegatedExecutionApplicationContext.java
@@ -14,21 +14,11 @@
 

 package org.eclipse.gemini.blueprint.context.support;

 

-import java.io.IOException;

-import java.util.ArrayList;

-import java.util.Collections;

-import java.util.Iterator;

-import java.util.List;

-

 import org.eclipse.gemini.blueprint.context.DelegatedExecutionOsgiBundleApplicationContext;

 import org.eclipse.gemini.blueprint.context.DependencyAwareBeanFactoryPostProcessor;

 import org.eclipse.gemini.blueprint.context.DependencyInitializationAwareBeanPostProcessor;

 import org.eclipse.gemini.blueprint.context.OsgiBundleApplicationContextExecutor;

-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticaster;

-import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEventMulticasterAdapter;

-import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextClosedEvent;

-import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextFailedEvent;

-import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextRefreshedEvent;

+import org.eclipse.gemini.blueprint.context.event.*;

 import org.eclipse.gemini.blueprint.util.OsgiBundleUtils;

 import org.eclipse.gemini.blueprint.util.OsgiStringUtils;

 import org.eclipse.gemini.blueprint.util.internal.PrivilegedUtils;

@@ -36,6 +26,8 @@
 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;

 import org.springframework.beans.factory.config.BeanPostProcessor;

 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

+import org.springframework.beans.factory.support.BeanDefinitionRegistry;

+import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;

 import org.springframework.beans.factory.support.DefaultListableBeanFactory;

 import org.springframework.context.ApplicationContext;

 import org.springframework.context.ApplicationContextException;

@@ -47,6 +39,9 @@
 import org.springframework.util.Assert;

 import org.springframework.util.ObjectUtils;

 

+import java.io.IOException;

+import java.util.*;

+

 /**

  * OSGi-specific application context that delegates the execution of its life cycle methods to a different class. The

  * main reason behind this is to <em>break</em> the startup of the application context in steps that can be executed

@@ -55,6 +50,8 @@
  * can still call the 'traditional' lifecycle methods through {@link #normalRefresh()} and {@link #normalClose()}.

  * 

  * @author Costin Leau

+ * @author Olaf Otto

+ *

  * @see DelegatedExecutionOsgiBundleApplicationContext

  */

 public abstract class AbstractDelegatedExecutionApplicationContext extends AbstractOsgiBundleApplicationContext

@@ -364,87 +361,190 @@
 	}

 

 	/**

-	 * Instantiate and invoke all registered BeanFactoryPostProcessor beans, respecting explicit order if given. <p/>

-	 * Must be called before singleton instantiation. Very similar to

-	 * {@link AbstractApplicationContext#invokeBeanFactoryPostProcessors} but allowing exclusion of a certain type.

-	 * 

-	 * @param beanFactory

-	 * @param type

-	 * @param exclude

+	 * This version of the original

+	 * {@link org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, List) post processor invocation}

+	 * implementation adds including and excluding processor types to allow for a multi-staged

+	 * context initialization, see for instance {{@link #completeRefresh()}}.

+	 *

+	 * @param beanFactory must not be <code>null</code>

+	 * @param include only invoke post processors that are assignment-compatible with this type. Must not be <code>null</code>

+	 * @param exclude exclude all post processors that are assignment-compatible with this type. Can be <code>null</code>

 	 */

-	private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, Class<?> type,

-			Class<?> exclude) {

-		// Invoke factory processors registered with the context instance.

-		for (Iterator<BeanFactoryPostProcessor> it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) {

-			BeanFactoryPostProcessor factoryProcessor = it.next();

-			// check the exclude type

-			if (type.isInstance(factoryProcessor) && (exclude == null || !exclude.isInstance(factoryProcessor))) {

-				factoryProcessor.postProcessBeanFactory(beanFactory);

+	private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory,

+												 Class<? extends BeanFactoryPostProcessor> include,

+												 Class<? extends BeanFactoryPostProcessor> exclude) {

+		// Invoke BeanDefinitionRegistryPostProcessors first, if any.

+		Set<String> processedBeans = new HashSet<String>();

+

+		if (beanFactory instanceof BeanDefinitionRegistry) {

+			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

+			List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();

+			List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =

+					new LinkedList<BeanDefinitionRegistryPostProcessor>();

+

+			for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) {

+				if (isExcluded(include, exclude, postProcessor)) {

+					continue;

+				}

+

+				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {

+					BeanDefinitionRegistryPostProcessor registryPostProcessor =

+							(BeanDefinitionRegistryPostProcessor) postProcessor;

+					registryPostProcessor.postProcessBeanDefinitionRegistry(registry);

+					registryPostProcessors.add(registryPostProcessor);

+				}

+				else {

+					regularPostProcessors.add(postProcessor);

+				}

 			}

+

+			if (include.isAssignableFrom(BeanDefinitionRegistryPostProcessor.class)) {

+				// Do not initialize FactoryBeans here: We need to leave all regular beans

+				// uninitialized to let the bean factory post-processors apply to them!

+				// Separate between BeanDefinitionRegistryPostProcessors that implement

+				// PriorityOrdered, Ordered, and the rest.

+				String[] postProcessorNames =

+						beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

+

+				// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.

+				List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();

+				for (String ppName : postProcessorNames) {

+					if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {

+						priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));

+						processedBeans.add(ppName);

+					}

+				}

+				sortPostProcessors(beanFactory, priorityOrderedPostProcessors);

+				registryPostProcessors.addAll(priorityOrderedPostProcessors);

+				invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);

+

+				// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.

+				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

+				List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();

+				for (String ppName : postProcessorNames) {

+					if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {

+						orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));

+						processedBeans.add(ppName);

+					}

+				}

+				sortPostProcessors(beanFactory, orderedPostProcessors);

+				registryPostProcessors.addAll(orderedPostProcessors);

+				invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);

+

+				// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.

+				boolean reiterate = true;

+				while (reiterate) {

+					reiterate = false;

+					postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

+					for (String ppName : postProcessorNames) {

+						if (!processedBeans.contains(ppName)) {

+							BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);

+							registryPostProcessors.add(pp);

+							processedBeans.add(ppName);

+							pp.postProcessBeanDefinitionRegistry(registry);

+							reiterate = true;

+						}

+					}

+				}

+

+				// Now, invoke the postProcessBeanFactory callback of all processors handled so far.

+				invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);

+			}

+

+			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

 		}

 

-		// Do not initialize FactoryBeans here: We need to leave all regular

-		// beans uninitialized to let the bean factory post-processors apply to

-		// them!

-		String[] postProcessorNames = beanFactory.getBeanNamesForType(type, true, false);

+		else {

+			// Invoke factory processors registered with the context instance.

+			invokeBeanFactoryPostProcessors(getBeanFactoryPostProcessors(), beanFactory);

+		}

 

-		// Separate between BeanFactoryPostProcessors that implement

-		// PriorityOrdered,

+		// Do not initialize FactoryBeans here: We need to leave all regular beans

+		// uninitialized to let the bean factory post-processors apply to them!

+		String[] postProcessorNames =

+				beanFactory.getBeanNamesForType(include, true, false);

+

+		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,

 		// Ordered, and the rest.

 		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();

 		List<String> orderedPostProcessorNames = new ArrayList<String>();

 		List<String> nonOrderedPostProcessorNames = new ArrayList<String>();

-		for (int i = 0; i < postProcessorNames.length; i++) {

-			// first check the excluded type

-			if (exclude == null || !isTypeMatch(postProcessorNames[i], exclude)) {

-				if (isTypeMatch(postProcessorNames[i], PriorityOrdered.class)) {

-					priorityOrderedPostProcessors.add(beanFactory.getBean(postProcessorNames[i],

-							BeanFactoryPostProcessor.class));

-				} else if (isTypeMatch(postProcessorNames[i], Ordered.class)) {

-					orderedPostProcessorNames.add(postProcessorNames[i]);

-				} else {

-					nonOrderedPostProcessorNames.add(postProcessorNames[i]);

-				}

+		for (String ppName : postProcessorNames) {

+			if (processedBeans.contains(ppName)) {

+				// skip - already processed in first phase above

+			}

+			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {

+				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, include));

+			}

+			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {

+				orderedPostProcessorNames.add(ppName);

+			}

+			else {

+				nonOrderedPostProcessorNames.add(ppName);

 			}

 		}

 

-		// First, invoke the BeanFactoryPostProcessors that implement

-		// PriorityOrdered.

-		Collections.sort(priorityOrderedPostProcessors, new OrderComparator());

-		invokeBeanFactoryPostProcessors(beanFactory, priorityOrderedPostProcessors);

+		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.

+		sortPostProcessors(beanFactory, priorityOrderedPostProcessors);

+		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

 

 		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.

 		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();

-		for (Iterator<String> it = orderedPostProcessorNames.iterator(); it.hasNext();) {

-			String postProcessorName = it.next();

-			orderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class));

+		for (String postProcessorName : orderedPostProcessorNames) {

+			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, include));

 		}

-		Collections.sort(orderedPostProcessors, new OrderComparator());

-		invokeBeanFactoryPostProcessors(beanFactory, orderedPostProcessors);

+		sortPostProcessors(beanFactory, orderedPostProcessors);

+		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

 

 		// Finally, invoke all other BeanFactoryPostProcessors.

 		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();

-		for (Iterator<String> it = nonOrderedPostProcessorNames.iterator(); it.hasNext();) {

-			String postProcessorName = it.next();

-			nonOrderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class));

+		for (String postProcessorName : nonOrderedPostProcessorNames) {

+			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, include));

 		}

-		invokeBeanFactoryPostProcessors(beanFactory, nonOrderedPostProcessors);

+		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

+

+		// Clear cached merged bean definitions since the post-processors might have

+		// modified the original metadata, e.g. replacing placeholders in values...

+		beanFactory.clearMetadataCache();

+	}

+

+	private boolean isExcluded(Class<? extends BeanFactoryPostProcessor> include, Class<? extends BeanFactoryPostProcessor> exclude, BeanFactoryPostProcessor postProcessor) {

+		return !include.isInstance(postProcessor) || exclude != null && !exclude.isInstance(postProcessor);

 	}

 

 	/**

-	 * Invoke given post processors.

-	 * 

-	 * @param beanFactory

-	 * @param postProcessors

+	 * Invoke the given BeanDefinitionRegistryPostProcessor beans.

 	 */

-	private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory,

-			List<BeanFactoryPostProcessor> postProcessors) {

+	private static void invokeBeanDefinitionRegistryPostProcessors(

+			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

 

-		for (BeanFactoryPostProcessor beanFactoryPostProcessor : postProcessors) {

-			beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);

+		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {

+			postProcessor.postProcessBeanDefinitionRegistry(registry);

 		}

 	}

 

+	/**

+	 * Invoke the given BeanFactoryPostProcessor beans.

+	 */

+	private static void invokeBeanFactoryPostProcessors(

+			Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

+

+		for (BeanFactoryPostProcessor postProcessor : postProcessors) {

+			postProcessor.postProcessBeanFactory(beanFactory);

+		}

+	}

+

+	private static void sortPostProcessors(ConfigurableListableBeanFactory beanFactory, List<?> postProcessors) {

+		Comparator<Object> comparatorToUse = null;

+		if (beanFactory instanceof DefaultListableBeanFactory) {

+			comparatorToUse = ((DefaultListableBeanFactory) beanFactory).getDependencyComparator();

+		}

+		if (comparatorToUse == null) {

+			comparatorToUse = OrderComparator.INSTANCE;

+		}

+		Collections.sort(postProcessors, comparatorToUse);

+	}

+

 	// customized to handle DependencyInitializationAwareBeanPostProcessor

 	// classes

 	protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {

diff --git a/core/src/test/java/org/eclipse/gemini/blueprint/blueprint/config/TypeConverterTest.java b/core/src/test/java/org/eclipse/gemini/blueprint/blueprint/config/TypeConverterTest.java
index e90c358..6b2db96 100644
--- a/core/src/test/java/org/eclipse/gemini/blueprint/blueprint/config/TypeConverterTest.java
+++ b/core/src/test/java/org/eclipse/gemini/blueprint/blueprint/config/TypeConverterTest.java
@@ -29,10 +29,9 @@
 import org.springframework.core.io.ClassPathResource;

 import org.springframework.util.ObjectUtils;

 

-import java.util.Collection;

 import java.util.List;

 

-import static org.fest.assertions.Assertions.assertThat;

+import static org.assertj.core.api.Assertions.assertThat;

 

 /**

  * @author Costin Leau

diff --git a/core/src/test/java/org/eclipse/gemini/blueprint/service/OsgiFilterUtilsTest.java b/core/src/test/java/org/eclipse/gemini/blueprint/service/OsgiFilterUtilsTest.java
index 1cd64f8..05fa1e1 100644
--- a/core/src/test/java/org/eclipse/gemini/blueprint/service/OsgiFilterUtilsTest.java
+++ b/core/src/test/java/org/eclipse/gemini/blueprint/service/OsgiFilterUtilsTest.java
@@ -20,9 +20,9 @@
 

 import junit.framework.TestCase;

 

+import org.assertj.core.api.Assertions;

 import org.eclipse.gemini.blueprint.mock.MockServiceReference;

 import org.eclipse.gemini.blueprint.util.OsgiFilterUtils;

-import org.fest.assertions.Assertions;

 import org.osgi.framework.BundleContext;

 import org.osgi.framework.Constants;

 import org.osgi.framework.Filter;

diff --git a/core/src/test/java/org/eclipse/gemini/blueprint/util/SimpleLoggerTest.java b/core/src/test/java/org/eclipse/gemini/blueprint/util/SimpleLoggerTest.java
index 526a680..7c4b41b 100644
--- a/core/src/test/java/org/eclipse/gemini/blueprint/util/SimpleLoggerTest.java
+++ b/core/src/test/java/org/eclipse/gemini/blueprint/util/SimpleLoggerTest.java
@@ -22,7 +22,7 @@
 

 import java.io.PrintStream;

 

-import static org.fest.assertions.Assertions.assertThat;

+import static org.assertj.core.api.Assertions.assertThat;

 import static org.mockito.Matchers.eq;

 import static org.mockito.Mockito.never;

 import static org.mockito.Mockito.verify;

diff --git a/integration-tests/tests/src/test/java/org/eclipse/gemini/blueprint/iandt/postprocessors/BeanDefinitionRegistryPostProcessorTest.java b/integration-tests/tests/src/test/java/org/eclipse/gemini/blueprint/iandt/postprocessors/BeanDefinitionRegistryPostProcessorTest.java
new file mode 100644
index 0000000..881d712
--- /dev/null
+++ b/integration-tests/tests/src/test/java/org/eclipse/gemini/blueprint/iandt/postprocessors/BeanDefinitionRegistryPostProcessorTest.java
@@ -0,0 +1,196 @@
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution. 
+ * The Eclipse Public License is available at 
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses. 
+ *
+ * Contributors:
+ *   VMware Inc.
+ *****************************************************************************/
+
+package org.eclipse.gemini.blueprint.iandt.postprocessors;
+
+import org.eclipse.gemini.blueprint.iandt.BaseIntegrationTest;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
+import org.springframework.core.Ordered;
+import org.springframework.core.PriorityOrdered;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;
+
+/**
+ * Tests application of ordered and unordered {@link BeanDefinitionRegistryPostProcessor} and {@link BeanFactoryPostProcessor}.
+ *
+ * @author Olaf Otto
+ */
+public class BeanDefinitionRegistryPostProcessorTest extends BaseIntegrationTest {
+    private static ThreadLocal<List<String>> INVOCATION_TRACKER = ThreadLocal.withInitial(ArrayList::new);
+
+    public static class DefinitionPostProcessor implements BeanDefinitionRegistryPostProcessor {
+        @Override
+        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
+            INVOCATION_TRACKER.get().add("DefinitionPostProcessor.postProcessBeanDefinitionRegistry");
+            registry.registerBeanDefinition("DefinitionPostProcessorChild", genericBeanDefinition(CustomPostProcessor.class).getBeanDefinition());
+        }
+
+        @Override
+        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+            INVOCATION_TRACKER.get().add("DefinitionPostProcessor.postProcessBeanFactory");
+        }
+
+        public static class CustomPostProcessor implements BeanDefinitionRegistryPostProcessor {
+            @Override
+            public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
+                INVOCATION_TRACKER.get().add("DefinitionPostProcessorChild.postProcessBeanDefinitionRegistry");
+                registry.registerBeanDefinition("DefinitionPostProcessorChildChild", genericBeanDefinition(ArrayList.class).getBeanDefinition());
+            }
+
+            @Override
+            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+                INVOCATION_TRACKER.get().add("DefinitionPostProcessorChild.postProcessBeanFactory");
+            }
+        }
+    }
+
+    public static class DefinitionPostProcessorWithPriorityOrder2 implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
+        @Override
+        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
+            INVOCATION_TRACKER.get().add("DefinitionPostProcessorWithPriorityOrder2.postProcessBeanDefinitionRegistry");
+            registry.registerBeanDefinition("DefinitionPostProcessorWithPriorityOrder2Child", genericBeanDefinition(CustomPostProcessor.class).getBeanDefinition());
+        }
+
+        @Override
+        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+            INVOCATION_TRACKER.get().add("DefinitionPostProcessorWithPriorityOrder2.postProcessBeanFactory");
+        }
+
+        @Override
+        public int getOrder() {
+            return 2;
+        }
+
+        public static class CustomPostProcessor implements BeanDefinitionRegistryPostProcessor {
+            @Override
+            public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
+                INVOCATION_TRACKER.get().add("DefinitionPostProcessorWithPriorityOrder2Child.postProcessBeanDefinitionRegistry");
+                registry.registerBeanDefinition("DefinitionPostProcessorWithPriorityOrder2ChildChild", genericBeanDefinition(ArrayList.class).getBeanDefinition());
+            }
+
+            @Override
+            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+                INVOCATION_TRACKER.get().add("DefinitionPostProcessorWithPriorityOrder2Child.postProcessBeanFactory");
+            }
+        }
+    }
+
+    public static class DefinitionPostProcessorWithOrder2 implements BeanDefinitionRegistryPostProcessor, Ordered {
+        @Override
+        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
+            INVOCATION_TRACKER.get().add("DefinitionPostProcessorWithOrder2.postProcessBeanDefinitionRegistry");
+            registry.registerBeanDefinition("DefinitionPostProcessorWithOrder2Child", genericBeanDefinition(CustomPostProcessor.class).getBeanDefinition());
+        }
+
+        @Override
+        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+            INVOCATION_TRACKER.get().add("DefinitionPostProcessorWithOrder2.postProcessBeanFactory");
+        }
+
+        @Override
+        public int getOrder() {
+            return 2;
+        }
+
+        public static class CustomPostProcessor implements BeanDefinitionRegistryPostProcessor {
+            @Override
+            public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
+                INVOCATION_TRACKER.get().add("DefinitionPostProcessorWithOrder2Child.postProcessBeanDefinitionRegistry");
+                registry.registerBeanDefinition("DefinitionPostProcessorWithOrder2Child", genericBeanDefinition(ArrayList.class).getBeanDefinition());
+            }
+
+            @Override
+            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+                INVOCATION_TRACKER.get().add("DefinitionPostProcessorWithOrder2Child.postProcessBeanFactory");
+            }
+        }
+    }
+
+    public static class RegularPostProcessor implements BeanFactoryPostProcessor {
+        @Override
+        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+            INVOCATION_TRACKER.get().add("RegularPostProcessor.postProcessBeanFactory");
+        }
+    }
+
+
+    public static class RegularPostProcessorWithPriorityOrder2 implements BeanFactoryPostProcessor, PriorityOrdered {
+        @Override
+        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+            INVOCATION_TRACKER.get().add("RegularPostProcessorWithPriorityOrder2.postProcessBeanFactory");
+        }
+
+        @Override
+        public int getOrder() {
+            return 2;
+        }
+    }
+
+
+    public static class RegularPostProcessorWithOrder2 implements BeanFactoryPostProcessor, Ordered {
+        @Override
+        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+            INVOCATION_TRACKER.get().add("RegularPostProcessorWithOrder2.postProcessBeanFactory");
+        }
+
+        @Override
+        public int getOrder() {
+            return 2;
+        }
+    }
+
+
+    protected String getManifestLocation() {
+        return null;
+    }
+
+    protected String[] getConfigLocations() {
+        return new String[]{"/org/eclipse/gemini/blueprint/iandt/postprocessors/postprocessors.xml"};
+    }
+
+    public void testOrderOfRegistryAndFactoryPostProcessorInvocations() throws Exception {
+        List<String> trackedInvocations = INVOCATION_TRACKER.get();
+
+        assertThat(trackedInvocations).containsExactly(
+                // Registry post processors must be executed first as they may alter the registry itself
+                // The initial registry post-processors are ordered and must come first.
+                "DefinitionPostProcessorWithPriorityOrder2.postProcessBeanDefinitionRegistry",
+                "DefinitionPostProcessorWithOrder2.postProcessBeanDefinitionRegistry",
+                "DefinitionPostProcessor.postProcessBeanDefinitionRegistry",
+                "DefinitionPostProcessorWithPriorityOrder2Child.postProcessBeanDefinitionRegistry",
+                "DefinitionPostProcessorWithOrder2Child.postProcessBeanDefinitionRegistry",
+                "DefinitionPostProcessorChild.postProcessBeanDefinitionRegistry",
+
+                // Factory post processing must be executed after the registry was processed.
+                // The initial factory post-processors are ordered and must come first.
+                "DefinitionPostProcessorWithPriorityOrder2.postProcessBeanFactory",
+                "DefinitionPostProcessorWithOrder2.postProcessBeanFactory",
+                "DefinitionPostProcessor.postProcessBeanFactory",
+                "DefinitionPostProcessorWithPriorityOrder2Child.postProcessBeanFactory",
+                "DefinitionPostProcessorWithOrder2Child.postProcessBeanFactory",
+                "DefinitionPostProcessorChild.postProcessBeanFactory",
+                "RegularPostProcessorWithPriorityOrder2.postProcessBeanFactory",
+                "RegularPostProcessorWithOrder2.postProcessBeanFactory",
+                "RegularPostProcessor.postProcessBeanFactory"
+        );
+    }
+}
diff --git a/integration-tests/tests/src/test/resources/org/eclipse/gemini/blueprint/iandt/postprocessors/postprocessors.xml b/integration-tests/tests/src/test/resources/org/eclipse/gemini/blueprint/iandt/postprocessors/postprocessors.xml
new file mode 100644
index 0000000..86697be
--- /dev/null
+++ b/integration-tests/tests/src/test/resources/org/eclipse/gemini/blueprint/iandt/postprocessors/postprocessors.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
+
+    <!-- These post processors can alter the registry itself, e.g. contribute new bean definitions -->
+    <bean id="registryPostProcessorUnordered"
+          class="org.eclipse.gemini.blueprint.iandt.postprocessors.BeanDefinitionRegistryPostProcessorTest$DefinitionPostProcessor" />
+    <bean id="registryPostProcessorPriorityOrdered"
+          class="org.eclipse.gemini.blueprint.iandt.postprocessors.BeanDefinitionRegistryPostProcessorTest$DefinitionPostProcessorWithPriorityOrder2" />
+    <bean id="registryPostProcessorOrdered"
+          class="org.eclipse.gemini.blueprint.iandt.postprocessors.BeanDefinitionRegistryPostProcessorTest$DefinitionPostProcessorWithOrder2" />
+
+
+    <!-- These post processors can the factory itself -->
+    <bean id="factoryPostProcessorUnordered"
+          class="org.eclipse.gemini.blueprint.iandt.postprocessors.BeanDefinitionRegistryPostProcessorTest$RegularPostProcessor" />
+    <bean id="factoryPostProcessorPriorityOrdered"
+          class="org.eclipse.gemini.blueprint.iandt.postprocessors.BeanDefinitionRegistryPostProcessorTest$RegularPostProcessorWithPriorityOrder2" />
+    <bean id="factoryPostProcessorOrdered"
+          class="org.eclipse.gemini.blueprint.iandt.postprocessors.BeanDefinitionRegistryPostProcessorTest$RegularPostProcessorWithOrder2" />
+
+</beans>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 2060faf..988bc9f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -334,9 +334,9 @@
         </dependency>
 
         <dependency>
-            <groupId>org.easytesting</groupId>
-            <artifactId>fest-assert</artifactId>
-            <version>1.4</version>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>3.6.2</version>
             <scope>test</scope>
         </dependency>
 
diff --git a/test-support/bnd.bnd b/test-support/bnd.bnd
index d1a6186..4acc4ed 100644
--- a/test-support/bnd.bnd
+++ b/test-support/bnd.bnd
@@ -2,6 +2,10 @@
  !*.internal.*, \
  org.eclipse.gemini.blueprint.test.*;version=${project.version}
 
+Private-Package: \
+ org.eclipse.gemini.blueprint.test.*, \
+ org.objectweb.*
+
 Import-Package: \
  !org.eclipse.gemini.blueprint.extender.internal.*, \
  !org.eclipse.gemini.blueprint.extender.support.internal.*, \
@@ -10,7 +14,6 @@
  org.apache.commons.logging.*;version=${logging.version.range}, \
  org.eclipse.gemini.blueprint.*;version=${gemini.blueprint.version.range}, \
  org.springframework.*;version=${spring.version.range}, \
- org.objectweb.*;version="[2,3)";resolution:=optional, \
  org.eclipse.*;resolution:=optional, \
  org.knopflerfish.*;resolution:=optional, \
  org.apache.felix.*;resolution:=optional, \
diff --git a/test-support/pom.xml b/test-support/pom.xml
index 26de111..42efb62 100644
--- a/test-support/pom.xml
+++ b/test-support/pom.xml
@@ -44,9 +44,9 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.servicemix.bundles</groupId>
-            <artifactId>org.apache.servicemix.bundles.asm</artifactId>
-            <version>2.2.3_1</version>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm-all</artifactId>
+            <version>5.2</version>
         </dependency>
 
         <dependency>
diff --git a/test-support/src/main/java/org/eclipse/gemini/blueprint/test/AbstractConfigurableOsgiTests.java b/test-support/src/main/java/org/eclipse/gemini/blueprint/test/AbstractConfigurableOsgiTests.java
index e5b9dbe..9cea66c 100644
--- a/test-support/src/main/java/org/eclipse/gemini/blueprint/test/AbstractConfigurableOsgiTests.java
+++ b/test-support/src/main/java/org/eclipse/gemini/blueprint/test/AbstractConfigurableOsgiTests.java
@@ -174,6 +174,8 @@
 		defaults.add("sun.*");
 		defaults.add("com.sun.*");
 
+		defaults.add("org.objectweb.*");
+
 		// FIXME: the JAXP package (for 1.4 VMs) should be discovered in an OSGi manner
 		defaults.add("org.apache.xerces.jaxp.*");
 		return defaults;
diff --git a/test-support/src/main/java/org/eclipse/gemini/blueprint/test/AbstractOnTheFlyBundleCreatorTests.java b/test-support/src/main/java/org/eclipse/gemini/blueprint/test/AbstractOnTheFlyBundleCreatorTests.java
index cd48554..e8cdf6c 100644
--- a/test-support/src/main/java/org/eclipse/gemini/blueprint/test/AbstractOnTheFlyBundleCreatorTests.java
+++ b/test-support/src/main/java/org/eclipse/gemini/blueprint/test/AbstractOnTheFlyBundleCreatorTests.java
@@ -494,7 +494,7 @@
 		} catch (Exception ex) {
 			throw (RuntimeException) new IllegalArgumentException("Cannot read class " + className).initCause(ex);
 		}
-		reader.accept(visitor, false);
+		reader.accept(visitor, 0);
 
 		// convert from / to . format
 		Set originalPackages = visitor.getPackages();
diff --git a/test-support/src/main/java/org/eclipse/gemini/blueprint/test/internal/util/DependencyVisitor.java b/test-support/src/main/java/org/eclipse/gemini/blueprint/test/internal/util/DependencyVisitor.java
index d8d6b81..0686604 100644
--- a/test-support/src/main/java/org/eclipse/gemini/blueprint/test/internal/util/DependencyVisitor.java
+++ b/test-support/src/main/java/org/eclipse/gemini/blueprint/test/internal/util/DependencyVisitor.java
@@ -49,14 +49,7 @@
 import java.util.Map;

 import java.util.Set;

 

-import org.objectweb.asm.AnnotationVisitor;

-import org.objectweb.asm.Attribute;

-import org.objectweb.asm.ClassVisitor;

-import org.objectweb.asm.FieldVisitor;

-import org.objectweb.asm.Label;

-import org.objectweb.asm.MethodVisitor;

-import org.objectweb.asm.Opcodes;

-import org.objectweb.asm.Type;

+import org.objectweb.asm.*;

 import org.objectweb.asm.signature.SignatureReader;

 import org.objectweb.asm.signature.SignatureVisitor;

 

@@ -70,7 +63,329 @@
  * 

  * @author Costin Leau

  */

-public class DependencyVisitor implements AnnotationVisitor, SignatureVisitor, ClassVisitor, FieldVisitor, MethodVisitor {

+public class DependencyVisitor extends ClassVisitor {

+

+	private final AnnotationVisitor av = new AnnotationVisitor(Opcodes.ASM5) {

+			@Override

+			public void visit(String name, Object value) {

+				DependencyVisitor.this.visit(name, value);

+			}

+

+			@Override

+			public void visitEnum(String name, String desc, String value) {

+				DependencyVisitor.this.visitEnum(name, desc, value);

+			}

+

+			@Override

+			public AnnotationVisitor visitAnnotation(String name, String desc) {

+				return DependencyVisitor.this.visitAnnotation(name, desc);

+			}

+

+			@Override

+			public AnnotationVisitor visitArray(String name) {

+				return DependencyVisitor.this.visitArray(name);

+			}

+

+			@Override

+			public void visitEnd() {

+				DependencyVisitor.this.visitEnd();

+			}

+	};

+

+	private final SignatureVisitor sv = new SignatureVisitor(Opcodes.ASM5) {

+		@Override

+		public void visitFormalTypeParameter(String name) {

+			DependencyVisitor.this.visitFormalTypeParameter(name);

+		}

+

+		@Override

+		public SignatureVisitor visitClassBound() {

+			return DependencyVisitor.this.visitClassBound();

+		}

+

+		@Override

+		public SignatureVisitor visitInterfaceBound() {

+			return DependencyVisitor.this.visitInterfaceBound();

+		}

+

+		@Override

+		public SignatureVisitor visitSuperclass() {

+			return DependencyVisitor.this.visitSuperclass();

+		}

+

+		@Override

+		public SignatureVisitor visitInterface() {

+			return DependencyVisitor.this.visitInterface();

+		}

+

+		@Override

+		public SignatureVisitor visitParameterType() {

+			return DependencyVisitor.this.visitParameterType();

+		}

+

+		@Override

+		public SignatureVisitor visitReturnType() {

+			return DependencyVisitor.this.visitReturnType();

+		}

+

+		@Override

+		public SignatureVisitor visitExceptionType() {

+			return DependencyVisitor.this.visitExceptionType();

+		}

+

+		@Override

+		public void visitBaseType(char descriptor) {

+			DependencyVisitor.this.visitBaseType(descriptor);

+		}

+

+		@Override

+		public void visitTypeVariable(String name) {

+			DependencyVisitor.this.visitTypeVariable(name);

+		}

+

+		@Override

+		public SignatureVisitor visitArrayType() {

+			return DependencyVisitor.this.visitArrayType();

+		}

+

+		@Override

+		public void visitClassType(String name) {

+			DependencyVisitor.this.visitClassType(name);

+		}

+

+		@Override

+		public void visitInnerClassType(String name) {

+			DependencyVisitor.this.visitInnerClassType(name);

+		}

+

+		@Override

+		public void visitTypeArgument() {

+			DependencyVisitor.this.visitTypeArgument();

+		}

+

+		@Override

+		public SignatureVisitor visitTypeArgument(char wildcard) {

+			return DependencyVisitor.this.visitTypeArgument(wildcard);

+		}

+

+		@Override

+		public void visitEnd() {

+			DependencyVisitor.this.visitEnd();

+		}

+	};

+

+	private final FieldVisitor fv = new FieldVisitor(Opcodes.ASM5) {

+		@Override

+		public AnnotationVisitor visitAnnotation(String desc, boolean visible) {

+			return DependencyVisitor.this.visitAnnotation(desc, visible);

+		}

+

+		@Override

+		public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {

+			return DependencyVisitor.this.visitTypeAnnotation(typeRef, typePath, desc, visible);

+		}

+

+		@Override

+		public void visitAttribute(Attribute attr) {

+			DependencyVisitor.this.visitAttribute(attr);

+		}

+

+		@Override

+		public void visitEnd() {

+			DependencyVisitor.this.visitEnd();

+		}

+	};

+

+	private final MethodVisitor mv = new MethodVisitor(Opcodes.ASM5) {

+		@Override

+		public void visitParameter(String name, int access) {

+			DependencyVisitor.this.visitParameter(name, access);

+		}

+

+		@Override

+		public AnnotationVisitor visitAnnotationDefault() {

+			return DependencyVisitor.this.visitAnnotationDefault();

+		}

+

+		@Override

+		public AnnotationVisitor visitAnnotation(String desc, boolean visible) {

+			return DependencyVisitor.this.visitAnnotation(desc, visible);

+		}

+

+		@Override

+		public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {

+			return DependencyVisitor.this.visitTypeAnnotation(typeRef, typePath, desc, visible);

+		}

+

+		@Override

+		public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {

+			return DependencyVisitor.this.visitParameterAnnotation(parameter, desc, visible);

+		}

+

+		@Override

+		public void visitAttribute(Attribute attr) {

+			DependencyVisitor.this.visitAttribute(attr);

+		}

+

+		@Override

+		public void visitCode() {

+			DependencyVisitor.this.visitCode();

+		}

+

+		@Override

+		public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {

+			DependencyVisitor.this.visitFrame(type, nLocal, local, nStack, stack);

+		}

+

+		@Override

+		public void visitInsn(int opcode) {

+			DependencyVisitor.this.visitInsn(opcode);

+		}

+

+		@Override

+		public void visitIntInsn(int opcode, int operand) {

+			DependencyVisitor.this.visitIntInsn(opcode, operand);

+		}

+

+		@Override

+		public void visitVarInsn(int opcode, int var) {

+			DependencyVisitor.this.visitVarInsn(opcode, var);

+		}

+

+		@Override

+		public void visitTypeInsn(int opcode, String type) {

+			DependencyVisitor.this.visitTypeInsn(opcode, type);

+		}

+

+		@Override

+		public void visitFieldInsn(int opcode, String owner, String name, String desc) {

+			DependencyVisitor.this.visitFieldInsn(opcode, owner, name, desc);

+		}

+

+		@Override

+		public void visitMethodInsn(int opcode, String owner, String name, String desc) {

+			DependencyVisitor.this.visitMethodInsn(opcode, owner, name, desc, false);

+		}

+

+		@Override

+		public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {

+			DependencyVisitor.this.visitMethodInsn(opcode, owner, name, desc, itf);

+		}

+

+		@Override

+		public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {

+			DependencyVisitor.this.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);

+		}

+

+		@Override

+		public void visitJumpInsn(int opcode, Label label) {

+			DependencyVisitor.this.visitJumpInsn(opcode, label);

+		}

+

+		@Override

+		public void visitLabel(Label label) {

+			DependencyVisitor.this.visitLabel(label);

+		}

+

+		@Override

+		public void visitLdcInsn(Object cst) {

+			DependencyVisitor.this.visitLdcInsn(cst);

+		}

+

+		@Override

+		public void visitIincInsn(int var, int increment) {

+			DependencyVisitor.this.visitIincInsn(var, increment);

+		}

+

+		@Override

+		public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {

+			DependencyVisitor.this.visitTableSwitchInsn(min, max, dflt, labels);

+		}

+

+		@Override

+		public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {

+			DependencyVisitor.this.visitLookupSwitchInsn(dflt, keys, labels);

+		}

+

+		@Override

+		public void visitMultiANewArrayInsn(String desc, int dims) {

+			DependencyVisitor.this.visitMultiANewArrayInsn(desc, dims);

+		}

+

+		@Override

+		public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {

+			return DependencyVisitor.this.visitInsnAnnotation(typeRef, typePath, desc, visible);

+		}

+

+		@Override

+		public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {

+			DependencyVisitor.this.visitTryCatchBlock(start, end, handler, type);

+		}

+

+		@Override

+		public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {

+			return DependencyVisitor.this.visitTryCatchAnnotation(typeRef, typePath, desc, visible);

+		}

+

+		@Override

+		public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {

+			DependencyVisitor.this.visitLocalVariable(name, desc, signature, start, end, index);

+		}

+

+		@Override

+		public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {

+			return DependencyVisitor.this.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible);

+		}

+

+		@Override

+		public void visitLineNumber(int line, Label start) {

+			DependencyVisitor.this.visitLineNumber(line, start);

+		}

+

+		@Override

+		public void visitMaxs(int maxStack, int maxLocals) {

+			DependencyVisitor.this.visitMaxs(maxStack, maxLocals);

+		}

+

+		@Override

+		public void visitEnd() {

+			DependencyVisitor.this.visitEnd();

+		}

+	};

+

+	public DependencyVisitor() {

+		super(Opcodes.ASM5);

+	}

+

+	private AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {

+		tempLdc = null;

+		addDesc(desc);

+		return this.av;

+	}

+

+	private AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {

+		tempLdc = null;

+		addDesc(desc);

+		return this.av;

+	}

+

+	private AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {

+		tempLdc = null;

+		addDesc(desc);

+		return this.av;

+	}

+

+	private void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object[] bsmArgs) {

+		for (Object o : bsmArgs) {

+			if (o instanceof Type) {

+				addType((Type) o);

+			}

+		}

+	}

+

+	private void visitParameter(String name, int access) {

+		tempLdc = null;

+	}

 

 	private Set packages = new LinkedHashSet();

 

@@ -120,7 +435,7 @@
 	public AnnotationVisitor visitAnnotation(String desc, boolean visible) {

 		tempLdc = null;

 		addDesc(desc);

-		return this;

+		return this.av;

 	}

 

 	public void visitAttribute(Attribute attr) {

@@ -136,7 +451,7 @@
 		}

 		if (value instanceof Type)

 			addType((Type) value);

-		return this;

+		return fv;

 	}

 

 	public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

@@ -147,7 +462,7 @@
 			addSignature(signature);

 		}

 		addNames(exceptions);

-		return this;

+		return mv;

 	}

 

 	public void visitSource(String source, String debug) {

@@ -176,7 +491,7 @@
 	public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {

 		tempLdc = null;

 		addDesc(desc);

-		return this;

+		return this.av;

 	}

 

 	public void visitTypeInsn(int opcode, String desc) {

@@ -193,7 +508,7 @@
 		addDesc(desc);

 	}

 

-	public void visitMethodInsn(int opcode, String owner, String name, String desc) {

+	public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {

 		String returnType = Type.getReturnType(desc).getClassName();

 		if (opcode == Opcodes.INVOKESTATIC && CLASS_NAME.equals(returnType)) {

 			if (tempLdc != null)

@@ -227,13 +542,17 @@
 

 	public AnnotationVisitor visitAnnotationDefault() {

 		tempLdc = null;

-		return this;

+		return av;

 	}

 

 	public void visitCode() {

 		tempLdc = null;

 	}

 

+	public void visitFrame(int i, int i1, Object[] objects, int i2, Object[] objects1) {

+		tempLdc = null;

+	}

+

 	public void visitInsn(int opcode) {

 		tempLdc = null;

 	}

@@ -295,12 +614,12 @@
 	public AnnotationVisitor visitAnnotation(String name, String desc) {

 		tempLdc = null;

 		addDesc(desc);

-		return this;

+		return this.av;

 	}

 

 	public AnnotationVisitor visitArray(String name) {

 		tempLdc = null;

-		return this;

+		return this.av;

 	}

 

 	// SignatureVisitor

@@ -311,37 +630,37 @@
 

 	public SignatureVisitor visitClassBound() {

 		tempLdc = null;

-		return this;

+		return sv;

 	}

 

 	public SignatureVisitor visitInterfaceBound() {

 		tempLdc = null;

-		return this;

+		return sv;

 	}

 

 	public SignatureVisitor visitSuperclass() {

 		tempLdc = null;

-		return this;

+		return sv;

 	}

 

 	public SignatureVisitor visitInterface() {

 		tempLdc = null;

-		return this;

+		return sv;

 	}

 

 	public SignatureVisitor visitParameterType() {

 		tempLdc = null;

-		return this;

+		return sv;

 	}

 

 	public SignatureVisitor visitReturnType() {

 		tempLdc = null;

-		return this;

+		return sv;

 	}

 

 	public SignatureVisitor visitExceptionType() {

 		tempLdc = null;

-		return this;

+		return sv;

 	}

 

 	public void visitBaseType(char descriptor) {

@@ -354,7 +673,7 @@
 

 	public SignatureVisitor visitArrayType() {

 		tempLdc = null;

-		return this;

+		return sv;

 	}

 

 	public void visitClassType(String name) {

@@ -373,7 +692,7 @@
 

 	public SignatureVisitor visitTypeArgument(char wildcard) {

 		tempLdc = null;

-		return this;

+		return sv;

 	}

 

 	// common

@@ -432,11 +751,11 @@
 

 	private void addSignature(String signature) {

 		if (signature != null)

-			new SignatureReader(signature).accept(this);

+			new SignatureReader(signature).accept(this.sv);

 	}

 

 	private void addTypeSignature(String signature) {

 		if (signature != null)

-			new SignatureReader(signature).acceptType(this);

+			new SignatureReader(signature).acceptType(this.sv);

 	}

 }
\ No newline at end of file
diff --git a/test-support/src/main/resources/org/eclipse/gemini/blueprint/test/internal/boot-bundles.properties b/test-support/src/main/resources/org/eclipse/gemini/blueprint/test/internal/boot-bundles.properties
index 1ac44e9..42ddcc7 100644
--- a/test-support/src/main/resources/org/eclipse/gemini/blueprint/test/internal/boot-bundles.properties
+++ b/test-support/src/main/resources/org/eclipse/gemini/blueprint/test/internal/boot-bundles.properties
@@ -22,7 +22,7 @@
 ignore.spring.version=4.3.6.RELEASE_1
 ignore.gemini.blueprint.version=${project.version}
 ignore.slf4j.version=1.7.5
-ignore.asm.version=2.2.3_1
+ignore.assertj.version=3.6.2
 
 # groupIds
 ignore.servicemix.bundles.groupId=org.apache.servicemix.bundles
@@ -47,8 +47,8 @@
 # aop alliance
 ${ignore.servicemix.bundles.groupId},${ignore.servicemix.bundles.groupId}.aopalliance,1.0_6=
 
-# asm
-org.apache.servicemix.bundles,org.apache.servicemix.bundles.asm,${ignore.asm.version}=
+# AssertJ for using AssertJ-assertions in OSGi test bundles at runtime
+org.assertj,assertj-core,${ignore.assertj.version}=
 
 # spring libs
 ${ignore.servicemix.bundles.groupId},${ignore.servicemix.bundles.groupId}.spring-beans,${ignore.spring.version}=