You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2022/11/22 21:03:55 UTC

[sling-org-apache-sling-testing-osgi-mock] 01/01: SLING-11698 full support for ComponentServiceObjects

This is an automated email from the ASF dual-hosted git repository.

sseifert pushed a commit to branch feature/SLING-11698-serviceobjects
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git

commit 381f3f60e75b58dec92f56c8a6d194aa35cba4f7
Author: Stefan Seifert <st...@users.noreply.github.com>
AuthorDate: Tue Nov 22 22:03:36 2022 +0100

    SLING-11698 full support for ComponentServiceObjects
---
 .../sling/testing/mock/osgi/OsgiServiceUtil.java   |  77 +++++++----
 ...eferencesOsgiR6ComponentServiceObjectsTest.java |  34 +++++
 ...ckBundleContextDynamicReferencesOsgiR6Test.java |   7 +-
 ...ctionComponentServiceObjectsReferencesTest.java |  34 +++++
 ...icGreedyConstructorInjectionReferencesTest.java |   6 +-
 .../testing/mock/osgi/OsgiServiceUtilTest.java     |  12 +-
 .../osgi/testsvc/osgiserviceutil/DictionaryTo.java |  42 ++++++
 .../osgi/testsvc/osgiserviceutil/Service3.java     |  11 +-
 .../testsvc/osgiserviceutil/Service3OsgiR6.java    | 118 ++--------------
 ...Service3OsgiR6ComponentServiceObjectsImpl.java} |  69 +++++-----
 ...Service3OsgiR6.java => Service3OsgiR6Impl.java} |  13 +-
 ...ructorInjectionComponentServiceObjectsImpl.java | 148 +++++++++++++++++++++
 .../osgiserviceutil/Service3StaticGreedyImpl.java  |  11 +-
 13 files changed, 381 insertions(+), 201 deletions(-)

