Fix issue FELIX-2093 : iPOJO doesn't always use the correct class loader to load Nullable classes
This came from the dynamic proxy strange behavior. The proxy don't use the specification classloader to load transitive classes. To fix that, the delegation is made manually.

This commit also update some tests to the latest pax:exam / tinybundle API.



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@912323 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
index c1821de..9bcaf8a 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
@@ -345,9 +345,14 @@
                     // To load the proxy we use the POJO class loader. Indeed, this classloader imports iPOJO (so can access to Nullable) and has
                     // access to the service specification.
                     try {
+                        ClassLoader cl = new NullableClassLoader(
+                                getHandler().getInstanceManager().getClazz().getClassLoader(), 
+                                getSpecification().getClassLoader());
+                        
                         m_nullable =
-                            Proxy.newProxyInstance(getHandler().getInstanceManager().getClazz().getClassLoader(), new Class[] {
+                            Proxy.newProxyInstance(cl, new Class[] {
                                     getSpecification(), Nullable.class }, new NullableObject()); // NOPMD
+                        
                     } catch (NoClassDefFoundError e) {
                         // A NoClassDefFoundError is thrown if the specification uses a class not accessible by the actual instance.
                         // It generally comes from a missing import.
@@ -778,6 +783,50 @@
         setAggregate(true);
         m_type = type;
     }
+    
+    /**
+     * Classloader for nullable objects.
+     */
+    private class NullableClassLoader extends ClassLoader {
+       /**
+        * Component classloader. 
+        */
+        private ClassLoader m_component;
+       
+       /**
+        * Specification classloader. 
+        */
+        private ClassLoader m_specification;
+       
+        /**
+         * Creates a NullableClassLoader.
+         * @param cmp the component class loader.
+         * @param spec the specification class loader.
+         */
+        public NullableClassLoader(ClassLoader cmp, ClassLoader spec) {
+            m_component = cmp;
+            m_specification = spec;
+        }
+        
+        /**
+         * Loads the given class.
+         * This method uses the classloader of the component class
+         * and (if not found) the specification classloader.
+         * @param name the class name
+         * @return the class object
+         * @throws ClassNotFoundException if the class is not found by the two classloaders.
+         * @see java.lang.ClassLoader#loadClass(java.lang.String)
+         */
+        public Class loadClass(String name) throws ClassNotFoundException {
+            try {
+                return m_component.loadClass(name);
+            } catch (ClassNotFoundException e) {
+                return m_specification.loadClass(name);
+            }
+        }
+        
+       
+    }
 
     /**
      * Creates smart proxy object for proxied scalar dependencies.
@@ -830,7 +879,7 @@
 
         /**
          * Loads the given class.
-         * This class use the classloader of the specification class
+         * This method uses the classloader of the specification class
          * or the handler class loader.
          * @param name the class name
          * @return the class object
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
index 81ab766..6b6637d 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
@@ -256,7 +256,7 @@
             String type = meta.getFieldType();
             if (type.endsWith("[]")) {
                 if (dep.isProxy()) {
-                    warn("Arrays cannot be used for proxied dependencies - Disable the proxy mode");
+                    info("Arrays cannot be used for proxied dependencies - Disable the proxy mode");
                     dep.setProxy(false);
                 }
                 // Set the dependency to multiple
diff --git a/ipojo/tests/core/factory-version/pom.xml b/ipojo/tests/core/factory-version/pom.xml
index f893e1b..23378ab 100644
--- a/ipojo/tests/core/factory-version/pom.xml
+++ b/ipojo/tests/core/factory-version/pom.xml
@@ -48,60 +48,70 @@
       <version>${pom.version}</version>
     </dependency>
 
-    <!--
+  <!--
     Pax Exam API:
   -->
-    <dependency>
-      <groupId>org.ops4j.pax.exam</groupId>
-      <artifactId>pax-exam</artifactId>
-      <version>1.1.0</version>
-    </dependency>
-    <!--
-      During runtime Pax Exam will discover the OSGi container to use by
-      searching metadata available into classpath. Pax Exam comes with a
-      default container that uses [Pax Runner] for implementing the
-      container requirements:
-    -->
-    <dependency>
-      <groupId>org.ops4j.pax.exam</groupId>
-      <artifactId>pax-exam-container-default
+  <dependency>
+    <groupId>org.ops4j.pax.exam</groupId>
+    <artifactId>pax-exam</artifactId>
+    <version>1.2.0</version>
+  </dependency>
+  <!--
+    During runtime Pax Exam will discover the OSGi container to use by
+    searching metadata available into classpath. Pax Exam comes with a
+    default container that uses [Pax Runner] for implementing the
+    container requirements:
+  -->
+  <dependency>
+    <groupId>org.ops4j.pax.exam</groupId>
+    <artifactId>pax-exam-container-default
     </artifactId>
-      <version>1.1.0</version>
-    </dependency>
-    <!--
-      If your test code is based on JUnit you will have to have the Junit
-      support artifact:
-    -->
-    <dependency>
-      <groupId>org.ops4j.pax.exam</groupId>
-      <artifactId>pax-exam-junit</artifactId>
-      <version>1.1.0</version>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.5</version>
-      <type>jar</type>
-      <scope>test</scope>
-    </dependency>
-    <!--  Tinybundles -->
-    <dependency>
-      <groupId>org.ops4j.pax.swissbox</groupId>
-      <artifactId>pax-swissbox-tinybundles</artifactId>
-      <version>1.0.0</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.felix</groupId>
-      <artifactId>org.apache.felix.ipojo.tinybundles.bundleAsiPOJO
-      </artifactId>
-      <version>${pom.version}</version>
-    </dependency>
+    <version>1.2.0</version>
+  </dependency>
+  <!--
+    If your test code is based on JUnit you will have to have the Junit
+    support artifact:
+  -->
+  <dependency>
+    <groupId>org.ops4j.pax.exam</groupId>
+    <artifactId>pax-exam-junit</artifactId>
+    <version>1.2.0</version>
+  </dependency>
+  <dependency>
+    <groupId>junit</groupId>
+    <artifactId>junit</artifactId>
+    <version>4.5</version>
+    <type>jar</type>
+    <scope>test</scope>
+  </dependency>
+  <!--  Tinybundles -->
+  <dependency>
+    <groupId>org.ops4j.pax.swissbox</groupId>
+    <artifactId>pax-swissbox-tinybundles</artifactId>
+    <version>1.2.0</version>
+  </dependency>
+  <dependency>
+    <groupId>org.apache.felix</groupId>
+    <artifactId>org.apache.felix.ipojo.tinybundles.bundleAsiPOJO</artifactId>
+    <version>${pom.version}</version>
+  </dependency>
 
     <dependency>
       <groupId>org.apache.felix</groupId>
       <artifactId>org.apache.felix.ipojo.test.helpers</artifactId>
       <version>${pom.version}</version>
     </dependency>
+    
+   <dependency>
+    <groupId>org.ops4j.base</groupId>
+    <artifactId>ops4j-base-io</artifactId>
+    <version>1.2.1</version>
+  </dependency>
+  <dependency>
+    <groupId>org.ops4j.base</groupId>
+    <artifactId>ops4j-base-lang</artifactId>
+    <version>1.2.1</version>
+  </dependency>
   </dependencies>
 
   <repositories>
diff --git a/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java
index 7a2ad7d..9c36963 100644
--- a/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java
+++ b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/FactoryVersionTest.java
@@ -8,9 +8,8 @@
 import static org.ops4j.pax.exam.CoreOptions.options;
 import static org.ops4j.pax.exam.CoreOptions.provision;
 import static org.ops4j.pax.exam.MavenUtils.asInProject;
-import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.asURL;
 import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.newBundle;
-import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.with;
+import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.withBnd;
 
 import java.io.File;
 
@@ -31,6 +30,7 @@
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 
 @RunWith( JUnit4TestRunner.class )
@@ -68,45 +68,34 @@
                 provision(
                         // Runtime.
                         mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo").version(asInProject()),
-                        mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo.test.helpers").version(asInProject()),
-                        mavenBundle().groupId( "org.ops4j.pax.swissbox" ).artifactId( "pax-swissbox-tinybundles" ).version(asInProject())
+                        mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo.test.helpers").version(asInProject())
+                        // mavenBundle().groupId( "org.ops4j.pax.swissbox" ).artifactId( "pax-swissbox-tinybundles" ).version(asInProject())
                         ),
                 provision(
                         newBundle()
-                            .addClass( MyService.class )
-                            .prepare()
+                            .add( MyService.class )
                            .set(Constants.BUNDLE_SYMBOLICNAME,"ServiceInterface")
                            .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
-                            .build( asURL() ).toExternalForm()
+                            .build( withBnd() )
                     ),
                provision(
                        // Component V1
                         newBundle()
-                            .addClass(MyComponent.class)
-                            .prepare(
-                                    with()
-                                        .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV1")
-                                        .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
-                                    )
-                            .build( asiPOJOBundle(new File(tmp, "provider-v1.jar"), new File("provider-v1.xml"))).toExternalForm(),
+                            .add(MyComponent.class)
+                            .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV1")
+                            .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
+                            .build( asiPOJOBundle(new File(tmp, "provider-v1.jar"), new File("provider-v1.xml"))),
                      // Component V1.1 (Bundle Version)
                         newBundle()
-                            .addClass(MyComponent.class)
-                            .prepare(
-                                    with()
-                                        .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV1.1")
-                                        .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
-                                        .set(Constants.BUNDLE_VERSION, "1.1")
-                                    )
-                            .build( asiPOJOBundle(new File(tmp, "provider-v1.1.jar"), new File("provider-v1.1.xml"))).toExternalForm(),
+                            .add(MyComponent.class)
+                            .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV1.1")
+                            .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service")
+                            .set(Constants.BUNDLE_VERSION, "1.1")
+                            .build( asiPOJOBundle(new File(tmp, "provider-v1.1.jar"), new File("provider-v1.1.xml"))),
                 // Instance declaration
                 newBundle()
-                    .prepare(
-                            with()
-                                .set(Constants.BUNDLE_SYMBOLICNAME,"Instances")
-                            )
-                    .build( asiPOJOBundle(new File(tmp, "instances.jar"), new File("instances.xml"))).toExternalForm()
-
+                    .set(Constants.BUNDLE_SYMBOLICNAME,"Instances")
+                    .build( asiPOJOBundle(new File(tmp, "instances.jar"), new File("instances.xml")))
                     )
                 );
         return opt;
@@ -157,30 +146,36 @@
     }
 
     @Test
-    public void testServiceProperty() {
+    public void testServiceProperty() throws InvalidSyntaxException {
+          
           // Version 1.0
-          ServiceReference refv1 = ipojo.getServiceReferenceByName(MyService.class.getName(), "instance-v1");
+          //ServiceReference refv1 = ipojo.getServiceReferenceByName(MyService.class.getName(), "instance-v1");
+          ServiceReference[] refv1 = context.getAllServiceReferences(MyService.class.getName(), "(instance.name=instance-v1)");
           Assert.assertNotNull(refv1);
-          String version = (String) refv1.getProperty("factory.version");
+          String version = (String) refv1[0].getProperty("factory.version");
           Assert.assertEquals("1.0", version);
 
           // Version 1.1
-          ServiceReference refv11 = ipojo.getServiceReferenceByName(MyService.class.getName(), "instance-v1.1");
+          ServiceReference[] refv11 = context.getAllServiceReferences(MyService.class.getName(), "(instance.name=instance-v1.1)");          
+          //ServiceReference refv11 = ipojo.getServiceReferenceByName(MyService.class.getName(), "instance-v1.1");
           Assert.assertNotNull(refv11);
-          String version11 = (String) refv11.getProperty("factory.version");
+          String version11 = (String) refv11[0].getProperty("factory.version");
 
           Assert.assertEquals("1.1", version11);
 
           // No Version
-          ServiceReference refany = ipojo.getServiceReferenceByName(MyService.class.getName(), "instance-any");
+          ServiceReference[] refany = context.getAllServiceReferences(MyService.class.getName(), "(instance.name=instance-any)");          
+
+          // ServiceReference refany = ipojo.getServiceReferenceByName(MyService.class.getName(), "instance-any");
           Assert.assertNotNull(refany);
-          String any = (String) refany.getProperty("factory.version");
+          String any = (String) refany[0].getProperty("factory.version");
           Assert.assertNotNull(any);
 
           // No version set in the factory, so no version.
-          ServiceReference refmci = ipojo.getServiceReferenceByName(MyService.class.getName(), "MyComponentInstance");
+          ServiceReference[] refmci = context.getAllServiceReferences(MyService.class.getName(), "(instance.name=MyComponentInstance)");          
+          //ServiceReference refmci = ipojo.getServiceReferenceByName(MyService.class.getName(), "MyComponentInstance");
           Assert.assertNotNull(refmci);
-          String mci = (String) refmci.getProperty("factory.version");
+          String mci = (String) refmci[0].getProperty("factory.version");
           Assert.assertNull(mci);
     }
 
diff --git a/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/VersionConflictTest.java b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/VersionConflictTest.java
index c41737e..9c159dc 100644
--- a/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/VersionConflictTest.java
+++ b/ipojo/tests/core/factory-version/src/test/java/org/apache/felix/ipojo/tests/core/VersionConflictTest.java
@@ -9,11 +9,13 @@
 import static org.ops4j.pax.exam.CoreOptions.provision;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
 import static org.ops4j.pax.exam.MavenUtils.asInProject;
-import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.asFile;
 import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.newBundle;
-import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.with;
+import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.withBnd;
 
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.net.MalformedURLException;
 
 import org.apache.felix.ipojo.architecture.Architecture;
@@ -31,6 +33,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.ops4j.io.StreamUtils;
+import org.ops4j.lang.NullArgumentException;
 import org.ops4j.pax.exam.Inject;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.Configuration;
@@ -68,70 +72,75 @@
 
 
     @Configuration
-    public static Option[] configure() throws MalformedURLException {
+    public static Option[] configure() throws NullArgumentException, FileNotFoundException, IOException {
 
         File tmp = new File("target/tmp");
         tmp.mkdirs();
 
-        String url1 =  // Version 1
-            newBundle()
-            .addClass( MyService.class )
-            .prepare()
-           .set(Constants.BUNDLE_SYMBOLICNAME,"ServiceInterfaceV1")
-           .set(Constants.BUNDLE_VERSION, "1.0.0")
-           .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"1.0.0\"")
-            .build( asFile(new File(tmp, "ServiceInterfaceV1.jar"))).toURL().toExternalForm();
-
-        String url2 = // Version 2
+        File f1 = new File(tmp, "service-interface-v1.jar");
+        StreamUtils.copyStream(
                 newBundle()
-                    .addClass( MyService.class )
-                    .prepare()
-                   .set(Constants.BUNDLE_SYMBOLICNAME,"ServiceInterfaceV2")
-                   .set(Constants.BUNDLE_VERSION, "2.0.0")
-                   .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"2.0.0\"")
-            .build( asFile(new File(tmp, "ServiceInterfaceV2.jar"))).toURL().toExternalForm();
+                .add( MyService.class )
+               .set(Constants.BUNDLE_SYMBOLICNAME,"ServiceInterfaceV1")
+               .set(Constants.BUNDLE_VERSION, "1.0.0")
+               .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"1.0.0\"")
+               .build( withBnd()),
+                new FileOutputStream(f1),
+                true);
+        
+        File f2 = new File(tmp, "service-interface-v2.jar");
+        StreamUtils.copyStream(
+                newBundle()
+                .add( MyService.class )
+                .set(Constants.BUNDLE_SYMBOLICNAME,"ServiceInterfaceV2")
+                .set(Constants.BUNDLE_VERSION, "2.0.0")
+                .set(Constants.EXPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"2.0.0\"")
+                .build( withBnd()),
+                new FileOutputStream(f2),
+                true);
+        
+        File c1 = new File(tmp, "component-v1.jar");
+        StreamUtils.copyStream(
+                newBundle()
+               .add(MyComponent.class)
+               .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV1")
+               .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"[1.0.0, 1.0.0]\"")
+               .build( asiPOJOBundle(new File("vprovider-v1.xml"))),
+               new FileOutputStream(c1),
+               true);
 
+        File c2 = new File(tmp, "component-v2.jar");
+        StreamUtils.copyStream(
+                newBundle()
+               .add(MyComponent.class)
+               .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV2")
+               .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"[2.0.0, 2.0.0]\"")
+               .build( asiPOJOBundle(new File("vprovider-v2.xml"))),
+               new FileOutputStream(c2),
+               true);
 
-        String c1 = newBundle()
-            .addClass(MyComponent.class)
-            .prepare(
-              with()
-                  .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV1")
-                  .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"[1.0.0, 1.0.0]\"")
-              )
-              .build( asiPOJOBundle(new File(tmp, "vprovider-v1.jar"), new File("vprovider-v1.xml"))).toExternalForm();
-
-      String c2 = newBundle()
-          .addClass(MyComponent.class)
-          .prepare(
-              with()
-                  .set(Constants.BUNDLE_SYMBOLICNAME,"ProviderV2")
-                  .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"[2.0.0, 2.0.0]\"")
-                  .set(Constants.BUNDLE_VERSION, "2.0")
-              )
-              .build( asiPOJOBundle(new File(tmp, "vprovider-v2.0.jar"), new File("vprovider-v2.xml"))).toExternalForm();
-
-      String cons =   newBundle()
-        .addClass(MyCons.class)
-        .prepare(
-            with()
-                .set(Constants.BUNDLE_SYMBOLICNAME,"MyCons")
-                .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"[2.0.0, 2.0.0]\"")
-                .set(Constants.BUNDLE_VERSION, "2.0")
-            )
-        .build( asiPOJOBundle(new File(tmp, "cons.jar"), new File("cons.xml"))).toExternalForm();
-
-
-      String consV1 =   newBundle()
-      .addClass(MyCons.class)
-      .prepare(
-          with()
-              .set(Constants.BUNDLE_SYMBOLICNAME,"MyCons")
-              .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"[1.0.0, 1.0.0]\"")
-              .set(Constants.BUNDLE_VERSION, "1.0")
-          )
-      .build( asiPOJOBundle(new File(tmp, "consv1.jar"), new File("cons.xml"))).toExternalForm();
-
+        File cons = new File(tmp, "cons.jar");
+        StreamUtils.copyStream(
+                newBundle()
+               .add(MyCons.class)
+               .set(Constants.BUNDLE_SYMBOLICNAME,"MyCons")
+               .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"[2.0.0, 2.0.0]\"")
+               .set(Constants.BUNDLE_VERSION, "2.0")
+               .build(asiPOJOBundle(new File("cons.xml"))),
+               new FileOutputStream(cons),
+               true);
+        
+        File consV1 = new File(tmp, "cons-v1.jar");
+        StreamUtils.copyStream(
+                newBundle()
+               .add(MyCons.class)
+               .set(Constants.BUNDLE_SYMBOLICNAME,"MyCons")
+               .set(Constants.IMPORT_PACKAGE, "org.apache.felix.ipojo.tests.core.service; version=\"[1.0.0, 1.0.0]\"")
+               .set(Constants.BUNDLE_VERSION, "1.0")
+               .build(asiPOJOBundle(new File("cons.xml"))),
+               new FileOutputStream(consV1),
+               true);
+        
         Option[] opt =  options(
                 felix(),
                 equinox(),
@@ -140,18 +149,16 @@
                         // Runtime.
                         mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo").version(asInProject()),
                         mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo.test.helpers").version(asInProject()),
-                        mavenBundle().groupId( "org.ops4j.pax.swissbox" ).artifactId( "pax-swissbox-tinybundles" ).version(asInProject())
+                        mavenBundle().groupId("org.ops4j.base").artifactId("ops4j-base-lang").versionAsInProject()
+//                        mavenBundle().groupId( "org.ops4j.pax.swissbox" ).artifactId( "pax-swissbox-tinybundles" ).version(asInProject())
                         ),
-                        systemProperty( "url1" ).value( url1 ),
-                        systemProperty( "url2" ).value( url2 ),
+                        systemProperty( "url1" ).value( f1.toURI().toURL().toExternalForm() ),
+                        systemProperty( "url2" ).value( f2.toURI().toURL().toExternalForm() ),
 
-                        systemProperty( "c1" ).value( c1 ),
-                        systemProperty( "c2" ).value( c2 ),
-                        systemProperty( "cons" ).value( cons ),
-                        systemProperty( "consV1" ).value( consV1 )
-
-
-
+                        systemProperty( "c1" ).value( c1.toURI().toURL().toExternalForm() ),
+                        systemProperty( "c2" ).value( c2.toURI().toURL().toExternalForm() ),
+                        systemProperty( "cons" ).value( cons.toURI().toURL().toExternalForm() ),
+                        systemProperty( "consV1" ).value( consV1.toURI().toURL().toExternalForm() )
                 );
         return opt;
     }
diff --git a/ipojo/tests/core/service-dependency-optional/pom.xml b/ipojo/tests/core/service-dependency-optional/pom.xml
new file mode 100644
index 0000000..2bced55
--- /dev/null
+++ b/ipojo/tests/core/service-dependency-optional/pom.xml
@@ -0,0 +1,121 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>ipojo.tests</groupId>
+  <artifactId>tests.core.dependency.optional</artifactId>
+  <name>iPOJO Optional Dependency Test Suite</name>
+  <version>1.5.0-SNAPSHOT</version>
+  <description>Test the optional dependencies</description>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.servicemix.tooling</groupId>
+        <artifactId>depends-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-depends-file</id>
+            <goals>
+              <goal>generate-depends-file</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.ipojo</artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+    <!--
+      <dependency> <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.log</artifactId>
+      <version>1.0.0</version> </dependency>
+    -->
+
+    <!--
+    Pax Exam API:
+    -->
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam</artifactId>
+      <version>1.2.0</version>
+    </dependency>
+    <!--
+      During runtime Pax Exam will discover the OSGi container to use by
+      searching metadata available into classpath. Pax Exam comes with a
+      default container that uses [Pax Runner] for implementing the
+      container requirements:
+    -->
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam-container-default
+    </artifactId>
+      <version>1.2.0</version>
+    </dependency>
+    <!--
+      If your test code is based on JUnit you will have to have the Junit
+      support artifact:
+    -->
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam-junit</artifactId>
+      <version>1.2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.5</version>
+      <type>jar</type>
+      <scope>test</scope>
+    </dependency>
+    <!--  Tinybundles -->
+    <dependency>
+      <groupId>org.ops4j.pax.swissbox</groupId>
+      <artifactId>pax-swissbox-tinybundles</artifactId>
+      <version>1.2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.ipojo.tinybundles.bundleAsiPOJO
+      </artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.ipojo.test.helpers</artifactId>
+      <version>${pom.version}</version>
+    </dependency>
+  </dependencies>
+
+  <repositories>
+    <repository>
+      <id>ops4j.releases</id>
+      <name>OPS4J Release</name>
+      <url> http://repository.ops4j.org/maven2/</url>
+      <releases>
+        <enabled>true</enabled>
+      </releases>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </repository>
+  </repositories>
+
+</project>
diff --git a/ipojo/tests/core/service-dependency-optional/src/main/java/org/apache/felix/ipojo/optional/MyComponent.java b/ipojo/tests/core/service-dependency-optional/src/main/java/org/apache/felix/ipojo/optional/MyComponent.java
new file mode 100644
index 0000000..b7a13ef
--- /dev/null
+++ b/ipojo/tests/core/service-dependency-optional/src/main/java/org/apache/felix/ipojo/optional/MyComponent.java
@@ -0,0 +1,23 @@
+package org.apache.felix.ipojo.optional;
+
+import org.apache.felix.ipojo.Nullable;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.osgi.service.log.LogService;
+
+
+@Component(immediate=true, name="optional-log-cons")
+public class MyComponent {
+
+    @Requires(optional=true, proxy=false)
+    private LogService log;
+    
+    
+    public MyComponent() {
+        System.out.println("Created ! : " + (log instanceof Nullable) + " - " + log);
+        log.log(LogService.LOG_INFO, "Created !");
+        
+    }
+    
+    
+}
diff --git a/ipojo/tests/core/service-dependency-optional/src/main/resources/metadata.xml b/ipojo/tests/core/service-dependency-optional/src/main/resources/metadata.xml
new file mode 100644
index 0000000..c8a1900
--- /dev/null
+++ b/ipojo/tests/core/service-dependency-optional/src/main/resources/metadata.xml
@@ -0,0 +1,2 @@
+<ipojo>
+</ipojo>
diff --git a/ipojo/tests/core/service-dependency-optional/src/test/java/org/apache/felix/ipojo/test/optional/NullableTransitiveClassloadingTest.java b/ipojo/tests/core/service-dependency-optional/src/test/java/org/apache/felix/ipojo/test/optional/NullableTransitiveClassloadingTest.java
new file mode 100644
index 0000000..6de1cc1
--- /dev/null
+++ b/ipojo/tests/core/service-dependency-optional/src/test/java/org/apache/felix/ipojo/test/optional/NullableTransitiveClassloadingTest.java
@@ -0,0 +1,98 @@
+package org.apache.felix.ipojo.test.optional;
+
+import static org.ops4j.pax.exam.CoreOptions.equinox;
+import static org.ops4j.pax.exam.CoreOptions.felix;
+import static org.ops4j.pax.exam.CoreOptions.knopflerfish;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+
+import java.io.File;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.optional.MyComponent;
+import org.apache.felix.ipojo.test.helpers.IPOJOHelper;
+import org.apache.felix.ipojo.test.helpers.OSGiHelper;
+import org.apache.felix.ipojo.tinybundles.BundleAsiPOJO;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Inject;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.ops4j.pax.swissbox.tinybundles.core.TinyBundles;
+import org.osgi.framework.BundleContext;
+
+import aQute.lib.osgi.Constants;
+
+
+/**
+ * Reproduces FELIX-2093
+ * iPOJO doesn't always use the correct class loader to load nullable object.
+ */
+@RunWith( JUnit4TestRunner.class )
+public class NullableTransitiveClassloadingTest {
+
+    @Inject
+    private BundleContext context;
+
+    private OSGiHelper osgi;
+
+    private IPOJOHelper ipojo;
+
+    @Before
+    public void init() {
+        osgi = new OSGiHelper(context);
+        ipojo = new IPOJOHelper(context);
+    }
+
+    @After
+    public void stop() {
+        ipojo.dispose();
+        osgi.dispose();
+    }
+
+    @Configuration
+    public static Option[] configure()  {
+
+        File tmp = new File("target/tmp");
+        tmp.mkdirs();
+
+
+        Option[] opt =  options(
+                felix(),
+                equinox(),
+                knopflerfish(),
+                provision(
+                        // Runtime.
+                        mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo").version(asInProject()),
+                        mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo.test.helpers").version(asInProject())
+                        ),
+                provision(
+                        TinyBundles.newBundle()
+                            .add(MyComponent.class)
+                            .set(Constants.IMPORT_PACKAGE, "*")
+                            .build(BundleAsiPOJO.asiPOJOBundle(new File("src/main/resources/metadata.xml"))
+                            )
+                            
+                ));
+
+        return opt;
+    }
+
+    @Test
+    public void testCreation() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+        Factory factory = ipojo.getFactory("optional-log-cons");
+        ComponentInstance ci = factory.createComponentInstance(null);
+        
+        ci.dispose();
+    }
+
+}
diff --git a/ipojo/tests/pom.xml b/ipojo/tests/pom.xml
index f08a11c..ba6e00c 100644
--- a/ipojo/tests/pom.xml
+++ b/ipojo/tests/pom.xml
@@ -39,11 +39,13 @@
   <module>core/service-dependency-comparator</module>

   <module>core/service-providing-strategies</module>

   <module>core/service-providing-inheritance</module>

+  <module>core/service-dependency-optional</module>

   <module>core/configuration</module>

   <module>core/handler</module>

   <module>core/external-handlers</module>

   <module>core/bad-configurations</module>

   <module>core/logger</module>

+  <module>core/factory-version</module>

   <module>composite/composite-runtime</module>

   <module>composite/import-export</module>

   <module>composite/service-instance</module>