diff --git a/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java b/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
index 6adc7b3..35460ce 100644
--- a/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
+++ b/core/src/main/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtil.java
@@ -50,7 +50,6 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceObjects;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.ComponentServiceObjects;
@@ -577,7 +576,7 @@ final class OsgiServiceUtil {
             switch (reference.getFieldCollectionType()) {
                 case SERVICE:
                     matchingServices.stream()
-                        .map(ServiceInfo::getServiceInstance)
+                        .map(ServiceInfo::getService)
                         .forEach(collection::add);
                     break;
                 case REFERENCE:
@@ -585,6 +584,9 @@ final class OsgiServiceUtil {
                         .map(ServiceInfo::getServiceReference)
                         .forEach(collection::add);
                     break;
+                case SERVICEOBJECTS:
+                    collection.addAll(matchingServices);
+                    break;
                 default:
                     throw new RuntimeException("Field collection type '" + reference.getFieldCollectionType() + "' not supported "
                             + "for reference '" + reference.getName()  + "' (" + type.getName() +  ") into constructor parameter " + parameterIndex + " for class " +  targetClass.getName());
@@ -598,13 +600,18 @@ final class OsgiServiceUtil {
 
             // 1. assignable from service instance
             if (parameterType.isAssignableFrom(reference.getInterfaceTypeAsClass())) {
-                return firstServiceInfo.map(ServiceInfo::getServiceInstance);
+                return firstServiceInfo.map(ServiceInfo::getService);
             }
 
             // 2. ServiceReference
             if (parameterType == ServiceReference.class) {
                 return firstServiceInfo.map(ServiceInfo::getServiceReference);
             }
+
+            // 3. ServiceReference
+            if (parameterType == ComponentServiceObjects.class) {
+                return firstServiceInfo;
+            }
         }
 
         // no match
@@ -669,7 +676,7 @@ final class OsgiServiceUtil {
             // 2. ComponentServiceObjects
             method = getMethod(targetClass, methodName, new Class<?>[] { ComponentServiceObjects.class });
             if (method != null) {
-                invokeMethod(target, method, new Object[] { toComponentServiceObjects(bundleContext.getServiceObjects(serviceInfo.getServiceReference())) });
+                invokeMethod(target, method, new Object[] { serviceInfo });
                 return;
             }
 
@@ -677,7 +684,7 @@ final class OsgiServiceUtil {
             Class<?> interfaceType = reference.getInterfaceTypeAsClass();
             method = getMethodWithAssignableTypes(targetClass, methodName, new Class<?>[] { interfaceType });
             if (method != null) {
-                invokeMethod(target, method, new Object[] { serviceInfo.getServiceInstance() });
+                invokeMethod(target, method, new Object[] { serviceInfo.getService() });
                 return;
             }
 
@@ -698,10 +705,10 @@ final class OsgiServiceUtil {
                         args[i] = serviceInfo.getServiceReference();
                     }
                     else if (method.getParameterTypes()[i] == ComponentServiceObjects.class) {
-                        args[i] = toComponentServiceObjects(bundleContext.getServiceObjects(serviceInfo.getServiceReference()));
+                        args[i] = serviceInfo;
                     }
                     else if (method.getParameterTypes()[i].isAssignableFrom(interfaceType)) {
-                        args[i] = serviceInfo.getServiceInstance();
+                        args[i] = serviceInfo.getService();
                     }
                     else if (method.getParameterTypes()[i] == Map.class) {
                         args[i] = serviceInfo.getServiceConfig();
@@ -723,12 +730,16 @@ final class OsgiServiceUtil {
                 switch (reference.getFieldCollectionType()) {
                     case SERVICE:
                     case REFERENCE:
+                    case SERVICEOBJECTS:
                         Object item = null;
                         if (serviceInfo != null) {
-                            item = serviceInfo.getServiceInstance();
+                            item = serviceInfo.getService();
                             if (reference.getFieldCollectionType() == FieldCollectionType.REFERENCE) {
                                 item = serviceInfo.getServiceReference();
                             }
+                            else if (reference.getFieldCollectionType() == FieldCollectionType.SERVICEOBJECTS) {
+                                item = serviceInfo;
+                            }
                         }
                         Field field = getCollectionField(targetClass, fieldName);
                         if (field != null) {
@@ -753,7 +764,7 @@ final class OsgiServiceUtil {
                 Class<?> interfaceType = reference.getInterfaceTypeAsClass();
                 Field field = getFieldWithAssignableType(targetClass, fieldName, interfaceType);
                 if (field != null) {
-                    setField(target, field, bind && serviceInfo != null ? serviceInfo.getServiceInstance() : null);
+                    setField(target, field, bind && serviceInfo != null ? serviceInfo.getService() : null);
                     return;
                 }
 
@@ -763,28 +774,18 @@ final class OsgiServiceUtil {
                     setField(target, field, bind && serviceInfo != null ? serviceInfo.getServiceReference() : null);
                     return;
                 }
+
+                // 3. ComponentServiceObjects
+                field = getField(targetClass, fieldName, ComponentServiceObjects.class);
+                if (field != null) {
+                    setField(target, field, bind && serviceInfo != null ? serviceInfo : null);
+                    return;
+                }
             }
         }
 
     }
 
-    private static <T> ComponentServiceObjects<T> toComponentServiceObjects(ServiceObjects<T> serviceObjects) {
-        return new ComponentServiceObjects<T>() {
-            @Override
-            public T getService() {
-                return serviceObjects.getService();
-            }
-            @Override
-            public void ungetService(T service) {
-                serviceObjects.ungetService(service);
-            }
-            @Override
-            public ServiceReference<T> getServiceReference() {
-                return serviceObjects.getServiceReference();
-            }
-        };
-    }
-
     @SuppressWarnings("unchecked")
     private static void addToCollection(Object target, Field field, Object item) {
         try {
@@ -942,7 +943,7 @@ final class OsgiServiceUtil {
         return references;
     }
 
-    static class ServiceInfo<T> {
+    static class ServiceInfo<T> implements ComponentServiceObjects<T> {
 
         private final T serviceInstance;
         private final Map<String, Object> serviceConfig;
@@ -960,7 +961,7 @@ final class OsgiServiceUtil {
             this.serviceReference = registration.getReference();
         }
 
-        public T getServiceInstance() {
+        public T getService() {
             return this.serviceInstance;
         }
 
@@ -972,6 +973,26 @@ final class OsgiServiceUtil {
             return serviceReference;
         }
 
+        @Override
+        public void ungetService(T service) {
+            // nothing to do
+        }
+
+        @Override
+        @SuppressWarnings("null")
+        public int hashCode() {
+            return serviceInstance.hashCode();
+        }
+
+        @Override
+        @SuppressWarnings("null")
+        public boolean equals(Object obj) {
+            if (obj instanceof ServiceInfo) {
+                return serviceInstance.equals(((ServiceInfo)obj).serviceInstance);
+            }
+            return false;
+        }
+
     }
 
     static class ReferenceInfo<T> {
diff --git a/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferencesOsgiR6ComponentServiceObjectsTest.java b/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferencesOsgiR6ComponentServiceObjectsTest.java
new file mode 100644
index 0000000..0b04165
--- /dev/null
+++ b/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferencesOsgiR6ComponentServiceObjectsTest.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3OsgiR6;
+import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3OsgiR6ComponentServiceObjectsImpl;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MockBundleContextDynamicReferencesOsgiR6ComponentServiceObjectsTest extends MockBundleContextDynamicReferencesOsgiR6Test {
+
+    @Override
+    protected Service3OsgiR6 newService3OsgiR6() {
+        return new Service3OsgiR6ComponentServiceObjectsImpl();
+    }
+
+}
diff --git a/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferencesOsgiR6Test.java b/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferencesOsgiR6Test.java
index 4bebcf4..db6d6d1 100644
--- a/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferencesOsgiR6Test.java
+++ b/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextDynamicReferencesOsgiR6Test.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3OsgiR6;
+import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3OsgiR6Impl;
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ServiceInterface1;
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ServiceInterface1Optional;
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ServiceInterface2;
@@ -74,7 +75,7 @@ public class MockBundleContextDynamicReferencesOsgiR6Test {
         reg1a = bundleContext.registerService(ServiceInterface1.class.getName(), dependency1a, null);
         reg2a = bundleContext.registerService(ServiceInterface2.class.getName(), dependency2a, null);
 
-        service = new Service3OsgiR6();
+        service = newService3OsgiR6();
         MockOsgi.injectServices(service, bundleContext);
         MockOsgi.activate(service, bundleContext);
         bundleContext.registerService(Service3OsgiR6.class.getName(), service, MapUtil.toDictionary(ImmutableMap.<String,Object>of("reference3DynamicFiltered.target","(prop1=def)")));
@@ -85,6 +86,10 @@ public class MockBundleContextDynamicReferencesOsgiR6Test {
         assertDependencies3();
     }
 
+    protected Service3OsgiR6 newService3OsgiR6() {
+        return new Service3OsgiR6Impl();
+    }
+
     @Test
     public void testAddRemoveOptionalUnaryService() {
         ServiceRegistration reg1aOptional = bundleContext.registerService(ServiceInterface1Optional.class.getName(), dependency1aOptional, null);
diff --git a/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyConstructorInjectionComponentServiceObjectsReferencesTest.java b/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyConstructorInjectionComponentServiceObjectsReferencesTest.java
new file mode 100644
index 0000000..45abff3
--- /dev/null
+++ b/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyConstructorInjectionComponentServiceObjectsReferencesTest.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi;
+
+import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3StaticGreedy;
+import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3StaticGreedyConstructorInjectionComponentServiceObjectsImpl;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MockBundleContextStaticGreedyConstructorInjectionComponentServiceObjectsReferencesTest  extends MockBundleContextStaticGreedyConstructorInjectionReferencesTest {
+
+    @Override
+    protected Class<? extends Service3StaticGreedy> getService3StaticGreedyClass() {
+        return Service3StaticGreedyConstructorInjectionComponentServiceObjectsImpl.class;
+    }
+
+}
diff --git a/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyConstructorInjectionReferencesTest.java b/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyConstructorInjectionReferencesTest.java
index 1673f93..ce0bebf 100644
--- a/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyConstructorInjectionReferencesTest.java
+++ b/core/src/test/java/org/apache/sling/testing/mock/osgi/MockBundleContextStaticGreedyConstructorInjectionReferencesTest.java
@@ -72,7 +72,7 @@ public class MockBundleContextStaticGreedyConstructorInjectionReferencesTest {
         reg1a = bundleContext.registerService(ServiceInterface1.class.getName(), dependency1a, null);
         reg2a = bundleContext.registerService(ServiceInterface2.class.getName(), dependency2a, null);
 
-        Service3StaticGreedy service = MockOsgi.activateInjectServices(Service3StaticGreedyConstructorInjectionImpl.class, bundleContext);
+        Service3StaticGreedy service = MockOsgi.activateInjectServices(getService3StaticGreedyClass(), bundleContext);
         bundleContext.registerService(Service3StaticGreedy.class.getName(), service, null);
 
         assertDependency1(dependency1a);
@@ -81,6 +81,10 @@ public class MockBundleContextStaticGreedyConstructorInjectionReferencesTest {
         assertDependencies3();
     }
 
+    protected Class<? extends Service3StaticGreedy> getService3StaticGreedyClass() {
+        return Service3StaticGreedyConstructorInjectionImpl.class;
+    }
+
     @Test
     public void testAddRemoveOptionalUnaryService() {
         ServiceRegistration reg1aOptional = bundleContext.registerService(ServiceInterface1Optional.class.getName(), dependency1aOptional, null);
diff --git a/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java b/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java
index 3e428ce..53eb85f 100644
--- a/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java
+++ b/core/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java
@@ -36,6 +36,8 @@ import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service1;
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service2;
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3;
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3OsgiR6;
+import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3OsgiR6ComponentServiceObjectsImpl;
+import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service3OsgiR6Impl;
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service4;
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.Service5;
 import org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil.ServiceFactory1;
@@ -110,7 +112,15 @@ public class OsgiServiceUtilTest {
 
     @Test
     public void testService3OsgiR6() {
-        Service3OsgiR6 service3 = new Service3OsgiR6();
+        testService3OsgiR6(new Service3OsgiR6Impl());
+    }
+
+    @Test
+    public void testService3OsgiR6ComponentServiceObjects() {
+        testService3OsgiR6(new Service3OsgiR6ComponentServiceObjectsImpl());
+    }
+
+    private void testService3OsgiR6(Service3OsgiR6 service3) {
         assertTrue(MockOsgi.injectServices(service3, bundleContext));
 
         Dictionary<String, Object> service3Config = new Hashtable<String, Object>();
diff --git a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/DictionaryTo.java b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/DictionaryTo.java
new file mode 100644
index 0000000..8b5f111
--- /dev/null
+++ b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/DictionaryTo.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+final class DictionaryTo {
+
+    private DictionaryTo() {
+        // static methods only
+    }
+
+    public static Map<String,Object> map(Dictionary<String,Object> dictionary) {
+        Map<String,Object> result = new HashMap<>();
+        Enumeration<String> keys = dictionary.keys();
+        while (keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            result.put(key, dictionary.get(key));
+        }
+        return result;
+    }
+
+}
diff --git a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3.java b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3.java
index 6f0bd12..fb48824 100644
--- a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3.java
+++ b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3.java
@@ -19,8 +19,6 @@
 package org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil;
 
 import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -69,14 +67,7 @@ public class Service3 implements ServiceInterface2 {
     @Activate
     private void activate(ComponentContext ctx) {
         this.componentContext = ctx;
-
-        // copy properties dictionary to config map
-        this.config = new HashMap<>();
-        Enumeration<String> keys = ctx.getProperties().keys();
-        while (keys.hasMoreElements()) {
-            String key = keys.nextElement();
-            this.config.put(key, ctx.getProperties().get(key));
-        }
+        this.config = DictionaryTo.map(ctx.getProperties());
     }
 
     @Deactivate
diff --git a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java
index 17ad401..b8745b8 100644
--- a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java
+++ b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java
@@ -18,129 +18,33 @@
  */
 package org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.FieldOption;
-import org.osgi.service.component.annotations.Modified;
-import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.component.annotations.ReferenceCardinality;
-import org.osgi.service.component.annotations.ReferencePolicy;
-import org.osgi.service.component.annotations.ReferencePolicyOption;
 
-@Component
-public class Service3OsgiR6 {
+public interface Service3OsgiR6 {
 
-    @Reference
-    private ServiceInterface1 reference1;
+    ServiceInterface1 getReference1();
 
-    @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
-    private volatile ServiceInterface1Optional reference1Optional;
+    ServiceInterface1Optional getReference1Optional();
 
-    @Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE,
-            policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
-    private volatile List<ServiceReference<ServiceInterface2>> references2 = new ArrayList<>();
+    List<ServiceInterface2> getReferences2();
 
-    @Reference(service = ServiceInterface3.class, cardinality = ReferenceCardinality.MULTIPLE,
-            policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
-    private volatile List<ServiceSuperInterface3> references3;
+    List<ServiceSuperInterface3> getReferences3();
 
-    @Reference(service = ServiceInterface3.class, cardinality = ReferenceCardinality.MULTIPLE, target="(prop1=abc)",
-            policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
-    private volatile List<ServiceSuperInterface3> references3Filtered;
+    List<ServiceSuperInterface3> getReferences3Filtered();
 
-    @Reference(cardinality = ReferenceCardinality.OPTIONAL,
-            policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY,
-            name = "reference3DynamicFiltered")
-    private volatile ServiceSuperInterface3 reference3DynamicFiltered;
+    ServiceSuperInterface3 getReference3DynamicFiltered();
 
-    @Reference(service = ServiceInterface3.class, cardinality = ReferenceCardinality.MULTIPLE,
-            policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY,
-            fieldOption = FieldOption.UPDATE)
-    private volatile Set<ServiceSuperInterface3> references3Set;
+    Set<ServiceSuperInterface3> getReferences3Set();
 
-    @Reference(service = ServiceInterface3.class, cardinality = ReferenceCardinality.MULTIPLE,
-            policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
-    private volatile Collection<ServiceSuperInterface3> references3Collection;
+    Collection<ServiceSuperInterface3> getReferences3Collection();
 
-    private ComponentContext componentContext;
-    private Map<String, Object> config;
+    ComponentContext getComponentContext();
 
-    @Activate
-    private void activate(ComponentContext ctx) {
-        this.componentContext = ctx;
-
-        // copy properties dictionary to config map
-        this.config = new HashMap<>();
-        Enumeration<String> keys = ctx.getProperties().keys();
-        while (keys.hasMoreElements()) {
-            String key = keys.nextElement();
-            this.config.put(key, ctx.getProperties().get(key));
-        }
-    }
-
-    @Deactivate
-    private void deactivate(ComponentContext ctx) {
-        this.componentContext = null;
-    }
-
-    @Modified
-    private void modified(Map<String,Object> newConfig) {
-        this.config = newConfig;
-    }
-
-    public ServiceInterface1 getReference1() {
-        return this.reference1;
-    }
-
-    public ServiceInterface1Optional getReference1Optional() {
-        return this.reference1Optional;
-    }
-
-    public List<ServiceInterface2> getReferences2() {
-        List<ServiceInterface2> services = new ArrayList<ServiceInterface2>();
-        for (ServiceReference<?> serviceReference : references2) {
-            services.add((ServiceInterface2)componentContext.getBundleContext().getService(serviceReference));
-        }
-        return services;
-    }
-
-    public List<ServiceSuperInterface3> getReferences3() {
-        return this.references3;
-    }
-
-    public List<ServiceSuperInterface3> getReferences3Filtered() {
-        return this.references3Filtered;
-    }
-
-    public ServiceSuperInterface3 getReference3DynamicFiltered() {
-        return this.reference3DynamicFiltered;
-    }
-
-    public Set<ServiceSuperInterface3> getReferences3Set() {
-        return this.references3Set;
-    }
-
-    public Collection<ServiceSuperInterface3> getReferences3Collection() {
-        return this.references3Collection;
-    }
-
-    public ComponentContext getComponentContext() {
-        return this.componentContext;
-    }
-
-    public Map<String, Object> getConfig() {
-        return config;
-    }
+    Map<String, Object> getConfig();
 
 }
diff --git a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6ComponentServiceObjectsImpl.java
similarity index 64%
copy from test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java
copy to test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6ComponentServiceObjectsImpl.java
index 17ad401..969227c 100644
--- a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java
+++ b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6ComponentServiceObjectsImpl.java
@@ -20,14 +20,14 @@ package org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 
-import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentServiceObjects;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
@@ -39,39 +39,39 @@ import org.osgi.service.component.annotations.ReferencePolicy;
 import org.osgi.service.component.annotations.ReferencePolicyOption;
 
 @Component
-public class Service3OsgiR6 {
+public class Service3OsgiR6ComponentServiceObjectsImpl implements Service3OsgiR6 {
 
     @Reference
-    private ServiceInterface1 reference1;
+    private ComponentServiceObjects<ServiceInterface1> reference1;
 
     @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
-    private volatile ServiceInterface1Optional reference1Optional;
+    private volatile ComponentServiceObjects<ServiceInterface1Optional> reference1Optional;
 
     @Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE,
             policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
-    private volatile List<ServiceReference<ServiceInterface2>> references2 = new ArrayList<>();
+    private volatile List<ComponentServiceObjects<ServiceInterface2>> references2 = new ArrayList<>();
 
     @Reference(service = ServiceInterface3.class, cardinality = ReferenceCardinality.MULTIPLE,
             policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
-    private volatile List<ServiceSuperInterface3> references3;
+    private volatile List<ComponentServiceObjects<ServiceSuperInterface3>> references3;
 
     @Reference(service = ServiceInterface3.class, cardinality = ReferenceCardinality.MULTIPLE, target="(prop1=abc)",
             policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
-    private volatile List<ServiceSuperInterface3> references3Filtered;
+    private volatile List<ComponentServiceObjects<ServiceSuperInterface3>> references3Filtered;
 
     @Reference(cardinality = ReferenceCardinality.OPTIONAL,
             policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY,
             name = "reference3DynamicFiltered")
-    private volatile ServiceSuperInterface3 reference3DynamicFiltered;
+    private volatile ComponentServiceObjects<ServiceSuperInterface3> reference3DynamicFiltered;
 
     @Reference(service = ServiceInterface3.class, cardinality = ReferenceCardinality.MULTIPLE,
             policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY,
             fieldOption = FieldOption.UPDATE)
-    private volatile Set<ServiceSuperInterface3> references3Set;
+    private volatile Set<ComponentServiceObjects<ServiceSuperInterface3>> references3Set;
 
     @Reference(service = ServiceInterface3.class, cardinality = ReferenceCardinality.MULTIPLE,
             policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY)
-    private volatile Collection<ServiceSuperInterface3> references3Collection;
+    private volatile Collection<ComponentServiceObjects<ServiceSuperInterface3>> references3Collection;
 
     private ComponentContext componentContext;
     private Map<String, Object> config;
@@ -79,14 +79,7 @@ public class Service3OsgiR6 {
     @Activate
     private void activate(ComponentContext ctx) {
         this.componentContext = ctx;
-
-        // copy properties dictionary to config map
-        this.config = new HashMap<>();
-        Enumeration<String> keys = ctx.getProperties().keys();
-        while (keys.hasMoreElements()) {
-            String key = keys.nextElement();
-            this.config.put(key, ctx.getProperties().get(key));
-        }
+        this.config = DictionaryTo.map(ctx.getProperties());
     }
 
     @Deactivate
@@ -100,39 +93,51 @@ public class Service3OsgiR6 {
     }
 
     public ServiceInterface1 getReference1() {
-        return this.reference1;
+        return Optional.ofNullable(this.reference1)
+            .map(ComponentServiceObjects::getService)
+            .orElse(null);
     }
 
     public ServiceInterface1Optional getReference1Optional() {
-        return this.reference1Optional;
+        return Optional.ofNullable(this.reference1Optional)
+                .map(ComponentServiceObjects::getService)
+                .orElse(null);
     }
 
     public List<ServiceInterface2> getReferences2() {
-        List<ServiceInterface2> services = new ArrayList<ServiceInterface2>();
-        for (ServiceReference<?> serviceReference : references2) {
-            services.add((ServiceInterface2)componentContext.getBundleContext().getService(serviceReference));
-        }
-        return services;
+        return references2.stream()
+                .map(ComponentServiceObjects::getService)
+                .collect(Collectors.toList());
     }
 
     public List<ServiceSuperInterface3> getReferences3() {
-        return this.references3;
+        return this.references3.stream()
+                .map(ComponentServiceObjects::getService)
+                .collect(Collectors.toList());
     }
 
     public List<ServiceSuperInterface3> getReferences3Filtered() {
-        return this.references3Filtered;
+        return this.references3Filtered.stream()
+                .map(ComponentServiceObjects::getService)
+                .collect(Collectors.toList());
     }
 
     public ServiceSuperInterface3 getReference3DynamicFiltered() {
-        return this.reference3DynamicFiltered;
+        return Optional.ofNullable(this.reference3DynamicFiltered)
+                .map(ComponentServiceObjects::getService)
+                .orElse(null);
     }
 
     public Set<ServiceSuperInterface3> getReferences3Set() {
-        return this.references3Set;
+        return this.references3Set.stream()
+                .map(ComponentServiceObjects::getService)
+                .collect(Collectors.toSet());
     }
 
     public Collection<ServiceSuperInterface3> getReferences3Collection() {
-        return this.references3Collection;
+        return this.references3Collection.stream()
+                .map(ComponentServiceObjects::getService)
+                .collect(Collectors.toList());
     }
 
     public ComponentContext getComponentContext() {
diff --git a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6Impl.java
similarity index 92%
copy from test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java
copy to test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6Impl.java
index 17ad401..5c2043a 100644
--- a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6.java
+++ b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3OsgiR6Impl.java
@@ -20,8 +20,6 @@ package org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -39,7 +37,7 @@ import org.osgi.service.component.annotations.ReferencePolicy;
 import org.osgi.service.component.annotations.ReferencePolicyOption;
 
 @Component
-public class Service3OsgiR6 {
+public class Service3OsgiR6Impl implements Service3OsgiR6 {
 
     @Reference
     private ServiceInterface1 reference1;
@@ -79,14 +77,7 @@ public class Service3OsgiR6 {
     @Activate
     private void activate(ComponentContext ctx) {
         this.componentContext = ctx;
-
-        // copy properties dictionary to config map
-        this.config = new HashMap<>();
-        Enumeration<String> keys = ctx.getProperties().keys();
-        while (keys.hasMoreElements()) {
-            String key = keys.nextElement();
-            this.config.put(key, ctx.getProperties().get(key));
-        }
+        this.config = DictionaryTo.map(ctx.getProperties());
     }
 
     @Deactivate
diff --git a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3StaticGreedyConstructorInjectionComponentServiceObjectsImpl.java b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3StaticGreedyConstructorInjectionComponentServiceObjectsImpl.java
new file mode 100644
index 0000000..af66ad9
--- /dev/null
+++ b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3StaticGreedyConstructorInjectionComponentServiceObjectsImpl.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentServiceObjects;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+
+@Component(service= Service3StaticGreedy.class)
+public class Service3StaticGreedyConstructorInjectionComponentServiceObjectsImpl implements Service3StaticGreedy {
+
+    private final ComponentServiceObjects<ServiceInterface1> reference1;
+    private final ComponentServiceObjects<ServiceInterface1Optional> reference1Optional;
+    private final List<ComponentServiceObjects<ServiceInterface2>> references2;
+    private final List<ComponentServiceObjects<ServiceSuperInterface3>> references3;
+
+    private final ComponentContext componentContext;
+    private final Map<String, Object> config;
+
+    // this constructor should be ignored as it contains additional parameters not valid for injection
+    public Service3StaticGreedyConstructorInjectionComponentServiceObjectsImpl(
+            ComponentServiceObjects<ServiceInterface1> reference1,
+            ComponentServiceObjects<ServiceInterface1Optional> reference1Optional,
+            List<ComponentServiceObjects<ServiceInterface2>> references2,
+            List<ComponentServiceObjects<ServiceSuperInterface3>> references3,
+            ComponentContext ctx,
+            Map<String, Object> config,
+            Object illegalParameter) {
+
+        this.componentContext = ctx;
+
+        this.reference1 = reference1;
+        this.reference1Optional = reference1Optional;
+        this.references2 = references2;
+        this.references3 = references3;
+
+        this.config = config;
+    }
+
+    @Activate
+    public Service3StaticGreedyConstructorInjectionComponentServiceObjectsImpl(
+
+            @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY)
+            ComponentServiceObjects<ServiceInterface1> reference1,
+
+            @Reference(cardinality = ReferenceCardinality.OPTIONAL,
+                    policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY)
+            ComponentServiceObjects<ServiceInterface1Optional> reference1Optional,
+
+            @Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE,
+                    policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY)
+            List<ComponentServiceObjects<ServiceInterface2>> references2,
+
+            @Reference(name = "reference3", service = ServiceInterface3.class, cardinality = ReferenceCardinality.MULTIPLE,
+                    policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY)
+            List<ComponentServiceObjects<ServiceSuperInterface3>> references3,
+
+            ComponentContext ctx,
+            Map<String, Object> config) {
+
+        this.componentContext = ctx;
+
+        this.reference1 = reference1;
+        this.reference1Optional = reference1Optional;
+        this.references2 = references2;
+        this.references3 = references3;
+
+        this.config = config;
+    }
+
+    @Override
+    public ServiceInterface1 getReference1() {
+        return Optional.ofNullable(this.reference1)
+                .map(ComponentServiceObjects::getService)
+                .orElse(null);
+    }
+
+    @Override
+    public ServiceInterface1Optional getReference1Optional() {
+        return Optional.ofNullable(this.reference1Optional)
+                .map(ComponentServiceObjects::getService)
+                .orElse(null);
+    }
+
+    @Override
+    public List<ServiceInterface2> getReferences2() {
+        return references2.stream()
+                .map(ComponentServiceObjects::getService)
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<ServiceSuperInterface3> getReferences3() {
+        return this.references3.stream()
+                .map(ComponentServiceObjects::getService)
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<Map<String, Object>> getReference3Configs() {
+        return this.references3.stream()
+                .map(ComponentServiceObjects::getServiceReference)
+                .map(ServiceReference::getProperties)
+                .map(DictionaryTo::map)
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<ServiceSuperInterface3> getReferences3Filtered() {
+        return null;
+    }
+
+    public ComponentContext getComponentContext() {
+        return this.componentContext;
+    }
+
+    public Map<String, Object> getConfig() {
+        return config;
+    }
+
+}
diff --git a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3StaticGreedyImpl.java b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3StaticGreedyImpl.java
index 6beb5d8..aadd261 100644
--- a/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3StaticGreedyImpl.java
+++ b/test-services/src/main/java/org/apache/sling/testing/mock/osgi/testsvc/osgiserviceutil/Service3StaticGreedyImpl.java
@@ -19,8 +19,6 @@
 package org.apache.sling.testing.mock.osgi.testsvc.osgiserviceutil;
 
 import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -67,14 +65,7 @@ public class Service3StaticGreedyImpl implements Service3StaticGreedy {
     @Activate
     private void activate(ComponentContext ctx) {
         this.componentContext = ctx;
-
-        // copy properties dictionary to config map
-        this.config = new HashMap<>();
-        Enumeration<String> keys = ctx.getProperties().keys();
-        while (keys.hasMoreElements()) {
-            String key = keys.nextElement();
-            this.config.put(key, ctx.getProperties().get(key));
-        }
+        this.config = DictionaryTo.map(ctx.getProperties());
     }
 
     @Deactivate