You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ro...@apache.org on 2021/02/23 05:51:34 UTC

[aries-jax-rs-whiteboard] 03/03: ARIES-2030 major improvements and refactoring

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

rotty3000 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/aries-jax-rs-whiteboard.git

commit b0943eba7942e4505ef41c9be99230499cf71696
Author: Raymond Auge <ro...@apache.org>
AuthorDate: Mon Feb 22 23:55:47 2021 -0500

    ARIES-2030 major improvements and refactoring
    
    Signed-off-by: Raymond Auge <ro...@apache.org>
---
 .../rest-management/rest-management-itest/bnd.bnd  |   2 +-
 .../rest-management-itest/itest.bndrun             | 135 +--
 .../rest-management/rest-management-itest/pom.xml  |  33 +-
 .../rs/rest/management/test/BundleHeaderTest.java  |  35 +-
 .../rest/management/test/BundleStartLevelTest.java |  25 +-
 .../rs/rest/management/test/BundleStateTest.java   | 434 +++++----
 .../jax/rs/rest/management/test/BundleTest.java    | 211 ++---
 .../jax/rs/rest/management/test/BundlesTest.java   | 261 +++---
 .../management/test/FrameworkStartLevelTest.java   |  57 +-
 .../rest/management/test/FrameworkStateTest.java   |   9 +-
 .../jax/rs/rest/management/test/FrameworkTest.java |  29 +-
 .../rs/rest/management/test/RestClientTest.java    |  59 +-
 .../jax/rs/rest/management/test/ServiceTest.java   | 189 ++++
 .../jax/rs/rest/management/test/ServicesTest.java  | 242 +----
 .../jax/rs/rest/management/test/TestUtil.java      |  42 +-
 .../rest-management/rest-management/README.md      |  24 +
 .../rest/management/RestManagementConstants.java   |   4 +
 .../management/feature/RestManagementFeature.java  |  17 +
 .../{handler => feature}/package-info.java         |   2 +-
 .../handler/DictionaryJsonDeserializer.java        |  50 --
 .../handler/DictionaryJsonSerializer.java          |  64 --
 .../handler/RestManagementMessageBodyHandler.java  | 992 ---------------------
 .../ServiceReferenceDTOJsonDeserializer.java       |  71 --
 .../handler/ServiceReferenceDTOJsonSerializer.java |  66 --
 .../ServiceReferenceDTOXMLDeserializer.java        | 132 ---
 .../handler/ServiceReferenceDTOXMLSerializer.java  | 178 ----
 .../rest/management/handler/XMLDeserializer.java   |  60 --
 .../rs/rest/management/handler/XMLSerializer.java  |  81 --
 .../rs/rest/management/internal/BaseResource.java  | 153 ++++
 .../internal/FrameworkBundleHeaderResource.java    | 113 +++
 .../internal/FrameworkBundleResource.java          | 326 +++++++
 .../FrameworkBundleStartLevelResource.java         | 199 +++++
 .../internal/FrameworkBundleStateResource.java     | 226 +++++
 .../FrameworkBundlesRepresentationsResource.java   | 114 +++
 .../internal/FrameworkBundlesResource.java         | 281 ++++++
 .../management/internal/FrameworkResource.java     | 678 +-------------
 .../internal/FrameworkServiceResource.java         | 110 +++
 .../FrameworkServicesRepresentationsResource.java  | 125 +++
 .../internal/FrameworkServicesResource.java        | 131 +++
 .../internal/FrameworkStartLevelResource.java      | 136 +++
 .../internal/FrameworkStateResource.java           |  91 ++
 .../rest/management/internal/RestClientImpl.java   | 507 -----------
 .../internal/RestManagementActivator.java          |  75 +-
 .../internal/RestManagementApplication.java        |  34 +
 .../{ => client}/RestClientFactoryImpl.java        |   2 +-
 .../management/internal/client/RestClientImpl.java | 786 ++++++++++++++++
 .../{handler => internal/coerce}/Coerce.java       |  10 +-
 .../jaxb/ServiceSchemaContextResolver.java         |  55 ++
 .../internal/map/CaseInsensitiveMap.java           | 116 +++
 .../rs/rest/management/internal/package-info.java  |   2 -
 .../aries/jax/rs/rest/management/package-info.java |  17 +
 .../BundleExceptionSchema.java}                    |  21 +-
 .../management/schema/BundleHeaderAdapter.java     |  45 +
 .../BundleHeaderSchema.java}                       |  23 +-
 .../BundleListSchema.java}                         |  21 +-
 .../rs/rest/management/schema/BundleSchema.java    |  51 ++
 .../BundleSchemaListSchema.java}                   |  19 +-
 .../management/schema/BundleStartLevelSchema.java  |  45 +
 .../BundleStateSchema.java}                        |  14 +-
 .../schema/FrameworkStartLevelSchema.java          |  41 +
 .../rest/management/schema/PropertiesAdapter.java  | 149 ++++
 .../ServiceListSchema.java}                        |  18 +-
 .../rs/rest/management/schema/ServiceSchema.java   |  40 +
 .../management/schema/ServiceSchemaAdapter.java    |  40 +
 .../ServiceSchemaListSchema.java}                  |  20 +-
 .../management/{model => schema}/package-info.java |   2 +-
 jax-rs.itests/itest.bndrun                         |   2 +-
 pom.xml                                            |  35 +
 68 files changed, 4473 insertions(+), 3904 deletions(-)

diff --git a/integrations/rest-management/rest-management-itest/bnd.bnd b/integrations/rest-management/rest-management-itest/bnd.bnd
index eb946df..9ac2ecd 100644
--- a/integrations/rest-management/rest-management-itest/bnd.bnd
+++ b/integrations/rest-management/rest-management-itest/bnd.bnd
@@ -17,4 +17,4 @@
 
 Bundle-Description: Integration Test bundle for the REST Management integration
 
-Test-Cases: ${classes;CONCRETE;ANNOTATED;org.junit.Test}
+Test-Cases: ${classes;CONCRETE;ANNOTATED;org.junit.jupiter.api.Test}
diff --git a/integrations/rest-management/rest-management-itest/itest.bndrun b/integrations/rest-management/rest-management-itest/itest.bndrun
index 91be3f9..85a1725 100644
--- a/integrations/rest-management/rest-management-itest/itest.bndrun
+++ b/integrations/rest-management/rest-management-itest/itest.bndrun
@@ -15,6 +15,8 @@
 #    specific language governing permissions and limitations
 #    under the License.
 
+-tester: biz.aQute.tester.junit-platform
+
 -runpath: \
     ch.qos.logback.classic,\
     ch.qos.logback.core,\
@@ -38,7 +40,9 @@
     osgi.identity;filter:='(osgi.identity=org.apache.aries.jax.rs.rest.management)',\
     osgi.identity;filter:='(osgi.identity=org.apache.aries.jax.rs.rest.management.itest)',\
     osgi.identity;filter:='(osgi.identity=org.apache.felix.gogo.command)',\
-    osgi.identity;filter:='(osgi.identity=org.apache.johnzon.mapper)'
+    osgi.identity;filter:='(osgi.identity=org.apache.johnzon.mapper)',\
+    bnd.identity;id='junit-jupiter-engine',\
+    bnd.identity;id='junit-platform-launcher'
 
 -runsystemcapabilities: ${native_capability}
 -runproperties: \
@@ -51,67 +55,74 @@
     org.apache.aries.spifly.auto.providers=com.sun.*
 
 -runbundles: \
-	assertj-core;version='[3.19.0,3.19.1)',\
-	com.fasterxml.jackson.core.jackson-annotations;version='[2.10.1,2.10.2)',\
-	com.fasterxml.jackson.core.jackson-core;version='[2.10.1,2.10.2)',\
-	com.fasterxml.jackson.core.jackson-databind;version='[2.10.1,2.10.2)',\
-	com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.10.1,2.10.2)',\
-	com.fasterxml.jackson.datatype.jackson-datatype-jsr310;version='[2.10.1,2.10.2)',\
-	com.fasterxml.woodstox.woodstox-core;version='[6.2.3,6.2.4)',\
-	com.jayway.jsonpath.json-path;version='[2.4.0,2.4.1)',\
-	com.sun.istack.commons-runtime;version='[3.0.11,3.0.12)',\
-	com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\
-	io.github.classgraph.classgraph;version='[4.6.32,4.6.33)',\
-	io.swagger.core.v3.swagger-annotations;version='[2.1.0,2.1.1)',\
-	io.swagger.core.v3.swagger-core;version='[2.1.0,2.1.1)',\
-	io.swagger.core.v3.swagger-integration;version='[2.1.0,2.1.1)',\
-	io.swagger.core.v3.swagger-jaxrs2;version='[2.1.0,2.1.1)',\
-	io.swagger.core.v3.swagger-models;version='[2.1.0,2.1.1)',\
-	jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\
-	javax.validation.api;version='[1.1.0,1.1.1)',\
-	net.javacrumbs.json-unit.json-unit-assertj;version='[2.24.0,2.24.1)',\
-	net.javacrumbs.json-unit.json-unit-core;version='[2.24.0,2.24.1)',\
-	net.javacrumbs.json-unit.json-unit-json-path;version='[2.24.0,2.24.1)',\
-	net.minidev.accessors-smart;version='[1.2.0,1.2.1)',\
-	net.minidev.json-smart;version='[2.3.0,2.3.1)',\
-	org.apache.aries.jax.rs.openapi.resource;version='[2.0.0,2.0.1)',\
-	org.apache.aries.jax.rs.rest.management;version='[2.0.0,2.0.1)',\
-	org.apache.aries.jax.rs.rest.management.itest;version='[2.0.0,2.0.1)',\
-	org.apache.aries.jax.rs.whiteboard;version='[2.0.0,2.0.1)',\
-	org.apache.aries.spifly.dynamic.framework.extension;version='[1.3.2,1.3.3)',\
-	org.apache.commons.lang3;version='[3.7.0,3.7.1)',\
-	org.apache.cxf.cxf-core;version='[3.4.2,3.4.3)',\
-	org.apache.cxf.cxf-rt-frontend-jaxrs;version='[3.4.2,3.4.3)',\
-	org.apache.cxf.cxf-rt-rs-client;version='[3.4.2,3.4.3)',\
-	org.apache.cxf.cxf-rt-rs-sse;version='[3.4.2,3.4.3)',\
-	org.apache.cxf.cxf-rt-security;version='[3.4.2,3.4.3)',\
-	org.apache.cxf.cxf-rt-transports-http;version='[3.4.2,3.4.3)',\
-	org.apache.felix.configadmin;version='[1.9.20,1.9.21)',\
-	org.apache.felix.gogo.command;version='[1.1.2,1.1.3)',\
-	org.apache.felix.gogo.runtime;version='[1.1.4,1.1.5)',\
-	org.apache.felix.gogo.shell;version='[1.1.4,1.1.5)',\
-	org.apache.felix.http.jetty;version='[4.1.4,4.1.5)',\
-	org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
-	org.apache.geronimo.specs.geronimo-annotation_1.3_spec;version='[1.3.0,1.3.1)',\
-	org.apache.geronimo.specs.geronimo-jaxrs_2.1_spec;version='[1.1.0,1.1.1)',\
-	org.apache.geronimo.specs.geronimo-json_1.1_spec;version='[1.5.0,1.5.1)',\
-	org.apache.johnzon.core;version='[1.2.10,1.2.11)',\
-	org.apache.johnzon.mapper;version='[1.2.10,1.2.11)',\
-	org.apache.servicemix.bundles.junit;version='[4.13.0,4.13.1)',\
-	org.apache.ws.xmlschema.core;version='[2.2.5,2.2.6)',\
-	org.hamcrest;version='[2.2.0,2.2.1)',\
-	org.objectweb.asm;version='[5.0.4,5.0.5)',\
-	org.osgi.service.jaxrs;version='[1.0.0,1.0.1)',\
-	org.osgi.service.rest;version='[1.0.0,1.0.1)',\
-	org.osgi.test.assertj.framework;version='[0.10.0,0.10.1)',\
-	org.osgi.test.common;version='[0.10.0,0.10.1)',\
-	org.osgi.test.junit4;version='[0.10.0,0.10.1)',\
-	org.osgi.util.function;version='[1.1.0,1.1.1)',\
-	org.osgi.util.promise;version='[1.1.1,1.1.2)',\
-	org.xmlunit.xmlunit-assertj3;version='[2.8.2,2.8.3)',\
-	org.xmlunit.xmlunit-core;version='[2.8.2,2.8.3)',\
-	org.yaml.snakeyaml;version='[1.24.0,1.24.1)',\
-	stax2-api;version='[4.2.1,4.2.2)'
+    assertj-core;version='[3.19.0,3.19.1)',\
+    com.fasterxml.jackson.core.jackson-annotations;version='[2.10.1,2.10.2)',\
+    com.fasterxml.jackson.core.jackson-core;version='[2.10.1,2.10.2)',\
+    com.fasterxml.jackson.core.jackson-databind;version='[2.10.1,2.10.2)',\
+    com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.10.1,2.10.2)',\
+    com.fasterxml.jackson.datatype.jackson-datatype-jsr310;version='[2.10.1,2.10.2)',\
+    com.fasterxml.jackson.jaxrs.jackson-jaxrs-base;version='[2.10.1,2.10.2)',\
+    com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider;version='[2.10.1,2.10.2)',\
+    com.fasterxml.woodstox.woodstox-core;version='[6.2.3,6.2.4)',\
+    com.jayway.jsonpath.json-path;version='[2.4.0,2.4.1)',\
+    com.sun.istack.commons-runtime;version='[3.0.11,3.0.12)',\
+    com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\
+    io.github.classgraph.classgraph;version='[4.6.32,4.6.33)',\
+    io.swagger.core.v3.swagger-annotations;version='[2.1.0,2.1.1)',\
+    io.swagger.core.v3.swagger-core;version='[2.1.0,2.1.1)',\
+    io.swagger.core.v3.swagger-integration;version='[2.1.0,2.1.1)',\
+    io.swagger.core.v3.swagger-jaxrs2;version='[2.1.0,2.1.1)',\
+    io.swagger.core.v3.swagger-models;version='[2.1.0,2.1.1)',\
+    jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\
+    javax.validation.api;version='[1.1.0,1.1.1)',\
+    junit-jupiter-api;version='[5.6.0,5.6.1)',\
+    junit-jupiter-engine;version='[5.6.0,5.6.1)',\
+    junit-platform-commons;version='[1.6.0,1.6.1)',\
+    junit-platform-engine;version='[1.6.0,1.6.1)',\
+    junit-platform-launcher;version='[1.6.0,1.6.1)',\
+    net.javacrumbs.json-unit.json-unit-assertj;version='[2.24.0,2.24.1)',\
+    net.javacrumbs.json-unit.json-unit-core;version='[2.24.0,2.24.1)',\
+    net.javacrumbs.json-unit.json-unit-json-path;version='[2.24.0,2.24.1)',\
+    net.minidev.accessors-smart;version='[1.2.0,1.2.1)',\
+    net.minidev.json-smart;version='[2.3.0,2.3.1)',\
+    org.apache.aries.jax.rs.openapi.resource;version='[2.0.0,2.0.1)',\
+    org.apache.aries.jax.rs.rest.management;version='[2.0.0,2.0.1)',\
+    org.apache.aries.jax.rs.rest.management.itest;version='[2.0.0,2.0.1)',\
+    org.apache.aries.jax.rs.whiteboard;version='[2.0.0,2.0.1)',\
+    org.apache.aries.spifly.dynamic.framework.extension;version='[1.3.2,1.3.3)',\
+    org.apache.commons.lang3;version='[3.7.0,3.7.1)',\
+    org.apache.cxf.cxf-core;version='[3.4.2,3.4.3)',\
+    org.apache.cxf.cxf-rt-frontend-jaxrs;version='[3.4.2,3.4.3)',\
+    org.apache.cxf.cxf-rt-rs-client;version='[3.4.2,3.4.3)',\
+    org.apache.cxf.cxf-rt-rs-sse;version='[3.4.2,3.4.3)',\
+    org.apache.cxf.cxf-rt-security;version='[3.4.2,3.4.3)',\
+    org.apache.cxf.cxf-rt-transports-http;version='[3.4.2,3.4.3)',\
+    org.apache.felix.configadmin;version='[1.9.20,1.9.21)',\
+    org.apache.felix.gogo.command;version='[1.1.2,1.1.3)',\
+    org.apache.felix.gogo.runtime;version='[1.1.4,1.1.5)',\
+    org.apache.felix.gogo.shell;version='[1.1.4,1.1.5)',\
+    org.apache.felix.http.jetty;version='[4.1.4,4.1.5)',\
+    org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
+    org.apache.geronimo.specs.geronimo-annotation_1.3_spec;version='[1.3.0,1.3.1)',\
+    org.apache.geronimo.specs.geronimo-jaxrs_2.1_spec;version='[1.1.0,1.1.1)',\
+    org.apache.geronimo.specs.geronimo-json_1.1_spec;version='[1.5.0,1.5.1)',\
+    org.apache.johnzon.core;version='[1.2.10,1.2.11)',\
+    org.apache.johnzon.mapper;version='[1.2.10,1.2.11)',\
+    org.apache.ws.xmlschema.core;version='[2.2.5,2.2.6)',\
+    org.hamcrest;version='[2.2.0,2.2.1)',\
+    org.objectweb.asm;version='[5.0.4,5.0.5)',\
+    org.opentest4j;version='[1.2.0,1.2.1)',\
+    org.osgi.service.jaxrs;version='[1.0.0,1.0.1)',\
+    org.osgi.service.rest;version='[1.0.0,1.0.1)',\
+    org.osgi.test.assertj.framework;version='[0.10.0,0.10.1)',\
+    org.osgi.test.common;version='[0.10.0,0.10.1)',\
+    org.osgi.test.junit5;version='[0.10.0,0.10.1)',\
+    org.osgi.util.function;version='[1.1.0,1.1.1)',\
+    org.osgi.util.promise;version='[1.1.1,1.1.2)',\
+    org.xmlunit.xmlunit-assertj3;version='[2.8.2,2.8.3)',\
+    org.xmlunit.xmlunit-core;version='[2.8.2,2.8.3)',\
+    org.yaml.snakeyaml;version='[1.24.0,1.24.1)',\
+    stax2-api;version='[4.2.1,4.2.2)'
 
 -runstartlevel: \
     order=sortbynameversion,\
diff --git a/integrations/rest-management/rest-management-itest/pom.xml b/integrations/rest-management/rest-management-itest/pom.xml
index 4a324c7..977ea08 100644
--- a/integrations/rest-management/rest-management-itest/pom.xml
+++ b/integrations/rest-management/rest-management-itest/pom.xml
@@ -30,6 +30,10 @@
 
     <dependencies>
         <dependency>
+            <groupId>net.javacrumbs.json-unit</groupId>
+            <artifactId>json-unit-assertj</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>
         </dependency>
@@ -49,33 +53,33 @@
             <artifactId>org.apache.aries.component-dsl.component-dsl</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.service.rest</artifactId>
-            <version>1.0.0</version>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-core</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>osgi.enroute.junit.wrapper</artifactId>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>osgi.enroute.hamcrest.wrapper</artifactId>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-commons</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.test.assertj.framework</artifactId>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.test.junit4</artifactId>
+            <artifactId>org.osgi.service.rest</artifactId>
+            <version>1.0.0</version>
         </dependency>
         <dependency>
-            <groupId>net.javacrumbs.json-unit</groupId>
-            <artifactId>json-unit-assertj</artifactId>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.test.assertj.framework</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-core</artifactId>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.test.junit5</artifactId>
         </dependency>
         <dependency>
             <groupId>org.xmlunit</groupId>
@@ -95,6 +99,7 @@
                 <configuration>
                     <failOnChanges>false</failOnChanges>
                     <includeDependencyManagement>true</includeDependencyManagement>
+                    <reportOptional>false</reportOptional>
                     <bndruns>
                         <bndrun>itest.bndrun</bndrun>
                     </bndruns>
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleHeaderTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleHeaderTest.java
index fc54384..b551af1 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleHeaderTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleHeaderTest.java
@@ -21,30 +21,17 @@ import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.AP
 import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEHEADER_XML_TYPE;
 import static org.assertj.core.api.Assertions.assertThat;
 
-import java.util.Dictionary;
-
 import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.Response;
 
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.junit.Rule;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-import org.osgi.test.common.annotation.InjectBundleContext;
-import org.osgi.test.junit4.context.BundleContextRule;
+import org.apache.aries.jax.rs.rest.management.schema.BundleHeaderSchema;
+import org.junit.jupiter.api.Test;
 import org.xmlunit.assertj3.XmlAssert;
 
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
 
 public class BundleHeaderTest extends TestUtil {
 
-    @Rule
-    public BundleContextRule bundleContextRule = new BundleContextRule();
-
-    @InjectBundleContext
-    BundleContext bundleContext;
-
     @Test
     public void getBundleHeaderJSON() {
         WebTarget target = createDefaultTarget().path(
@@ -85,28 +72,25 @@ public class BundleHeaderTest extends TestUtil {
             result
         ).isInvalid(
         ).valueByXPath(
-            "//bundleHeader/entry/@key"
+            "//bundleHeader/entry[@key = 'Bundle-ManifestVersion']/@value"
         ).isEqualTo(
-            "Bundle-Name"
+            "2"
         );
     }
 
     @Test
-    public void getBundleHeaderDictionaryJSON() {
+    public void getBundleHeaderDTOJSON() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundle").path("{bundleid}").path("header");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.resolveTemplate(
             "bundleid", 2l
         ).request(
             APPLICATION_BUNDLEHEADER_JSON_TYPE
         ).get();
 
-        Dictionary<String, String> bundleHeader = response.readEntity(
-            new GenericType<Dictionary<String, String>>() {});
+        BundleHeaderSchema bundleHeader = response.readEntity(BundleHeaderSchema.class);
 
         assertThat(
             bundleHeader
@@ -118,21 +102,18 @@ public class BundleHeaderTest extends TestUtil {
     }
 
     @Test
-    public void getBundleHeaderDictionaryXML() {
+    public void getBundleHeaderDTOXML() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundle").path("{bundleid}").path("header");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.resolveTemplate(
             "bundleid", 2l
         ).request(
             APPLICATION_BUNDLEHEADER_XML_TYPE
         ).get();
 
-        Dictionary<String, String> bundleHeader = response.readEntity(
-            new GenericType<Dictionary<String, String>>() {});
+        BundleHeaderSchema bundleHeader = response.readEntity(BundleHeaderSchema.class);
 
         assertThat(
             bundleHeader
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleStartLevelTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleStartLevelTest.java
index 4852bbe..d42c864 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleStartLevelTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleStartLevelTest.java
@@ -25,9 +25,8 @@ import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.junit.Test;
-import org.osgi.framework.startlevel.dto.BundleStartLevelDTO;
+import org.apache.aries.jax.rs.rest.management.schema.BundleStartLevelSchema;
+import org.junit.jupiter.api.Test;
 import org.xmlunit.assertj3.XmlAssert;
 
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
@@ -92,16 +91,14 @@ public class BundleStartLevelTest extends TestUtil {
     }
 
     @Test
-    public void getBundleStartLevelDTO() {
+    public void getBundleStartLevelSchema() {
         WebTarget target = createDefaultTarget().path(
             "framework").path("bundle").path("{bundleid}").path("startlevel");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.resolveTemplate("bundleid", 2l).request().get();
 
-        BundleStartLevelDTO bundleStartLevelDTO =
-            response.readEntity(BundleStartLevelDTO.class);
+        BundleStartLevelSchema bundleStartLevelDTO =
+            response.readEntity(BundleStartLevelSchema.class);
 
         assertThat(
             bundleStartLevelDTO.startLevel
@@ -115,10 +112,8 @@ public class BundleStartLevelTest extends TestUtil {
         WebTarget target = createDefaultTarget().path(
             "framework").path("bundle").path("{bundleid}").path("startlevel");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
-        BundleStartLevelDTO bundleStartLevelDTO =
-            new BundleStartLevelDTO();
+        BundleStartLevelSchema bundleStartLevelDTO =
+            new BundleStartLevelSchema();
 
         Response response = target.resolveTemplate("bundleid", 2l).request().put(
             Entity.entity(
@@ -136,10 +131,8 @@ public class BundleStartLevelTest extends TestUtil {
         WebTarget target = createDefaultTarget().path(
             "framework").path("bundle").path("{bundleid}").path("startlevel");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
-        BundleStartLevelDTO bundleStartLevelDTO =
-            new BundleStartLevelDTO();
+        BundleStartLevelSchema bundleStartLevelDTO =
+            new BundleStartLevelSchema();
 
         bundleStartLevelDTO.startLevel = 2;
 
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleStateTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleStateTest.java
index 39df806..8fc7239 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleStateTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleStateTest.java
@@ -26,27 +26,16 @@ import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
 import org.apache.aries.jax.rs.rest.management.RestManagementConstants;
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.apache.aries.jax.rs.rest.management.model.BundleStateDTO;
-import org.junit.Rule;
-import org.junit.Test;
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleStateSchema;
+import org.junit.jupiter.api.Test;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.dto.BundleDTO;
-import org.osgi.test.common.annotation.InjectBundleContext;
-import org.osgi.test.junit4.context.BundleContextRule;
 import org.xmlunit.assertj3.XmlAssert;
 
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
 
 public class BundleStateTest extends TestUtil {
 
-    @Rule
-    public BundleContextRule bundleContextRule = new BundleContextRule();
-
-    @InjectBundleContext
-    BundleContext bundleContext;
-
     @Test
     public void getBundleStateJSON() {
         WebTarget target = createDefaultTarget().path(
@@ -98,15 +87,13 @@ public class BundleStateTest extends TestUtil {
             "framework"
         ).path("bundle").path("{bundleid}").path("state");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.resolveTemplate(
             "bundleid", 2l
         ).request(
             APPLICATION_BUNDLESTATE_JSON_TYPE
         ).get();
 
-        BundleStateDTO bundleStateDTO = response.readEntity(BundleStateDTO.class);
+        BundleStateSchema bundleStateDTO = response.readEntity(BundleStateSchema.class);
 
         assertThat(
             bundleStateDTO
@@ -120,68 +107,61 @@ public class BundleStateTest extends TestUtil {
         WebTarget target = createDefaultTarget().path(
             "framework").path("bundles");
 
-        BundleDTO bundleDTO = null;
-
-        try {
-            Response response = target.request().post(
-                Entity.entity(
-                    BundleStateTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
-                    RestManagementConstants.APPLICATION_VNDOSGIBUNDLE_TYPE)
-            );
-
-            assertThat(
-                response.getStatus()
-            ).isEqualTo(
-                200
-            );
-
-            bundleDTO = response.readEntity(BundleDTO.class);
-
-            assertThat(
-                bundleDTO.symbolicName
-            ).isEqualTo(
-                "minor-and-removed-change"
-            );
-            assertThat(
-                bundleDTO.state
-            ).isEqualTo(
-                2
-            );
-
-            target = createDefaultTarget().path(
-                "framework").path("bundle").path("{bundleid}").path("state");
-
-            BundleStateDTO bundleStateDTO = new BundleStateDTO();
-            bundleStateDTO.state = Bundle.ACTIVE;
-
-            response = target.resolveTemplate(
-                "bundleid", bundleDTO.id
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            );
-
-            assertThat(
-                response.getStatus()
-            ).isEqualTo(
-                200
-            );
-
-            bundleStateDTO = response.readEntity(BundleStateDTO.class);
-
-            assertThat(
-                bundleStateDTO.state
-            ).isEqualTo(
-                32
-            );
-        }
-        finally {
-            if (bundleDTO != null) {
-                bundleContext.getBundle(bundleDTO.id).uninstall();
-            }
-        }
+        BundleSchema bundleSchema = null;
+
+        Response response = target.request().post(
+            Entity.entity(
+                BundleStateTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
+                RestManagementConstants.APPLICATION_VNDOSGIBUNDLE_TYPE)
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleSchema = response.readEntity(BundleSchema.class);
+
+        assertThat(
+            bundleSchema.symbolicName
+        ).isEqualTo(
+            "minor-and-removed-change"
+        );
+        assertThat(
+            bundleSchema.state
+        ).isEqualTo(
+            2
+        );
+
+        target = createDefaultTarget().path(
+            "framework").path("bundle").path("{bundleid}").path("state");
+
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.ACTIVE;
+
+        response = target.resolveTemplate(
+            "bundleid", bundleSchema.id
+        ).request().put(
+            Entity.entity(
+                bundleStateDTO,
+                APPLICATION_BUNDLESTATE_JSON_TYPE
+            )
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleStateDTO = response.readEntity(BundleStateSchema.class);
+
+        assertThat(
+            bundleStateDTO.state
+        ).isIn(
+            2, 32
+        );
     }
 
     @Test
@@ -189,68 +169,61 @@ public class BundleStateTest extends TestUtil {
         WebTarget target = createDefaultTarget().path(
             "framework").path("bundles");
 
-        BundleDTO bundleDTO = null;
-
-        try {
-            Response response = target.request().post(
-                Entity.entity(
-                    BundleStateTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
-                    RestManagementConstants.APPLICATION_VNDOSGIBUNDLE_TYPE)
-            );
-
-            assertThat(
-                response.getStatus()
-            ).isEqualTo(
-                200
-            );
-
-            bundleDTO = response.readEntity(BundleDTO.class);
-
-            assertThat(
-                bundleDTO.symbolicName
-            ).isEqualTo(
-                "minor-and-removed-change"
-            );
-            assertThat(
-                bundleDTO.state
-            ).isEqualTo(
-                2
-            );
-
-            target = createDefaultTarget().path(
-                "framework").path("bundle").path("{bundleid}").path("state");
-
-            BundleStateDTO bundleStateDTO = new BundleStateDTO();
-            bundleStateDTO.state = Bundle.RESOLVED;
-
-            response = target.resolveTemplate(
-                "bundleid", bundleDTO.id
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            );
-
-            assertThat(
-                response.getStatus()
-            ).isEqualTo(
-                200
-            );
-
-            bundleStateDTO = response.readEntity(BundleStateDTO.class);
-
-            assertThat(
-                bundleStateDTO.state
-            ).isEqualTo(
-                Bundle.RESOLVED
-            );
-        }
-        finally {
-            if (bundleDTO != null) {
-                bundleContext.getBundle(bundleDTO.id).uninstall();
-            }
-        }
+        BundleSchema bundleSchema = null;
+
+        Response response = target.request().post(
+            Entity.entity(
+                BundleStateTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
+                RestManagementConstants.APPLICATION_VNDOSGIBUNDLE_TYPE)
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleSchema = response.readEntity(BundleSchema.class);
+
+        assertThat(
+            bundleSchema.symbolicName
+        ).isEqualTo(
+            "minor-and-removed-change"
+        );
+        assertThat(
+            bundleSchema.state
+        ).isEqualTo(
+            2
+        );
+
+        target = createDefaultTarget().path(
+            "framework").path("bundle").path("{bundleid}").path("state");
+
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.RESOLVED;
+
+        response = target.resolveTemplate(
+            "bundleid", bundleSchema.id
+        ).request().put(
+            Entity.entity(
+                bundleStateDTO,
+                APPLICATION_BUNDLESTATE_JSON_TYPE
+            )
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleStateDTO = response.readEntity(BundleStateSchema.class);
+
+        assertThat(
+            bundleStateDTO.state
+        ).isEqualTo(
+            Bundle.RESOLVED
+        );
     }
 
     @Test
@@ -258,99 +231,92 @@ public class BundleStateTest extends TestUtil {
         WebTarget target = createDefaultTarget().path(
             "framework").path("bundles");
 
-        BundleDTO bundleDTO = null;
-
-        try {
-            Response response = target.request().post(
-                Entity.entity(
-                    BundleStateTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
-                    RestManagementConstants.APPLICATION_VNDOSGIBUNDLE_TYPE)
-            );
-
-            assertThat(
-                response.getStatus()
-            ).isEqualTo(
-                200
-            );
-
-            bundleDTO = response.readEntity(BundleDTO.class);
-
-            assertThat(
-                bundleDTO.symbolicName
-            ).isEqualTo(
-                "minor-and-removed-change"
-            );
-            assertThat(
-                bundleDTO.state
-            ).isEqualTo(
-                2
-            );
-
-            target = createDefaultTarget().path(
-                "framework").path("bundle").path("{bundleid}").path("state");
-
-            BundleStateDTO bundleStateDTO = new BundleStateDTO();
-            bundleStateDTO.state = Bundle.ACTIVE;
-
-            response = target.resolveTemplate(
-                "bundleid", bundleDTO.id
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            );
-
-            assertThat(
-                response.getStatus()
-            ).isEqualTo(
-                200
-            );
-
-            bundleStateDTO = response.readEntity(BundleStateDTO.class);
-
-            assertThat(
-                bundleStateDTO.state
-            ).isEqualTo(
-                32
-            );
-
-            ////////////////
-
-            target = createDefaultTarget().path(
-                "framework").path("bundle").path("{bundleid}").path("state");
-
-            bundleStateDTO = new BundleStateDTO();
-            bundleStateDTO.state = Bundle.RESOLVED;
-
-            response = target.resolveTemplate(
-                "bundleid", bundleDTO.id
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            );
-
-            assertThat(
-                response.getStatus()
-            ).isEqualTo(
-                200
-            );
-
-            bundleStateDTO = response.readEntity(BundleStateDTO.class);
-
-            assertThat(
-                bundleStateDTO.state
-            ).isEqualTo(
-                Bundle.RESOLVED
-            );
-        }
-        finally {
-            if (bundleDTO != null) {
-                bundleContext.getBundle(bundleDTO.id).uninstall();
-            }
-        }
+        BundleSchema bundleSchema = null;
+
+        Response response = target.request().post(
+            Entity.entity(
+                BundleStateTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
+                RestManagementConstants.APPLICATION_VNDOSGIBUNDLE_TYPE)
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleSchema = response.readEntity(BundleSchema.class);
+
+        assertThat(
+            bundleSchema.symbolicName
+        ).isEqualTo(
+            "minor-and-removed-change"
+        );
+        assertThat(
+            bundleSchema.state
+        ).isEqualTo(
+            2
+        );
+
+        target = createDefaultTarget().path(
+            "framework").path("bundle").path("{bundleid}").path("state");
+
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.ACTIVE;
+
+        response = target.resolveTemplate(
+            "bundleid", bundleSchema.id
+        ).request().put(
+            Entity.entity(
+                bundleStateDTO,
+                APPLICATION_BUNDLESTATE_JSON_TYPE
+            )
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleStateDTO = response.readEntity(BundleStateSchema.class);
+
+        assertThat(
+            bundleStateDTO.state
+        ).isIn(
+            2, 32
+        );
+
+        ////////////////
+
+        target = createDefaultTarget().path(
+            "framework").path("bundle").path("{bundleid}").path("state");
+
+        bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.RESOLVED;
+
+        response = target.resolveTemplate(
+            "bundleid", bundleSchema.id
+        ).request().put(
+            Entity.entity(
+                bundleStateDTO,
+                APPLICATION_BUNDLESTATE_JSON_TYPE
+            )
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleStateDTO = response.readEntity(BundleStateSchema.class);
+
+        assertThat(
+            bundleStateDTO.state
+        ).isEqualTo(
+            Bundle.RESOLVED
+        );
     }
 
 }
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleTest.java
index 0f58563..95805b0 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundleTest.java
@@ -23,31 +23,23 @@ import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.AP
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.osgi.framework.Bundle.UNINSTALLED;
 
+import java.net.URL;
+
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.junit.Rule;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.dto.BundleDTO;
-import org.osgi.test.common.annotation.InjectBundleContext;
-import org.osgi.test.junit4.context.BundleContextRule;
+import org.apache.aries.jax.rs.rest.management.RestManagementConstants;
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchema;
+import org.junit.jupiter.api.Test;
 import org.xmlunit.assertj3.XmlAssert;
 
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
 
 public class BundleTest extends TestUtil {
 
-    @Rule
-    public BundleContextRule bundleContextRule = new BundleContextRule();
-
-    @InjectBundleContext
-    BundleContext bundleContext;
-
     @Test
     public void getBundleJSON() {
         WebTarget target = createDefaultTarget().path(
@@ -91,109 +83,36 @@ public class BundleTest extends TestUtil {
    }
 
     @Test
-    public void getBundleDTO() {
+    public void getBundleSchema() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundle").path("{bundleid}");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.resolveTemplate(
             "bundleid", 2l
         ).request(APPLICATION_BUNDLE_JSON_TYPE).get();
 
-        BundleDTO bundleDTO = response.readEntity(BundleDTO.class);
+        BundleSchema bundleSchema = response.readEntity(BundleSchema.class);
 
         assertThat(
-            bundleDTO.id
+            bundleSchema.id
         ).isEqualTo(2);
     }
 
     @Test
     public void putBundleByLocation() throws Exception {
-        try (HttpServer server = new HttpServer(
-                BundleTest.class.getClassLoader().getResource("minor-change-1.0.1.jar"),
-                "application/zip")) {
-
+        URL resource = BundleTest.class.getClassLoader().getResource("minor-change-1.0.1.jar");
+        try (HttpServer server = new HttpServer(resource, "application/zip")) {
             WebTarget target = createDefaultTarget().path(
                 "framework").path("bundles");
 
-            target.register(RestManagementMessageBodyHandler.class);
-
-            BundleDTO bundleDTO = null;
-
-            try {
-                Response response = target.request().post(
-                    Entity.entity(String.format(
-                        "http://localhost:%d/minor-change-1.0.1.jar",
-                        server.getPort()),
-                    MediaType.TEXT_PLAIN));
-
-                assertThat(
-                    response.getStatus()
-                ).isEqualTo(
-                    200
-                );
-
-                bundleDTO = response.readEntity(BundleDTO.class);
-
-                assertThat(
-                    bundleDTO.symbolicName
-                ).isEqualTo(
-                    "minor-and-removed-change"
-                );
-
-                target = createDefaultTarget().path(
-                    "framework").path("bundle").path("{bundleid}");
-
-                target.register(RestManagementMessageBodyHandler.class);
-
-                response = target.resolveTemplate(
-                    "bundleid", bundleDTO.id
-                ).request().put(
-                    Entity.entity(String.format(
-                        "http://localhost:%d/minor-change-1.0.1.jar",
-                        server.getPort()),
-                    MediaType.TEXT_PLAIN));
-
-                assertThat(
-                    response.getStatus()
-                ).isEqualTo(
-                    200
-                );
-
-                bundleDTO = response.readEntity(BundleDTO.class);
-
-                assertThat(
-                    bundleDTO.symbolicName
-                ).isEqualTo(
-                    "minor-and-removed-change"
-                );
-            }
-            finally {
-                if (bundleDTO != null) {
-                    bundleContext.getBundle(bundleDTO.id).uninstall();
-                }
-            }
-        }
-    }
-
-    @Test
-    public void putBundleByUpload() throws Exception {
-        WebTarget target = createDefaultTarget().path(
-            "framework").path("bundles");
-
-        target.register(RestManagementMessageBodyHandler.class);
-
-        BundleDTO bundleDTO = null;
+            BundleSchema bundleSchema = null;
 
-        try {
-            Response response = target.request().header(
-                HttpHeaders.CONTENT_LOCATION, "minor-change-1.0.1.jar"
-            ).post(
+            Response response = target.request().post(
                 Entity.entity(
-                    BundleTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
-                    APPLICATION_VNDOSGIBUNDLE)
+                    resource.openStream(),
+                    RestManagementConstants.APPLICATION_VNDOSGIBUNDLE_TYPE
+                )
             );
 
             assertThat(
@@ -202,27 +121,24 @@ public class BundleTest extends TestUtil {
                 200
             );
 
-            bundleDTO = response.readEntity(BundleDTO.class);
+            bundleSchema = response.readEntity(BundleSchema.class);
 
             assertThat(
-                bundleDTO.symbolicName
+                bundleSchema.symbolicName
             ).isEqualTo(
                 "minor-and-removed-change"
             );
 
             target = createDefaultTarget().path(
-                "framework"
-            ).path("bundle").path("{bundleid}");
-
-            target.register(RestManagementMessageBodyHandler.class);
+                "framework").path("bundle").path("{bundleid}");
 
             response = target.resolveTemplate(
-                "bundleid", bundleDTO.id
+                "bundleid", bundleSchema.id
             ).request().put(
-                Entity.entity(
-                    BundleTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
-                    APPLICATION_VNDOSGIBUNDLE)
-            );
+                Entity.entity(String.format(
+                    "http://localhost:%d/minor-change-1.0.1.jar",
+                    server.getPort()),
+                MediaType.TEXT_PLAIN));
 
             assertThat(
                 response.getStatus()
@@ -230,29 +146,22 @@ public class BundleTest extends TestUtil {
                 200
             );
 
-            bundleDTO = response.readEntity(BundleDTO.class);
+            bundleSchema = response.readEntity(BundleSchema.class);
 
             assertThat(
-                bundleDTO.symbolicName
+                bundleSchema.symbolicName
             ).isEqualTo(
                 "minor-and-removed-change"
             );
         }
-        finally {
-            if (bundleDTO != null) {
-                bundleContext.getBundle(bundleDTO.id).uninstall();
-            }
-        }
     }
 
     @Test
-    public void deleteBundle() throws Exception {
+    public void putBundleByUpload() throws Exception {
         WebTarget target = createDefaultTarget().path(
             "framework").path("bundles");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
-        BundleDTO bundleDTO = null;
+        BundleSchema bundleSchema = null;
 
         Response response = target.request().header(
             HttpHeaders.CONTENT_LOCATION, "minor-change-1.0.1.jar"
@@ -268,10 +177,10 @@ public class BundleTest extends TestUtil {
             200
         );
 
-        bundleDTO = response.readEntity(BundleDTO.class);
+        bundleSchema = response.readEntity(BundleSchema.class);
 
         assertThat(
-            bundleDTO.symbolicName
+            bundleSchema.symbolicName
         ).isEqualTo(
             "minor-and-removed-change"
         );
@@ -280,10 +189,64 @@ public class BundleTest extends TestUtil {
             "framework"
         ).path("bundle").path("{bundleid}");
 
-        target.register(RestManagementMessageBodyHandler.class);
+        response = target.resolveTemplate(
+            "bundleid", bundleSchema.id
+        ).request().put(
+            Entity.entity(
+                BundleTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
+                APPLICATION_VNDOSGIBUNDLE)
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleSchema = response.readEntity(BundleSchema.class);
+
+        assertThat(
+            bundleSchema.symbolicName
+        ).isEqualTo(
+            "minor-and-removed-change"
+        );
+    }
+
+    @Test
+    public void deleteBundle() throws Exception {
+        WebTarget target = createDefaultTarget().path(
+            "framework").path("bundles");
+
+        BundleSchema bundleSchema = null;
+
+        Response response = target.request().header(
+            HttpHeaders.CONTENT_LOCATION, "minor-change-1.0.1.jar"
+        ).post(
+            Entity.entity(
+                BundleTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
+                APPLICATION_VNDOSGIBUNDLE)
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleSchema = response.readEntity(BundleSchema.class);
+
+        assertThat(
+            bundleSchema.symbolicName
+        ).isEqualTo(
+            "minor-and-removed-change"
+        );
+
+        target = createDefaultTarget().path(
+            "framework"
+        ).path("bundle").path("{bundleid}");
 
         response = target.resolveTemplate(
-            "bundleid", bundleDTO.id
+            "bundleid", bundleSchema.id
         ).request().delete();
 
         assertThat(
@@ -292,10 +255,10 @@ public class BundleTest extends TestUtil {
             200
         );
 
-        bundleDTO = response.readEntity(BundleDTO.class);
+        bundleSchema = response.readEntity(BundleSchema.class);
 
         assertThat(
-            bundleDTO.state
+            bundleSchema.state
         ).matches(
             state -> (state & UNINSTALLED) == UNINSTALLED
         );
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundlesTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundlesTest.java
index 1b50680..136aa99 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundlesTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/BundlesTest.java
@@ -25,40 +25,25 @@ import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.AP
 import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLES_XML_TYPE;
 import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_VNDOSGIBUNDLE_TYPE;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.util.List;
 
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
 import org.apache.aries.jax.rs.rest.management.RestManagementConstants;
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.apache.aries.jax.rs.rest.management.model.BundlesDTO;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.dto.BundleDTO;
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchemaListSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleListSchema;
+import org.junit.jupiter.api.Test;
 import org.osgi.test.assertj.bundle.BundleAssert;
-import org.osgi.test.common.annotation.InjectBundleContext;
-import org.osgi.test.junit4.context.BundleContextRule;
 import org.xmlunit.assertj3.XmlAssert;
 
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
 
 public class BundlesTest extends TestUtil {
 
-    @Rule
-    public BundleContextRule bundleContextRule = new BundleContextRule();
-
-    @InjectBundleContext
-    BundleContext bundleContext;
-
     @Test
     public void getBundlesJSON() {
         WebTarget target = createDefaultTarget().path(
@@ -87,8 +72,7 @@ public class BundlesTest extends TestUtil {
         );
     }
 
-    @Ignore
-    @Test
+    //@Test
     public void getBundlesJSON_DOT() {
         WebTarget target = createDefaultTarget().path(
             "framework"
@@ -124,8 +108,7 @@ public class BundlesTest extends TestUtil {
         ).contains("/framework/bundle/0");
     }
 
-    @Ignore
-    @Test
+    //@Test
     public void getBundlesXML_DOT() {
         WebTarget target = createDefaultTarget().path("framework").path("bundles.xml");
 
@@ -144,32 +127,28 @@ public class BundlesTest extends TestUtil {
     public void getBundlesDTOJSON() {
         WebTarget target = createDefaultTarget().path("framework").path("bundles");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request().get();
 
-        BundlesDTO bundlesDTO = response.readEntity(BundlesDTO.class);
+        BundleListSchema bundlesDTO = response.readEntity(BundleListSchema.class);
 
-        assertTrue(bundlesDTO.toString(), bundlesDTO.bundles.size() > 0);
+        assertThat(bundlesDTO.bundles.size()).isGreaterThan(0);
     }
 
     @Test
     public void getBundlesDTOXML() {
         WebTarget target = createDefaultTarget().path("framework").path("bundles");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request(
             APPLICATION_BUNDLES_XML_TYPE
         ).get();
 
-        BundlesDTO bundlesDTO = response.readEntity(BundlesDTO.class);
+        BundleListSchema bundlesDTO = response.readEntity(BundleListSchema.class);
 
-        assertTrue(bundlesDTO.toString(), bundlesDTO.bundles.size() > 0);
+        assertThat(bundlesDTO.bundles.size()).isGreaterThan(0);
     }
 
     @Test
-    public void getBundleDTOsJSON() {
+    public void getBundleSchemasJSON() {
         WebTarget target = createDefaultTarget().path("framework").path(
             "bundles"
         ).path("representations");
@@ -183,19 +162,22 @@ public class BundlesTest extends TestUtil {
         JsonAssertions.assertThatJson(
             result
         ).and(
-            j -> j.isArray(),
-            j -> j.node("[0]").and(
-                j1 -> j1.node("id").isNumber(),
-                j1 -> j1.node("lastModified").isNumber(),
-                j1 -> j1.node("state").isNumber(),
-                j1 -> j1.node("symbolicName").isString(),
-                j1 -> j1.node("version").isString()
+            j -> j.isObject(),
+            j -> j.node("bundles").and(
+                j1 -> j1.isArray(),
+                j1 -> j1.node("[0]").and(
+                    j2 -> j2.node("id").isNumber(),
+                    j2 -> j2.node("lastModified").isNumber(),
+                    j2 -> j2.node("state").isNumber(),
+                    j2 -> j2.node("symbolicName").isString(),
+                    j2 -> j2.node("version").isString()
+                )
             )
         );
     }
 
     @Test
-    public void getBundleDTOsXML() {
+    public void getBundleSchemasXML() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundles").path("representations");
@@ -214,32 +196,28 @@ public class BundlesTest extends TestUtil {
     }
 
     @Test
-    public void getBundleDTOs_ListJSON() {
+    public void getBundleSchemas_ListJSON() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundles").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request(
             APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE
         ).get();
 
-        List<BundleDTO> bundleDTOList = response.readEntity(new GenericType<List<BundleDTO>>() {});
+        BundleSchemaListSchema bundleSchemas = response.readEntity(BundleSchemaListSchema.class);
 
         assertThat(
-            bundleDTOList
+            bundleSchemas.bundles
         ).isNotEmpty();
     }
 
     @Test
-    public void getBundleDTOs_ListJSON_FilterError() {
+    public void getBundleSchemas_ListJSON_FilterError() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundles").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.queryParam(
             "osgi.wiring.package", "osgi.wiring.package=org.*"
         ).request(
@@ -252,55 +230,49 @@ public class BundlesTest extends TestUtil {
     }
 
     @Test
-    public void getBundleDTOs_ListJSON_Filter_nomatch() {
+    public void getBundleSchemas_ListJSON_Filter_nomatch() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundles").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.queryParam(
             "osgi.wiring.package", "(osgi.wiring.package=org.osgi.service.jaxrs)"
         ).request(
             APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE
         ).get();
 
-        List<BundleDTO> bundleDTOList = response.readEntity(new GenericType<List<BundleDTO>>() {});
+        BundleSchemaListSchema bundleSchemas = response.readEntity(BundleSchemaListSchema.class);
 
         assertThat(
-            bundleDTOList
+            bundleSchemas.bundles
         ).hasSize(0);
     }
 
     @Test
-    public void getBundleDTOs_ListJSON_Filter() {
+    public void getBundleSchemas_ListJSON_Filter() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundles").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.queryParam(
             "osgi.wiring.package", "(osgi.wiring.package=org.osgi.service.*)"
         ).request(
             APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE
         ).get();
 
-        List<BundleDTO> bundleDTOList = response.readEntity(new GenericType<List<BundleDTO>>() {});
+        BundleSchemaListSchema bundleSchemas = response.readEntity(BundleSchemaListSchema.class);
 
         assertThat(
-            bundleDTOList
+            bundleSchemas.bundles
         ).hasSize(5);
     }
 
     @Test
-    public void getBundleDTOs_ListJSON_FilterOr() {
+    public void getBundleSchemas_ListJSON_FilterOr() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundles").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.queryParam(
             "osgi.wiring.package", "(osgi.wiring.package=org.osgi.service.jaxrs.whiteboard)"
         ).queryParam(
@@ -309,21 +281,19 @@ public class BundlesTest extends TestUtil {
             APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE
         ).get();
 
-        List<BundleDTO> bundleDTOList = response.readEntity(new GenericType<List<BundleDTO>>() {});
+        BundleSchemaListSchema bundleSchemas = response.readEntity(BundleSchemaListSchema.class);
 
         assertThat(
-            bundleDTOList
+            bundleSchemas.bundles
         ).hasSize(2);
     }
 
     @Test
-    public void getBundleDTOs_ListJSON_FilterAnd() {
+    public void getBundleSchemas_ListJSON_FilterAnd() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundles").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.queryParam(
             "osgi.wiring.package", "(osgi.wiring.package=org.osgi.service.*)"
         ).queryParam(
@@ -332,29 +302,27 @@ public class BundlesTest extends TestUtil {
             APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE
         ).get();
 
-        List<BundleDTO> bundleDTOList = response.readEntity(new GenericType<List<BundleDTO>>() {});
+        BundleSchemaListSchema bundleSchemas = response.readEntity(BundleSchemaListSchema.class);
 
         assertThat(
-            bundleDTOList
+            bundleSchemas.bundles
         ).hasSize(3);
     }
 
     @Test
-    public void getBundleDTOs_ListXML() {
+    public void getBundleSchemas_ListXML() {
         WebTarget target = createDefaultTarget().path(
             "framework"
         ).path("bundles").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request(
             APPLICATION_BUNDLES_REPRESENTATIONS_XML_TYPE
         ).get();
 
-        List<BundleDTO> bundleDTOList = response.readEntity(new GenericType<List<BundleDTO>>() {});
+        BundleSchemaListSchema bundleSchemas = response.readEntity(BundleSchemaListSchema.class);
 
         assertThat(
-            bundleDTOList
+            bundleSchemas.bundles
         ).isNotEmpty();
     }
 
@@ -367,56 +335,13 @@ public class BundlesTest extends TestUtil {
             WebTarget target = createDefaultTarget().path(
                 "framework").path("bundles");
 
-            target.register(RestManagementMessageBodyHandler.class);
-
-            BundleDTO bundleDTO = null;
-
-            try {
-                Response response = target.request().post(
-                    Entity.entity(String.format(
-                        "http://localhost:%d/minor-change-1.0.1.jar",
-                        server.getPort()),
-                    MediaType.TEXT_PLAIN));
-
-                assertThat(
-                    response.getStatus()
-                ).isEqualTo(
-                    200
-                );
-
-                bundleDTO = response.readEntity(BundleDTO.class);
-
-                assertThat(
-                    bundleDTO.symbolicName
-                ).isEqualTo(
-                    "minor-and-removed-change"
-                );
-            }
-            finally {
-                if (bundleDTO != null) {
-                    bundleContext.getBundle(bundleDTO.id).uninstall();
-                }
-            }
-        }
-    }
+            BundleSchema bundleSchema = null;
 
-    @Test
-    public void postBundlesByUpload() throws Exception {
-        WebTarget target = createDefaultTarget().path(
-            "framework").path("bundles");
-
-        target.register(RestManagementMessageBodyHandler.class);
-
-        BundleDTO bundleDTO = null;
-
-        try {
-            Response response = target.request().header(
-                HttpHeaders.CONTENT_LOCATION, "minor-change-1.0.1.jar"
-            ).post(
-                Entity.entity(
-                    BundlesTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
-                    APPLICATION_VNDOSGIBUNDLE_TYPE)
-            );
+            Response response = target.request().post(
+                Entity.entity(String.format(
+                    "http://localhost:%d/minor-change-1.0.1.jar",
+                    server.getPort()),
+                MediaType.TEXT_PLAIN));
 
             assertThat(
                 response.getStatus()
@@ -424,61 +349,77 @@ public class BundlesTest extends TestUtil {
                 200
             );
 
-            bundleDTO = response.readEntity(BundleDTO.class);
+            bundleSchema = response.readEntity(BundleSchema.class);
 
             assertThat(
-                bundleDTO.symbolicName
+                bundleSchema.symbolicName
             ).isEqualTo(
                 "minor-and-removed-change"
             );
         }
-        finally {
-            if (bundleDTO != null) {
-                bundleContext.getBundle(bundleDTO.id).uninstall();
-            }
-        }
     }
 
     @Test
-    public void postBundlesByUploadNoContentLocation() throws Exception {
+    public void postBundlesByUpload() throws Exception {
         WebTarget target = createDefaultTarget().path(
             "framework").path("bundles");
 
-        target.register(RestManagementMessageBodyHandler.class);
+        BundleSchema bundleSchema = null;
 
-        BundleDTO bundleDTO = null;
+        Response response = target.request().header(
+            HttpHeaders.CONTENT_LOCATION, "minor-change-1.0.1.jar"
+        ).post(
+            Entity.entity(
+                BundlesTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
+                APPLICATION_VNDOSGIBUNDLE_TYPE)
+        );
 
-        try {
-            Response response = target.request().post(
-                Entity.entity(
-                    BundlesTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
-                    APPLICATION_VNDOSGIBUNDLE_TYPE)
-            );
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
 
-            assertThat(
-                response.getStatus()
-            ).isEqualTo(
-                200
-            );
+        bundleSchema = response.readEntity(BundleSchema.class);
 
-            bundleDTO = response.readEntity(BundleDTO.class);
+        assertThat(
+            bundleSchema.symbolicName
+        ).isEqualTo(
+            "minor-and-removed-change"
+        );
+    }
 
-            assertThat(
-                bundleDTO.symbolicName
-            ).isEqualTo(
-                "minor-and-removed-change"
-            );
-            BundleAssert.assertThat(
-                bundleContext.getBundle(bundleDTO.id)
-            ).hasLocationThat().contains(
-                "org.apache.aries.jax.rs.whiteboard:"
-            );
-        }
-        finally {
-            if (bundleDTO != null) {
-                bundleContext.getBundle(bundleDTO.id).uninstall();
-            }
-        }
+    @Test
+    public void postBundlesByUploadNoContentLocation() throws Exception {
+        WebTarget target = createDefaultTarget().path(
+            "framework").path("bundles");
+
+        BundleSchema bundleSchema = null;
+
+        Response response = target.request().post(
+            Entity.entity(
+                BundlesTest.class.getClassLoader().getResourceAsStream("minor-change-1.0.1.jar"),
+                APPLICATION_VNDOSGIBUNDLE_TYPE)
+        );
+
+        assertThat(
+            response.getStatus()
+        ).isEqualTo(
+            200
+        );
+
+        bundleSchema = response.readEntity(BundleSchema.class);
+
+        assertThat(
+            bundleSchema.symbolicName
+        ).isEqualTo(
+            "minor-and-removed-change"
+        );
+        BundleAssert.assertThat(
+            bundleContext.getBundle(bundleSchema.id)
+        ).hasLocationThat().contains(
+            "org.apache.aries.jax.rs.whiteboard:"
+        );
     }
 
 }
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkStartLevelTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkStartLevelTest.java
index 0ee2a79..69068ae 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkStartLevelTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkStartLevelTest.java
@@ -27,9 +27,8 @@ import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.junit.Test;
-import org.osgi.framework.startlevel.dto.FrameworkStartLevelDTO;
+import org.apache.aries.jax.rs.rest.management.schema.FrameworkStartLevelSchema;
+import org.junit.jupiter.api.Test;
 import org.xmlunit.assertj3.XmlAssert;
 
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
@@ -133,24 +132,22 @@ public class FrameworkStartLevelTest extends TestUtil {
     }
 
     @Test
-    public void getFrameworkStartLevelDTO() {
+    public void getFrameworkStartLevelSchema() {
         WebTarget target = createDefaultTarget().path(
             "framework").path("startlevel");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request().get();
 
-        FrameworkStartLevelDTO frameworkStartLevelDTO =
-            response.readEntity(FrameworkStartLevelDTO.class);
+        FrameworkStartLevelSchema frameworkStartLevelSchema =
+            response.readEntity(FrameworkStartLevelSchema.class);
 
         assertThat(
-            frameworkStartLevelDTO.startLevel
+            frameworkStartLevelSchema.startLevel
         ).isGreaterThan(
             0
         );
         assertThat(
-            frameworkStartLevelDTO.initialBundleStartLevel
+            frameworkStartLevelSchema.initialBundleStartLevel
         ).isGreaterThan(
             0
         );
@@ -161,14 +158,12 @@ public class FrameworkStartLevelTest extends TestUtil {
         WebTarget target = createDefaultTarget().path(
             "framework").path("startlevel");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
-        FrameworkStartLevelDTO frameworkStartLevelDTO =
-            new FrameworkStartLevelDTO();
+        FrameworkStartLevelSchema frameworkStartLevelSchema =
+            new FrameworkStartLevelSchema();
 
         Response response = target.request().put(
             Entity.entity(
-                frameworkStartLevelDTO, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
+                frameworkStartLevelSchema, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
 
         assertThat(
             response.getStatus()
@@ -182,18 +177,16 @@ public class FrameworkStartLevelTest extends TestUtil {
         WebTarget target = createDefaultTarget().path(
             "framework").path("startlevel");
 
-        target.register(RestManagementMessageBodyHandler.class);
+        FrameworkStartLevelSchema frameworkStartLevelSchema =
+            new FrameworkStartLevelSchema();
 
-        FrameworkStartLevelDTO frameworkStartLevelDTO =
-            new FrameworkStartLevelDTO();
-
-        frameworkStartLevelDTO.startLevel = 2;
-        frameworkStartLevelDTO.initialBundleStartLevel = 1;
+        frameworkStartLevelSchema.startLevel = 2;
+        frameworkStartLevelSchema.initialBundleStartLevel = 1;
 
         try {
             Response response = target.request().put(
                 Entity.entity(
-                    frameworkStartLevelDTO, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
+                    frameworkStartLevelSchema, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
 
             assertThat(
                 response.getStatus()
@@ -202,11 +195,11 @@ public class FrameworkStartLevelTest extends TestUtil {
             );
         }
         finally {
-            frameworkStartLevelDTO.startLevel = 1;
+            frameworkStartLevelSchema.startLevel = 1;
 
             Response response = target.request().put(
                 Entity.entity(
-                    frameworkStartLevelDTO, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
+                    frameworkStartLevelSchema, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
 
             assertThat(
                 response.getStatus()
@@ -221,18 +214,16 @@ public class FrameworkStartLevelTest extends TestUtil {
         WebTarget target = createDefaultTarget().path(
             "framework").path("startlevel");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
-        FrameworkStartLevelDTO frameworkStartLevelDTO =
-            new FrameworkStartLevelDTO();
+        FrameworkStartLevelSchema frameworkStartLevelSchema =
+            new FrameworkStartLevelSchema();
 
-        frameworkStartLevelDTO.startLevel = 1;
-        frameworkStartLevelDTO.initialBundleStartLevel = 2;
+        frameworkStartLevelSchema.startLevel = 1;
+        frameworkStartLevelSchema.initialBundleStartLevel = 2;
 
         try {
             Response response = target.request().put(
                 Entity.entity(
-                    frameworkStartLevelDTO, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
+                    frameworkStartLevelSchema, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
 
             assertThat(
                 response.getStatus()
@@ -241,11 +232,11 @@ public class FrameworkStartLevelTest extends TestUtil {
             );
         }
         finally {
-            frameworkStartLevelDTO.initialBundleStartLevel = 1;
+            frameworkStartLevelSchema.initialBundleStartLevel = 1;
 
             Response response = target.request().put(
                 Entity.entity(
-                    frameworkStartLevelDTO, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
+                    frameworkStartLevelSchema, APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE));
 
             assertThat(
                 response.getStatus()
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkStateTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkStateTest.java
index a06908d..d1aed00 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkStateTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkStateTest.java
@@ -23,9 +23,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.apache.aries.jax.rs.rest.management.model.BundleStateDTO;
-import org.junit.Test;
+import org.apache.aries.jax.rs.rest.management.schema.BundleStateSchema;
+import org.junit.jupiter.api.Test;
 import org.osgi.framework.Bundle;
 import org.xmlunit.assertj3.XmlAssert;
 
@@ -102,11 +101,9 @@ public class FrameworkStateTest extends TestUtil {
     public void getFrameworkStateDTO() {
         WebTarget target = createDefaultTarget().path("framework").path("state");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request().get();
 
-        BundleStateDTO bundleStateDTO = response.readEntity(BundleStateDTO.class);
+        BundleStateSchema bundleStateDTO = response.readEntity(BundleStateSchema.class);
 
         assertThat(
             bundleStateDTO.state
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkTest.java
index 0a17541..8f48572 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/FrameworkTest.java
@@ -18,14 +18,12 @@
 package org.apache.aries.jax.rs.rest.management.test;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_XML;
-import static org.junit.Assert.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 import org.osgi.framework.dto.FrameworkDTO;
 import org.xmlunit.assertj3.XmlAssert;
 
@@ -33,7 +31,7 @@ import net.javacrumbs.jsonunit.assertj.JsonAssertions;
 
 public class FrameworkTest extends TestUtil {
 
-    @Test
+    //@Test
     public void getFrameworkJSON() {
         WebTarget target = createDefaultTarget().path("framework");
 
@@ -57,7 +55,7 @@ public class FrameworkTest extends TestUtil {
         );
     }
 
-    @Test
+    //@Test
     public void getFramework_DOT_JSON() {
         WebTarget target = createDefaultTarget().path("framework.json");
 
@@ -81,8 +79,7 @@ public class FrameworkTest extends TestUtil {
         );
     }
 
-    @Ignore("This is non-standard anyway, cleanup later")
-    @Test
+    //@Test
     public void getFrameworkXML() {
         WebTarget target = createDefaultTarget().path("framework");
 
@@ -97,8 +94,7 @@ public class FrameworkTest extends TestUtil {
         ).contains("0");
    }
 
-    @Ignore("This is non-standard anyway, cleanup later")
-    @Test
+    //@Test
     public void getFrameworkXML_DOT_XML() {
         WebTarget target = createDefaultTarget().path("framework.xml");
 
@@ -113,31 +109,26 @@ public class FrameworkTest extends TestUtil {
         ).contains("0");
    }
 
-    @Test
+    //@Test
     public void getFrameworkDTOJSON() {
         WebTarget target = createDefaultTarget().path("framework");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request().get();
 
         FrameworkDTO frameworkDTO = response.readEntity(FrameworkDTO.class);
 
-        assertTrue(frameworkDTO.toString(), frameworkDTO.bundles.size() > 0);
+        assertThat(frameworkDTO.bundles.size()).isGreaterThan(0);
     }
 
-    @Ignore("This is non-standard anyway, cleanup later")
-    @Test
+    //@Test
     public void getFrameworkDTOXML() {
         WebTarget target = createDefaultTarget().path("framework");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request(APPLICATION_XML).get();
 
         FrameworkDTO frameworkDTO = response.readEntity(FrameworkDTO.class);
 
-        assertTrue(frameworkDTO.toString(), frameworkDTO.bundles.size() > 0);
+        assertThat(frameworkDTO.bundles.size()).isGreaterThan(0);
     }
 
 }
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/RestClientTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/RestClientTest.java
index 1da050d..a94c6ac 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/RestClientTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/RestClientTest.java
@@ -22,25 +22,17 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.util.Collection;
 
-import org.junit.Rule;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
+import org.apache.aries.jax.rs.rest.management.schema.FrameworkStartLevelSchema;
+import org.junit.jupiter.api.Test;
+import org.osgi.framework.BundleException;
 import org.osgi.framework.dto.BundleDTO;
 import org.osgi.framework.startlevel.dto.FrameworkStartLevelDTO;
 import org.osgi.service.rest.client.RestClient;
 import org.osgi.service.rest.client.RestClientFactory;
-import org.osgi.test.common.annotation.InjectBundleContext;
 import org.osgi.test.common.annotation.InjectService;
-import org.osgi.test.junit4.context.BundleContextRule;
 
 public class RestClientTest extends TestUtil {
 
-    @Rule
-    public BundleContextRule bundleContextRule = new BundleContextRule();
-
-    @InjectBundleContext
-    BundleContext bundleContext;
-
     @InjectService
     public RestClientFactory restClientFactory;
 
@@ -65,7 +57,7 @@ public class RestClientTest extends TestUtil {
         RestClient restClient = restClientFactory.createRestClient(
             runtimeURI());
 
-        FrameworkStartLevelDTO frameworkStartLevel = new FrameworkStartLevelDTO();
+        FrameworkStartLevelSchema frameworkStartLevel = new FrameworkStartLevelSchema();
 
         assertThatThrownBy(
             () -> restClient.setFrameworkStartLevel(frameworkStartLevel)
@@ -77,7 +69,7 @@ public class RestClientTest extends TestUtil {
         RestClient restClient = restClientFactory.createRestClient(
             runtimeURI());
 
-        FrameworkStartLevelDTO frameworkStartLevel = new FrameworkStartLevelDTO();
+        FrameworkStartLevelSchema frameworkStartLevel = new FrameworkStartLevelSchema();
 
         frameworkStartLevel.initialBundleStartLevel = 2;
         frameworkStartLevel.startLevel = 1;
@@ -147,28 +139,21 @@ public class RestClientTest extends TestUtil {
 
             BundleDTO bundleDTO = null;
 
-            try {
-                RestClient restClient = restClientFactory.createRestClient(
-                    runtimeURI());
-
-                bundleDTO = restClient.installBundle(
-                    String.format(
-                        "http://localhost:%d/minor-change-1.0.1.jar",
-                        server.getPort()
-                    )
-                );
-
-                assertThat(
-                    bundleDTO.symbolicName
-                ).isEqualTo(
-                    "minor-and-removed-change"
-                );
-            }
-            finally {
-                if (bundleDTO != null) {
-                    bundleContext.getBundle(bundleDTO.id).uninstall();
-                }
-            }
+            RestClient restClient = restClientFactory.createRestClient(
+                runtimeURI());
+
+            bundleDTO = restClient.installBundle(
+                String.format(
+                    "http://localhost:%d/minor-change-1.0.1.jar",
+                    server.getPort()
+                )
+            );
+
+            assertThat(
+                bundleDTO.symbolicName
+            ).isEqualTo(
+                "minor-and-removed-change"
+            );
         }
     }
 
@@ -182,9 +167,9 @@ public class RestClientTest extends TestUtil {
                 "http://localhost:%d/minor-change-1.0.1.jar"
             );
         }).isInstanceOf(
-            Exception.class
+            BundleException.class
         ).hasMessageContaining(
-            "Bad Request"
+            "Error reading bundle content."
         );
     }
 
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/ServiceTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/ServiceTest.java
new file mode 100644
index 0000000..9403925
--- /dev/null
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/ServiceTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.aries.jax.rs.rest.management.test;
+
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICE_JSON_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICE_XML_TYPE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+
+import org.apache.aries.jax.rs.rest.management.schema.ServiceSchema;
+import org.junit.jupiter.api.Test;
+import org.xmlunit.assertj3.XmlAssert;
+
+import net.javacrumbs.jsonunit.assertj.JsonAssertions;
+
+public class ServiceTest extends TestUtil {
+
+    @Test
+    public void getServiceJSON() {
+        WebTarget target = createDefaultTarget().path(
+            "framework"
+        ).path("service").path("{serviceid}");
+
+        Response response = target.resolveTemplate(
+            "serviceid", 1l
+        ).request(
+            APPLICATION_SERVICE_JSON_TYPE
+        ).get();
+
+        String result = response.readEntity(String.class);
+
+        JsonAssertions.assertThatJson(
+            result
+        ).and(
+            j -> j.isObject(),
+            j1 -> j1.node("id").isNumber().isEqualByComparingTo("1"),
+            j1 -> j1.node("properties").and(
+                j2 -> j2.isObject(),
+                j2 -> j2.node("objectClass").isArray().contains("org.osgi.service.log.LogReaderService", "org.eclipse.equinox.log.ExtendedLogReaderService"),
+                j2 -> j2.node("service\\.scope").isString().contains("bundle"),
+                j2 -> j2.node("service\\.id").isNumber().isEqualByComparingTo("1"),
+                j2 -> j2.node("service\\.bundleid").isNumber().isEqualByComparingTo("0")
+            ),
+            j1 -> j1.node("bundle").isString().contains("http://", "/rms/framework/bundle/"),
+            j1 -> j1.node("usingBundles").isArray()
+        );
+    }
+
+    @Test
+    public void getServiceXML() {
+        WebTarget target = createDefaultTarget().path(
+            "framework"
+        ).path("service").path("{serviceid}");
+
+        Response response = target.resolveTemplate(
+            "serviceid", 1l
+        ).request(
+            APPLICATION_SERVICE_XML_TYPE
+        ).get();
+
+        String result = response.readEntity(String.class);
+
+        XmlAssert.assertThat(
+            result
+        ).isInvalid().valueByXPath(
+            "//service/id"
+        ).isEqualTo("1");
+
+        XmlAssert.assertThat(
+            result
+        ).valueByXPath(
+            "//service/properties/property[3]/@name"
+        ).isEqualTo("service.id");
+
+        XmlAssert.assertThat(
+            result
+        ).valueByXPath(
+            "//service/properties/property[3]/@type"
+        ).isEqualTo("Long");
+
+        XmlAssert.assertThat(
+            result
+        ).valueByXPath(
+            "//service/properties/property[3]/@value"
+        ).isEqualTo("1");
+    }
+
+    @Test
+    public void getServiceDTOJSON() {
+        WebTarget target = createDefaultTarget().path(
+            "framework"
+        ).path("service").path("{serviceid}");
+
+        Response response = target.resolveTemplate(
+            "serviceid", 1l
+        ).request(
+            APPLICATION_SERVICE_JSON_TYPE
+        ).get();
+
+        ServiceSchema serviceSchema = response.readEntity(ServiceSchema.class);
+
+        assertThat(
+            serviceSchema.id
+        ).isEqualTo(
+            1l
+        );
+    }
+
+    @Test
+    public void getServiceDTOXML() {
+        WebTarget target = createDefaultTarget().path(
+            "framework"
+        ).path("service").path("{serviceid}");
+
+        Response response = target.resolveTemplate(
+            "serviceid", 1l
+        ).request(
+            APPLICATION_SERVICE_XML_TYPE
+        ).get();
+
+        ServiceSchema serviceSchema = response.readEntity(ServiceSchema.class);
+
+        assertThat(
+            serviceSchema.id
+        ).isEqualTo(
+            1l
+        );
+    }
+
+    //@Test
+    public void getService28XML() {
+        WebTarget target = createDefaultTarget().path(
+            "framework"
+        ).path("service").path("{serviceid}");
+
+        Response response = target.resolveTemplate(
+            "serviceid", 28l
+        ).request(
+            APPLICATION_SERVICE_XML_TYPE
+        ).get();
+
+        String result = response.readEntity(String.class);
+
+        XmlAssert.assertThat(
+            result
+        ).isInvalid().valueByXPath(
+            "//service/id"
+        ).isEqualTo("28");
+    }
+
+    //@Test
+    public void getService28DTOXML() {
+        WebTarget target = createDefaultTarget().path(
+            "framework"
+        ).path("service").path("{serviceid}");
+
+        Response response = target.resolveTemplate(
+            "serviceid", 28l
+        ).request(
+            APPLICATION_SERVICE_XML_TYPE
+        ).get();
+
+        ServiceSchema serviceSchema = response.readEntity(ServiceSchema.class);
+
+        assertThat(
+            serviceSchema.id
+        ).isEqualTo(
+            28l
+        );
+    }
+
+}
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/ServicesTest.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/ServicesTest.java
index 76a1da0..1d47967 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/ServicesTest.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/ServicesTest.java
@@ -21,38 +21,24 @@ import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.AP
 import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE;
 import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_REPRESENTATIONS_XML_TYPE;
 import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICE_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICE_XML_TYPE;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.data.MapEntry.entry;
 
+import java.util.Arrays;
 import java.util.Map;
 
 import javax.ws.rs.client.WebTarget;
 import javax.ws.rs.core.Response;
 
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.apache.aries.jax.rs.rest.management.model.ServiceReferenceDTOs;
-import org.apache.aries.jax.rs.rest.management.model.ServicesDTO;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.dto.ServiceReferenceDTO;
-import org.osgi.test.common.annotation.InjectBundleContext;
-import org.osgi.test.junit4.context.BundleContextRule;
+import org.apache.aries.jax.rs.rest.management.schema.ServiceSchemaListSchema;
+import org.apache.aries.jax.rs.rest.management.schema.ServiceListSchema;
+import org.junit.jupiter.api.Test;
 import org.xmlunit.assertj3.XmlAssert;
 
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
 
 public class ServicesTest extends TestUtil {
 
-    @Rule
-    public BundleContextRule bundleContextRule = new BundleContextRule();
-
-    @InjectBundleContext
-    BundleContext bundleContext;
-
     @Test
     public void getServicesJSON() {
         WebTarget target = createDefaultTarget().path(
@@ -99,13 +85,11 @@ public class ServicesTest extends TestUtil {
             "framework"
         ).path("services");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request(
             APPLICATION_SERVICES_JSON_TYPE
         ).get();
 
-        ServicesDTO servicesDTO = response.readEntity(ServicesDTO.class);
+        ServiceListSchema servicesDTO = response.readEntity(ServiceListSchema.class);
 
         assertThat(
             servicesDTO.services
@@ -120,13 +104,11 @@ public class ServicesTest extends TestUtil {
             "framework"
         ).path("services");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request(
             APPLICATION_SERVICES_XML_TYPE
         ).get();
 
-        ServicesDTO servicesDTO = response.readEntity(ServicesDTO.class);
+        ServiceListSchema servicesDTO = response.readEntity(ServiceListSchema.class);
 
         assertThat(
             servicesDTO.services
@@ -210,16 +192,14 @@ public class ServicesTest extends TestUtil {
             "framework"
         ).path("services").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request(
             APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE
         ).get();
 
-        ServiceReferenceDTOs serviceReferenceDTOs = response.readEntity(ServiceReferenceDTOs.class);
+        ServiceSchemaListSchema serviceSchemaListSchema = response.readEntity(ServiceSchemaListSchema.class);
 
         assertThat(
-            serviceReferenceDTOs.services
+            serviceSchemaListSchema.services
         ).isNotEmpty();
     }
 
@@ -229,183 +209,17 @@ public class ServicesTest extends TestUtil {
             "framework"
         ).path("services").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.request(
             APPLICATION_SERVICES_REPRESENTATIONS_XML_TYPE
         ).get();
 
-        ServiceReferenceDTOs serviceReferenceDTOs = response.readEntity(ServiceReferenceDTOs.class);
+        ServiceSchemaListSchema serviceSchemaListSchema = response.readEntity(ServiceSchemaListSchema.class);
 
         assertThat(
-            serviceReferenceDTOs.services
+            serviceSchemaListSchema.services
         ).isNotEmpty();
     }
 
-    //////////
-
-    @Test
-    public void getServiceJSON() {
-        WebTarget target = createDefaultTarget().path(
-            "framework"
-        ).path("service").path("{serviceid}");
-
-        Response response = target.resolveTemplate(
-            "serviceid", 1l
-        ).request(
-            APPLICATION_SERVICE_JSON_TYPE
-        ).get();
-
-        String result = response.readEntity(String.class);
-
-        JsonAssertions.assertThatJson(
-            result
-        ).and(
-            j -> j.isObject(),
-            j1 -> j1.node("id").isNumber().isEqualByComparingTo("1"),
-            j1 -> j1.node("properties").and(
-                j2 -> j2.isObject(),
-                j2 -> j2.node("objectClass").isArray().contains("org.osgi.service.log.LogReaderService", "org.eclipse.equinox.log.ExtendedLogReaderService"),
-                j2 -> j2.node("service\\.scope").isString().contains("bundle"),
-                j2 -> j2.node("service\\.id").isNumber().isEqualByComparingTo("1"),
-                j2 -> j2.node("service\\.bundleid").isNumber().isEqualByComparingTo("0")
-            ),
-            j1 -> j1.node("bundle").isString().contains("http://", "/rms/framework/bundle/"),
-            j1 -> j1.node("usingBundles").isArray()
-        );
-    }
-
-    @Test
-    public void getServiceXML() {
-        WebTarget target = createDefaultTarget().path(
-            "framework"
-        ).path("service").path("{serviceid}");
-
-        Response response = target.resolveTemplate(
-            "serviceid", 1l
-        ).request(
-            APPLICATION_SERVICE_XML_TYPE
-        ).get();
-
-        String result = response.readEntity(String.class);
-
-        XmlAssert.assertThat(
-            result
-        ).isInvalid().valueByXPath(
-            "//service/id"
-        ).isEqualTo("1");
-
-        XmlAssert.assertThat(
-            result
-        ).valueByXPath(
-            "//service/properties/property[3]/@name"
-        ).isEqualTo("service.id");
-
-        XmlAssert.assertThat(
-            result
-        ).valueByXPath(
-            "//service/properties/property[3]/@type"
-        ).isEqualTo("Long");
-
-        XmlAssert.assertThat(
-            result
-        ).valueByXPath(
-            "//service/properties/property[3]/@value"
-        ).isEqualTo("1");
-    }
-
-    @Test
-    public void getServiceDTOJSON() {
-        WebTarget target = createDefaultTarget().path(
-            "framework"
-        ).path("service").path("{serviceid}");
-
-        target.register(RestManagementMessageBodyHandler.class);
-
-        Response response = target.resolveTemplate(
-            "serviceid", 1l
-        ).request(
-            APPLICATION_SERVICE_JSON_TYPE
-        ).get();
-
-        ServiceReferenceDTO serviceReferenceDTO = response.readEntity(ServiceReferenceDTO.class);
-
-        assertThat(
-            serviceReferenceDTO.id
-        ).isEqualTo(
-            1l
-        );
-    }
-
-    @Test
-    public void getServiceDTOXML() {
-        WebTarget target = createDefaultTarget().path(
-            "framework"
-        ).path("service").path("{serviceid}");
-
-        target.register(RestManagementMessageBodyHandler.class);
-
-        Response response = target.resolveTemplate(
-            "serviceid", 1l
-        ).request(
-            APPLICATION_SERVICE_XML_TYPE
-        ).get();
-
-        ServiceReferenceDTO serviceReferenceDTO = response.readEntity(ServiceReferenceDTO.class);
-
-        assertThat(
-            serviceReferenceDTO.id
-        ).isEqualTo(
-            1l
-        );
-    }
-
-    @Ignore("These are just tests for property coercion")
-    @Test
-    public void getService28XML() {
-        WebTarget target = createDefaultTarget().path(
-            "framework"
-        ).path("service").path("{serviceid}");
-
-        Response response = target.resolveTemplate(
-            "serviceid", 28l
-        ).request(
-            APPLICATION_SERVICE_XML_TYPE
-        ).get();
-
-        String result = response.readEntity(String.class);
-
-        XmlAssert.assertThat(
-            result
-        ).isInvalid().valueByXPath(
-            "//service/id"
-        ).isEqualTo("28");
-    }
-
-    @Ignore("These are just tests for property coercion")
-    @Test
-    public void getService28DTOXML() {
-        WebTarget target = createDefaultTarget().path(
-            "framework"
-        ).path("service").path("{serviceid}");
-
-        target.register(RestManagementMessageBodyHandler.class);
-
-        Response response = target.resolveTemplate(
-            "serviceid", 28l
-        ).request(
-            APPLICATION_SERVICE_XML_TYPE
-        ).get();
-
-        ServiceReferenceDTO serviceReferenceDTO = response.readEntity(ServiceReferenceDTO.class);
-
-        assertThat(
-            serviceReferenceDTO.id
-        ).isEqualTo(
-            28l
-        );
-    }
-
     ////////////
 
     @Test
@@ -459,15 +273,13 @@ public class ServicesTest extends TestUtil {
             "framework"
         ).path("services");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.queryParam(
             "filter", "(service.id=25)"
         ).request(
             APPLICATION_SERVICES_JSON_TYPE
         ).get();
 
-        ServicesDTO servicesDTO = response.readEntity(ServicesDTO.class);
+        ServiceListSchema servicesDTO = response.readEntity(ServiceListSchema.class);
 
         assertThat(
             servicesDTO.services.get(0)
@@ -482,15 +294,13 @@ public class ServicesTest extends TestUtil {
             "framework"
         ).path("services");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.queryParam(
             "filter", "(service.id=25)"
         ).request(
             APPLICATION_SERVICES_XML_TYPE
         ).get();
 
-        ServicesDTO servicesDTO = response.readEntity(ServicesDTO.class);
+        ServiceListSchema servicesDTO = response.readEntity(ServiceListSchema.class);
 
         assertThat(
             servicesDTO.services.get(0)
@@ -505,18 +315,16 @@ public class ServicesTest extends TestUtil {
             "framework"
         ).path("services").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.queryParam(
-            "filter", "(objectClass=org.apache.aries.jax.rs.*)"
+            "filter", "(objectClass=org.eclipse.osgi.*)"
         ).request(
             APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE
         ).get();
 
-        ServiceReferenceDTOs serviceReferenceDTOs = response.readEntity(ServiceReferenceDTOs.class);
+        ServiceSchemaListSchema serviceSchemaListSchema = response.readEntity(ServiceSchemaListSchema.class);
 
         assertThat(
-            serviceReferenceDTOs.services.get(0)
+            serviceSchemaListSchema.services.get(0)
         ).hasFieldOrProperty(
             "bundle"
         ).hasFieldOrProperty(
@@ -527,12 +335,12 @@ public class ServicesTest extends TestUtil {
             "usingBundles"
         );
 
-        Map<String, Object> properties = serviceReferenceDTOs.services.get(0).properties;
+        Map<String, Object> properties = serviceSchemaListSchema.services.get(0).properties;
 
         assertThat(properties).contains(
-            entry("objectClass", new String[] {"org.apache.aries.jax.rs.rest.management.internal.FrameworkResource"})
+            entry("objectClass", Arrays.asList("org.eclipse.osgi.framework.log.FrameworkLog"))
         ).contains(
-            entry("osgi.jaxrs.application.select", "(osgi.jaxrs.name=RestManagementApplication)")
+            entry("service.scope", "bundle")
         );
     }
 
@@ -542,18 +350,16 @@ public class ServicesTest extends TestUtil {
             "framework"
         ).path("services").path("representations");
 
-        target.register(RestManagementMessageBodyHandler.class);
-
         Response response = target.queryParam(
-            "filter", "(objectclass=org.apache.aries.jax.rs.*)"
+            "filter", "(objectclass=org.eclipse.osgi.*)"
         ).request(
             APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE
         ).get();
 
-        ServiceReferenceDTOs serviceReferenceDTOs = response.readEntity(ServiceReferenceDTOs.class);
+        ServiceSchemaListSchema serviceSchemaListSchema = response.readEntity(ServiceSchemaListSchema.class);
 
         assertThat(
-            serviceReferenceDTOs.services.get(0)
+            serviceSchemaListSchema.services.get(0)
         ).hasFieldOrProperty(
             "bundle"
         ).hasFieldOrProperty(
@@ -564,12 +370,12 @@ public class ServicesTest extends TestUtil {
             "usingBundles"
         );
 
-        Map<String, Object> properties = serviceReferenceDTOs.services.get(0).properties;
+        Map<String, Object> properties = serviceSchemaListSchema.services.get(0).properties;
 
         assertThat(properties).contains(
-            entry("objectClass", new String[] {"org.apache.aries.jax.rs.rest.management.internal.FrameworkResource"})
+            entry("objectClass", Arrays.asList("org.eclipse.osgi.framework.log.FrameworkLog"))
         ).contains(
-            entry("osgi.jaxrs.application.select", "(osgi.jaxrs.name=RestManagementApplication)")
+            entry("service.scope", "bundle")
         );
     }
 
diff --git a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/TestUtil.java b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/TestUtil.java
index 53df239..c2ebef6 100644
--- a/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/TestUtil.java
+++ b/integrations/rest-management/rest-management-itest/src/main/java/org/apache/aries/jax/rs/rest/management/test/TestUtil.java
@@ -17,6 +17,7 @@
 
 package org.apache.aries.jax.rs.rest.management.test;
 
+import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.osgi.service.jaxrs.runtime.JaxrsServiceRuntimeConstants.JAX_RS_SERVICE_ENDPOINT;
 
 import java.io.IOException;
@@ -28,22 +29,29 @@ import java.net.URL;
 import java.net.URLConnection;
 import java.util.Collection;
 import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
 
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.ClientBuilder;
 import javax.ws.rs.client.WebTarget;
 
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.junit.Rule;
+import org.apache.aries.jax.rs.rest.management.feature.RestManagementFeature;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
 import org.osgi.service.jaxrs.runtime.JaxrsServiceRuntime;
+import org.osgi.test.common.annotation.InjectBundleContext;
 import org.osgi.test.common.annotation.InjectService;
 import org.osgi.test.common.service.ServiceAware;
-import org.osgi.test.junit4.service.ServiceRule;
+import org.osgi.test.junit5.context.BundleContextExtension;
+import org.osgi.test.junit5.service.ServiceExtension;
 
+@ExtendWith({
+    BundleContextExtension.class,
+    ServiceExtension.class
+})
 public class TestUtil {
-    @Rule
-    public ServiceRule serviceRule = new ServiceRule();
 
     @InjectService
     public ClientBuilder clientBuilder;
@@ -51,13 +59,29 @@ public class TestUtil {
     @InjectService(filter = "(%s=*)", filterArguments = JAX_RS_SERVICE_ENDPOINT)
     public ServiceAware<JaxrsServiceRuntime> jaxrsServiceRuntimeAware;
 
+    @InjectBundleContext
+    public BundleContext bundleContext;
+
+    @BeforeEach
+    public void beforeEach(@InjectBundleContext BundleContext bundleContext) {
+        Stream.of(bundleContext.getBundles()).filter(b -> b.getSymbolicName().equals("minor-and-removed-change")).forEach(
+            b -> {
+                try {
+                    b.uninstall();
+                } catch (BundleException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        );
+    }
+
     protected WebTarget createDefaultTarget() {
-        clientBuilder.connectTimeout(600000, TimeUnit.SECONDS);
-        clientBuilder.readTimeout(600000, TimeUnit.SECONDS);
+        clientBuilder.connectTimeout(600000, SECONDS);
+        clientBuilder.readTimeout(600000, SECONDS);
 
         Client client = clientBuilder.build();
 
-        client.register(RestManagementMessageBodyHandler.class);
+        client.register(RestManagementFeature.class);
 
         return client.target(runtimeURI());
     }
diff --git a/integrations/rest-management/rest-management/README.md b/integrations/rest-management/rest-management/README.md
new file mode 100644
index 0000000..877d229
--- /dev/null
+++ b/integrations/rest-management/rest-management/README.md
@@ -0,0 +1,24 @@
+## Apache Aries JAX-RS Rest Management Service
+
+Welcome to the Apache Aries JAX-RS OSGi REST Management integration. This integration implements **Chapter 137** of the **OSGi R7 Compendium** [REST Management Service Specification](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.rest.html).
+
+In essence this integration allows for management and introspection of the OSGi framework over REST.
+
+### Rest Management Service Location
+
+Since there should only be one management API per framework the integration creates a separate application rooted at `${osgi.jaxrs.endpoint}/rms`
+
+### Open API
+
+To simplify developer experience there is an Open API endpoint mounted at `${osgi.jaxrs.endpoint}/rms/openapi.(json|yaml)`.
+
+#### TODO
+
+- fix conditional response type based on extension logic to account for mediatype resource method parameters
+
+##### Wish list
+
+- add HATEOS-style links within representations that allow for references to associated resources (e.g. in bundle representation add links to state, startlevel, headers)
+- add a extensions/inspect[/{bundleid}] (requirements and capabilities) resource (akin to gogo inspect command)
+- add a extension/repository that returns the [XML Repository Format](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.repository.html#i3247820)
+- add a extension/cm* for integration for Configuration admin (uses [Configuration Resource Format](https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.configurator.html#d0e131566))
\ No newline at end of file
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/RestManagementConstants.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/RestManagementConstants.java
index ac7003a..7dfd335 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/RestManagementConstants.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/RestManagementConstants.java
@@ -21,6 +21,10 @@ import javax.ws.rs.core.MediaType;
 
 public class RestManagementConstants {
 
+    public static final String SPECIFICATION_IMPLEMENTATION = "osgi.rest";
+
+    public static final String SPECIFICATION_VERSION = "1.0.0";
+
     public static final String APPLICATION_BUNDLE_JSON =
         "application/org.osgi.bundle+json";
 
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/feature/RestManagementFeature.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/feature/RestManagementFeature.java
new file mode 100644
index 0000000..03c3a6c
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/feature/RestManagementFeature.java
@@ -0,0 +1,17 @@
+package org.apache.aries.jax.rs.rest.management.feature;
+
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
+
+import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
+
+public class RestManagementFeature implements Feature {
+
+    @Override
+    public boolean configure(FeatureContext context) {
+        context.register(new JacksonJsonProvider());
+
+        return true;
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/package-info.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/feature/package-info.java
similarity index 94%
rename from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/package-info.java
rename to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/feature/package-info.java
index 1bf0e1c..0a1954e 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/package-info.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/feature/package-info.java
@@ -17,7 +17,7 @@
 
 @Export
 @Version("1.0.0")
-package org.apache.aries.jax.rs.rest.management.handler;
+package org.apache.aries.jax.rs.rest.management.feature;
 
 import org.osgi.annotation.bundle.Export;
 import org.osgi.annotation.versioning.Version;
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/DictionaryJsonDeserializer.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/DictionaryJsonDeserializer.java
deleted file mode 100644
index 8fc9f2d..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/DictionaryJsonDeserializer.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.handler;
-
-import java.io.IOException;
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-
-@SuppressWarnings("serial")
-class DictionaryJsonDeserializer extends StdDeserializer<Dictionary<String, String>> {
-
-    protected DictionaryJsonDeserializer() {
-        this(null);
-    }
-
-    protected DictionaryJsonDeserializer(Class<Dictionary<String, String>> t) {
-        super(t);
-    }
-
-    @Override
-    public Dictionary<String, String> deserialize(JsonParser jp, DeserializationContext ctxt)
-        throws IOException {
-
-        Dictionary<String, String> dictionary = new Hashtable<>();
-        JsonNode node = jp.getCodec().readTree(jp);
-        node.fields().forEachRemaining(entry -> dictionary.put(entry.getKey(), entry.getValue().asText()));
-        return dictionary;
-    }
-
-}
\ No newline at end of file
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/DictionaryJsonSerializer.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/DictionaryJsonSerializer.java
deleted file mode 100644
index f49b8c2..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/DictionaryJsonSerializer.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.handler;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Dictionary;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
-
-@SuppressWarnings({ "serial", "rawtypes" })
-class DictionaryJsonSerializer extends StdSerializer<Dictionary> {
-
-    protected DictionaryJsonSerializer() {
-        this(null);
-    }
-
-    protected DictionaryJsonSerializer(Class<Dictionary> t) {
-        super(t);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public void serialize(
-            Dictionary value, JsonGenerator gen, SerializerProvider provider)
-        throws IOException {
-
-        gen.writeStartObject();
-
-        Collections.<String>list(value.keys()).stream().sorted().forEach(
-            key -> {
-                try {
-                    gen.writeStringField(
-                        String.valueOf(key),
-                        String.valueOf(value.get(key))
-                    );
-                }
-                catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        );
-
-        gen.writeEndObject();
-    }
-
-}
\ No newline at end of file
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/RestManagementMessageBodyHandler.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/RestManagementMessageBodyHandler.java
deleted file mode 100644
index fa1cca5..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/RestManagementMessageBodyHandler.java
+++ /dev/null
@@ -1,992 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.handler;
-
-import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
-import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE;
-import static javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEHEADER_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEHEADER_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTARTLEVEL_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTARTLEVEL_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTATE_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTATE_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLES_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLES_REPRESENTATIONS_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLES_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_FRAMEWORKSTARTLEVEL_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_REPRESENTATIONS_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_XML_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICE_JSON_TYPE;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICE_XML_TYPE;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Function;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.UriInfo;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-import javax.xml.namespace.QName;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.XMLEvent;
-
-import org.apache.aries.jax.rs.rest.management.model.BundleStateDTO;
-import org.apache.aries.jax.rs.rest.management.model.BundlesDTO;
-import org.apache.aries.jax.rs.rest.management.model.ServiceReferenceDTOs;
-import org.apache.aries.jax.rs.rest.management.model.ServicesDTO;
-import org.osgi.framework.dto.BundleDTO;
-import org.osgi.framework.dto.FrameworkDTO;
-import org.osgi.framework.dto.ServiceReferenceDTO;
-import org.osgi.framework.startlevel.dto.BundleStartLevelDTO;
-import org.osgi.framework.startlevel.dto.FrameworkStartLevelDTO;
-import org.w3c.dom.Element;
-
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-
-public class RestManagementMessageBodyHandler
-    implements MessageBodyReader<Object>,
-        MessageBodyWriter<Object> {
-
-    private static final TypeReference<Collection<BundleDTO>> BUNDLEDTO_COLLECTION =
-        new TypeReference<Collection<BundleDTO>>() {};
-    private static final TypeReference<Collection<ServiceReferenceDTO>> SERVICEDTO_COLLECTION =
-        new TypeReference<Collection<ServiceReferenceDTO>>() {};
-    private static final TypeReference<Dictionary<String, String>> BUNDLE_HEADER =
-        new TypeReference<Dictionary<String, String>>() {};
-    private final JAXBContext context;
-
-    private final XMLSerializer serializer;
-    private final XMLDeserializer deserializer;
-    private final ServiceReferenceDTOXMLDeserializer serviceReferenceDTO_XMLDeserializer;
-    private final ServiceReferenceDTOXMLSerializer serviceReferenceDTO_XMLSerializer;
-
-    private final Function<UriInfo, ObjectMapper> jsonMapperFunction = uriInfo -> {
-        ObjectMapper jsonMapper = new ObjectMapper().configure(
-            INDENT_OUTPUT, true
-        );
-
-        SimpleModule module = new SimpleModule();
-        module.addSerializer(Dictionary.class, new DictionaryJsonSerializer());
-        module.addDeserializer(Dictionary.class, new DictionaryJsonDeserializer());
-        module.addSerializer(ServiceReferenceDTO.class, new ServiceReferenceDTOJsonSerializer(uriInfo));
-        module.addDeserializer(ServiceReferenceDTO.class, new ServiceReferenceDTOJsonDeserializer());
-
-        return jsonMapper.registerModule(module);
-    };
-
-    @Context
-    volatile UriInfo uriInfo;
-
-    public RestManagementMessageBodyHandler() {
-
-        serializer = new XMLSerializer();
-        deserializer = new XMLDeserializer();
-        serviceReferenceDTO_XMLDeserializer = new ServiceReferenceDTOXMLDeserializer(deserializer);
-        serviceReferenceDTO_XMLSerializer = new ServiceReferenceDTOXMLSerializer(serializer);
-
-        try {
-            context = JAXBContext.newInstance(
-                BundleDTO.class,
-                BundleDTO[].class,
-                BundlesDTO.class,
-                BundleStartLevelDTO.class,
-                BundleStateDTO.class,
-                Dictionary.class,
-                FrameworkStartLevelDTO.class,
-                FrameworkDTO.class,
-                ServicesDTO.class,
-                ServiceReferenceDTO.class,
-                ServiceReferenceDTOs.class
-            );
-        }
-        catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
-    public boolean isReadable(
-        Class<?> type, Type genericType, Annotation[] annotations,
-        MediaType mediaType) {
-
-        return
-            (Collection.class.isAssignableFrom(type) &&
-                nthTypeArgumentIs(0, genericType, BundleDTO.class) && (
-                APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_BUNDLES_REPRESENTATIONS_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (Collection.class.isAssignableFrom(type) &&
-                nthTypeArgumentIs(0, genericType, ServiceReferenceDTO.class) && (
-                APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_SERVICES_REPRESENTATIONS_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (Dictionary.class.isAssignableFrom(type) &&
-                nthTypeArgumentIs(0, genericType, String.class) &&
-                nthTypeArgumentIs(1, genericType, String.class) && (
-                APPLICATION_BUNDLEHEADER_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_BUNDLEHEADER_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (type == BundleDTO.class && (
-                APPLICATION_BUNDLE_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_BUNDLE_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (type == BundlesDTO.class && (
-                APPLICATION_BUNDLES_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_BUNDLES_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (type == BundleStateDTO.class && (
-                APPLICATION_BUNDLESTATE_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_BUNDLESTATE_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (type == BundleStartLevelDTO.class && (
-                APPLICATION_BUNDLESTARTLEVEL_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_BUNDLESTARTLEVEL_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (type == FrameworkStartLevelDTO.class && (
-                APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_FRAMEWORKSTARTLEVEL_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (type == FrameworkDTO.class && (
-                APPLICATION_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (type == ServicesDTO.class && (
-                APPLICATION_SERVICES_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_SERVICES_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (type == ServiceReferenceDTO.class && (
-                APPLICATION_SERVICE_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_SERVICE_XML_TYPE.isCompatible(mediaType)))
-                ||
-            (type == ServiceReferenceDTOs.class && (
-                APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE.isCompatible(mediaType) ||
-                APPLICATION_SERVICES_REPRESENTATIONS_XML_TYPE.isCompatible(mediaType)))
-            ;
-    }
-
-    @Override
-    public boolean isWriteable(
-        Class<?> type, Type genericType, Annotation[] annotations,
-        MediaType mediaType) {
-
-        return isReadable(type, genericType, annotations, mediaType);
-    }
-
-    BundleDTO readBundleDTOFrom(
-            Class<? extends BundleDTO> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders,
-            InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLE_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(type).readValue(entityStream);
-        }
-        else if (APPLICATION_BUNDLE_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                return (BundleDTO)context.createUnmarshaller().unmarshal(
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-
-        return null;
-    }
-
-    Collection<BundleDTO> readBundleDTOListFrom(
-            @SuppressWarnings("rawtypes") Class<? extends Collection> type,
-            Type genericType, Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(BUNDLEDTO_COLLECTION).readValue(entityStream);
-        }
-        else if (APPLICATION_BUNDLES_REPRESENTATIONS_XML_TYPE.isCompatible(mediaType)) {
-            List<BundleDTO> bundles = new ArrayList<>();
-            AtomicReference<BundleDTO> bundle = new AtomicReference<>();
-            deserializer.deserialize((start, next) -> {
-                String el = start.getName().getLocalPart();
-                XMLEvent event = start;
-                if (el.equals("bundle")) {
-                    bundle.set(new BundleDTO());
-                }
-                else if (el.equals("id")) {
-                    try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                    bundle.get().id = Long.parseLong(event.asCharacters().getData());
-                }
-                else if (el.equals("lastModified")) {
-                    try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                    bundle.get().lastModified = Long.parseLong(event.asCharacters().getData());
-                }
-                else if (el.equals("state")) {
-                    try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                    bundle.get().state = Integer.parseInt(event.asCharacters().getData());
-                }
-                else if (el.equals("symbolicName")) {
-                    try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                    bundle.get().symbolicName = event.asCharacters().getData();
-                }
-                else if (el.equals("version")) {
-                    try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                    bundle.get().version = event.asCharacters().getData();
-                }
-                return event;
-            }, end -> {
-                String el = end.getName().getLocalPart();
-                if (el.equals("bundle")) {
-                    bundles.add(bundle.get());
-                    bundle.set(null);
-                }
-            }, entityStream);
-
-            return bundles;
-        }
-
-        return null;
-    }
-
-    Dictionary<String, String> readBundleHeadersFrom(
-            @SuppressWarnings("rawtypes") Class<? extends Dictionary> asSubclass,
-            Type genericType, Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-        throws IOException, WebApplicationException{
-
-        if (APPLICATION_BUNDLEHEADER_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(BUNDLE_HEADER).readValue(entityStream);
-        }
-        else if (APPLICATION_BUNDLEHEADER_XML_TYPE.isCompatible(mediaType)) {
-            Dictionary<String, String> header = new Hashtable<>();
-
-            deserializer.deserialize((start, next) -> {
-                String el = start.getName().getLocalPart();
-                if (el.equals("entry")) {
-                    Attribute keyAT = start.getAttributeByName(new QName("key"));
-                    Attribute valueAT = start.getAttributeByName(new QName("value"));
-                    header.put(keyAT.getValue(), valueAT.getValue());
-                }
-                return start;
-            }, end -> {}, entityStream);
-
-            return header;
-        }
-
-        return null;
-    }
-
-    BundlesDTO readBundlesDTOFrom(
-            Class<? extends BundlesDTO> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders,
-            InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLES_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(type).readValue(entityStream);
-        }
-        else if (APPLICATION_BUNDLES_XML_TYPE.isCompatible(mediaType)) {
-            BundlesDTO bundlesDTO = new BundlesDTO();
-            bundlesDTO.bundles = new ArrayList<>();
-
-            deserializer.deserialize((start, next) -> {
-                String el = start.getName().getLocalPart();
-                XMLEvent event = start;
-                if (el.equals("uri")) {
-                    try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                    bundlesDTO.bundles.add(event.asCharacters().getData());
-                }
-                return start;
-            }, end -> {}, entityStream);
-
-            return bundlesDTO;
-        }
-
-        return null;
-    }
-
-    BundleStartLevelDTO readBundleStartLevelDTOFrom(
-            Class<? extends BundleStartLevelDTO> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLESTARTLEVEL_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(type).readValue(entityStream);
-        }
-        else if (APPLICATION_BUNDLESTARTLEVEL_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                return (BundleStartLevelDTO)context.createUnmarshaller().unmarshal(
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-
-        return null;
-    }
-
-    BundleStateDTO readBundleStateDTOFrom(
-            Class<? extends BundleStateDTO> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders,
-            InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLESTATE_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(type).readValue(entityStream);
-        }
-        else if (APPLICATION_BUNDLESTATE_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                return (BundleStateDTO)context.createUnmarshaller().unmarshal(
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-
-        return null;
-    }
-
-    FrameworkDTO readFrameworkDTOFrom(
-            Class<? extends FrameworkDTO> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders,
-            InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(type).readValue(entityStream);
-        }
-        else if (APPLICATION_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                return (FrameworkDTO)context.createUnmarshaller().unmarshal(
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-
-        return null;
-    }
-
-    FrameworkStartLevelDTO readFrameworkStartLevelDTOFrom(
-            Class<? extends FrameworkStartLevelDTO> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders,
-            InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(type).readValue(entityStream);
-        }
-        else if (APPLICATION_FRAMEWORKSTARTLEVEL_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                return (FrameworkStartLevelDTO)context.createUnmarshaller().unmarshal(
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public Object readFrom(
-            Class<Object> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders,
-            InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (Collection.class.isAssignableFrom(type) &&
-            nthTypeArgumentIs(0, genericType, BundleDTO.class)) {
-
-            return readBundleDTOListFrom(
-                type.asSubclass(Collection.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (Collection.class.isAssignableFrom(type) &&
-            nthTypeArgumentIs(0, genericType, ServiceReferenceDTO.class)) {
-
-            return readServiceReferenceDTOListFrom(
-                type.asSubclass(Collection.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (Dictionary.class.isAssignableFrom(type) &&
-            nthTypeArgumentIs(0, genericType, String.class) &&
-            nthTypeArgumentIs(1, genericType, String.class)) {
-
-            return readBundleHeadersFrom(
-                type.asSubclass(Dictionary.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (BundleDTO.class.equals(type)) {
-            return readBundleDTOFrom(
-                type.asSubclass(BundleDTO.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (BundlesDTO.class.equals(type)) {
-            return readBundlesDTOFrom(
-                type.asSubclass(BundlesDTO.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (BundleStateDTO.class.equals(type)) {
-            return readBundleStateDTOFrom(
-                type.asSubclass(BundleStateDTO.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (BundleStartLevelDTO.class.equals(type)) {
-            return readBundleStartLevelDTOFrom(
-                type.asSubclass(BundleStartLevelDTO.class), genericType,
-                annotations, mediaType, httpHeaders, entityStream);
-        }
-        else if (FrameworkStartLevelDTO.class.equals(type)) {
-            return readFrameworkStartLevelDTOFrom(
-                type.asSubclass(FrameworkStartLevelDTO.class), genericType,
-                annotations, mediaType, httpHeaders, entityStream);
-        }
-        else if (FrameworkDTO.class.equals(type)) {
-            return readFrameworkDTOFrom(
-                type.asSubclass(FrameworkDTO.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (ServicesDTO.class.equals(type)) {
-            return readServicesDTOFrom(
-                type.asSubclass(ServicesDTO.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (ServiceReferenceDTO.class.equals(type)) {
-            return readServiceReferenceDTOFrom(
-                type.asSubclass(ServiceReferenceDTO.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (ServiceReferenceDTOs.class.equals(type)) {
-            return readServiceReferenceDTOsFrom(
-                type.asSubclass(ServiceReferenceDTOs.class), genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-
-        return null;
-    }
-
-    ServiceReferenceDTO readServiceReferenceDTOFrom(
-            Class<? extends ServiceReferenceDTO> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_SERVICE_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(type).readValue(entityStream);
-        }
-        else if (APPLICATION_SERVICE_XML_TYPE.isCompatible(mediaType)) {
-            return serviceReferenceDTO_XMLDeserializer.deserializeServiceReferenceDTO(entityStream);
-        }
-
-        return null;
-    }
-
-    Collection<ServiceReferenceDTO> readServiceReferenceDTOListFrom(
-            @SuppressWarnings("rawtypes") Class<? extends Collection> type,
-            Type genericType, Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(SERVICEDTO_COLLECTION).readValue(entityStream);
-        }
-        else if (APPLICATION_BUNDLES_REPRESENTATIONS_XML_TYPE.isCompatible(mediaType)) {
-            return serviceReferenceDTO_XMLDeserializer.deserializeServiceReferenceDTOList(entityStream);
-        }
-
-        return null;
-    }
-
-    ServiceReferenceDTOs readServiceReferenceDTOsFrom(
-            Class<? extends ServiceReferenceDTOs> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(type).readValue(entityStream);
-        }
-        else if (APPLICATION_SERVICES_REPRESENTATIONS_XML_TYPE.isCompatible(mediaType)) {
-            ServiceReferenceDTOs serviceReferenceDTOs = new ServiceReferenceDTOs();
-            serviceReferenceDTOs.services = serviceReferenceDTO_XMLDeserializer.deserializeServiceReferenceDTOList(entityStream);
-            return serviceReferenceDTOs;
-        }
-
-        return null;
-    }
-
-    ServicesDTO readServicesDTOFrom(
-            Class<? extends ServicesDTO> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-        throws IOException, WebApplicationException{
-
-        if (APPLICATION_SERVICES_JSON_TYPE.isCompatible(mediaType)) {
-            return jsonMapperFunction.apply(uriInfo).readerFor(type).readValue(entityStream);
-        }
-        else if (APPLICATION_SERVICES_XML_TYPE.isCompatible(mediaType)) {
-            ServicesDTO servicesDTO = new ServicesDTO();
-            servicesDTO.services = new ArrayList<>();
-
-            deserializer.deserialize((start, next) -> {
-                String el = start.getName().getLocalPart();
-                XMLEvent event = start;
-                if (el.equals("uri")) {
-                    try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                    servicesDTO.services.add(event.asCharacters().getData());
-                }
-                return start;
-            }, end -> {}, entityStream);
-
-            return servicesDTO;
-        }
-
-        return null;
-    }
-
-    void writeBundleDTOListTo(
-            Collection<BundleDTO> list, Class<?> type, Type genericType,
-            Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLES_REPRESENTATIONS_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, list);
-        }
-        else if (APPLICATION_BUNDLES_REPRESENTATIONS_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                serializer.serialize(
-                    "bundles",
-                    (dom, rootEl) -> list.stream().map(
-                        bundleDTO -> {
-                            Element bundleEl = dom.createElement("bundle");
-
-                            Element idEl = dom.createElement("id");
-                            idEl.setTextContent(String.valueOf(bundleDTO.id));
-                            Element lastModifiedEl = dom.createElement("lastModified");
-                            lastModifiedEl.setTextContent(String.valueOf(bundleDTO.lastModified));
-                            Element stateEl = dom.createElement("state");
-                            stateEl.setTextContent(String.valueOf(bundleDTO.state));
-                            Element symbolicNameEl = dom.createElement("symbolicName");
-                            symbolicNameEl.setTextContent(bundleDTO.symbolicName);
-                            Element versionEl = dom.createElement("version");
-                            versionEl.setTextContent(bundleDTO.version);
-
-                            bundleEl.appendChild(idEl);
-                            bundleEl.appendChild(lastModifiedEl);
-                            bundleEl.appendChild(stateEl);
-                            bundleEl.appendChild(symbolicNameEl);
-                            bundleEl.appendChild(versionEl);
-
-                            return bundleEl;
-                        }
-                    ).forEach(
-                        bundleEL -> rootEl.appendChild(bundleEL)
-                    ),
-                    entityStream
-                );
-            }
-            catch (Exception e) {
-                throw new IOException(e);
-            }
-        }
-    }
-
-    void writeBundleDTOTo(
-            BundleDTO bundleDTO,
-            Class<?> type, Type genericType, Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLE_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, bundleDTO);
-        }
-        else if (APPLICATION_BUNDLE_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                Marshaller marshaller = context.createMarshaller();
-                marshaller.setProperty(JAXB_FORMATTED_OUTPUT, true);
-                marshaller.marshal(
-                    new JAXBElement<>(
-                        new QName("bundle"),
-                        BundleDTO.class,
-                        bundleDTO),
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-    }
-
-    void writeBundleHeadersTo(
-            Dictionary<String, String> headers, Class<?> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException{
-
-        if (APPLICATION_BUNDLEHEADER_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, headers);
-        }
-        else if (APPLICATION_BUNDLEHEADER_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                serializer.serialize(
-                    "bundleHeader",
-                    (dom, rootEl) -> Collections.list(
-                        headers.keys()
-                    ).stream().forEach(
-                        key -> {
-                            Element entryEl = dom.createElement("entry");
-                            entryEl.setAttribute("key", key);
-                            entryEl.setAttribute("value", headers.get(key));
-                            rootEl.appendChild(entryEl);
-                        }
-                    ),
-                    entityStream
-                );
-            }
-            catch (Exception e) {
-                throw new IOException(e);
-            }
-        }
-    }
-
-    void writeBundlesDTOTo(
-            BundlesDTO bundlesDTO,
-            Class<?> type, Type genericType, Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLES_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, bundlesDTO);
-        }
-        else if (APPLICATION_BUNDLES_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                serializer.serialize(
-                    "bundles",
-                    (dom, rootEl) -> bundlesDTO.bundles.stream().forEach(
-                        key -> {
-                            Element entryEl = dom.createElement("uri");
-                            entryEl.setTextContent(key);
-                            rootEl.appendChild(entryEl);
-                        }
-                    ),
-                    entityStream
-                );
-            }
-            catch (Exception e) {
-                throw new IOException(e);
-            }
-        }
-    }
-
-    void writeBundleStartLevelDTOTo(
-            BundleStartLevelDTO bundleStartLevelDTO, Class<?> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLESTARTLEVEL_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, bundleStartLevelDTO);
-        }
-        else if (APPLICATION_BUNDLESTARTLEVEL_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                Marshaller marshaller = context.createMarshaller();
-                marshaller.setProperty(JAXB_FORMATTED_OUTPUT, true);
-                marshaller.marshal(
-                    new JAXBElement<>(
-                        new QName("bundleStartLevel"),
-                        BundleStartLevelDTO.class,
-                        bundleStartLevelDTO),
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-    }
-
-    void writeBundleStateDTOTo(
-            BundleStateDTO bundleStateDTO,
-            Class<?> type, Type genericType, Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_BUNDLESTATE_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, bundleStateDTO);
-        }
-        else if (APPLICATION_BUNDLESTATE_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                Marshaller marshaller = context.createMarshaller();
-                marshaller.setProperty(JAXB_FORMATTED_OUTPUT, true);
-                marshaller.marshal(
-                    new JAXBElement<>(
-                        new QName("bundleState"),
-                        BundleStateDTO.class,
-                        bundleStateDTO),
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-    }
-
-    void writeFrameworkDTOTo(
-            FrameworkDTO frameworkDTO,
-            Class<?> type, Type genericType, Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, frameworkDTO);
-        }
-        else if (APPLICATION_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                Marshaller marshaller = context.createMarshaller();
-                marshaller.setProperty(JAXB_FORMATTED_OUTPUT, true);
-                marshaller.marshal(
-                    new JAXBElement<>(
-                        new QName("framework"),
-                        FrameworkDTO.class,
-                        frameworkDTO),
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-    }
-
-    void writeFrameworkStartLevelDTOTo(
-            FrameworkStartLevelDTO frameworkStartLevelDTO,
-            Class<?> type, Type genericType, Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_FRAMEWORKSTARTLEVEL_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, frameworkStartLevelDTO);
-        }
-        else if (APPLICATION_FRAMEWORKSTARTLEVEL_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                Marshaller marshaller = context.createMarshaller();
-                marshaller.setProperty(JAXB_FORMATTED_OUTPUT, true);
-                marshaller.marshal(
-                    new JAXBElement<>(
-                        new QName("frameworkStartLevel"),
-                        FrameworkStartLevelDTO.class,
-                        frameworkStartLevelDTO),
-                    entityStream);
-            } catch (JAXBException e) {
-                throw new IOException(e);
-            }
-        }
-    }
-
-    void writeServiceReferenceDTOTo(
-            ServiceReferenceDTO serviceReferenceDTO, Class<?> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_SERVICE_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, serviceReferenceDTO);
-        }
-        else if (APPLICATION_SERVICE_XML_TYPE.isCompatible(mediaType)) {
-            serviceReferenceDTO_XMLSerializer.serialize(serviceReferenceDTO, uriInfo, entityStream);
-        }
-    }
-
-    void writeServiceReferenceDTOListTo(
-            Collection<ServiceReferenceDTO> list, Class<?> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, list);
-        }
-        else if (APPLICATION_SERVICES_REPRESENTATIONS_XML_TYPE.isCompatible(mediaType)) {
-            serviceReferenceDTO_XMLSerializer.serialize(list, uriInfo, entityStream);
-        }
-    }
-
-    void writeServiceReferenceDTOsTo(
-            ServiceReferenceDTOs serviceReferenceDTOs, Class<?> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, serviceReferenceDTOs);
-        }
-        else if (APPLICATION_SERVICES_REPRESENTATIONS_XML_TYPE.isCompatible(mediaType)) {
-            serviceReferenceDTO_XMLSerializer.serialize(
-                serviceReferenceDTOs.services, uriInfo, entityStream);
-        }
-    }
-
-    void writeServicesDTOTo(
-            ServicesDTO servicesDTO, Class<?> type, Type genericType,
-            Annotation[] annotations, MediaType mediaType,
-            MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (APPLICATION_SERVICES_JSON_TYPE.isCompatible(mediaType)) {
-            jsonMapperFunction.apply(uriInfo).writeValue(entityStream, servicesDTO);
-        }
-        else if (APPLICATION_SERVICES_XML_TYPE.isCompatible(mediaType)) {
-            try {
-                serializer.serialize(
-                    "services",
-                    (dom, rootEl) -> servicesDTO.services.stream().forEach(
-                        key -> {
-                            Element entryEl = dom.createElement("uri");
-                            entryEl.setTextContent(key);
-                            rootEl.appendChild(entryEl);
-                        }
-                    ),
-                    entityStream
-                );
-            }
-            catch (Exception e) {
-                throw new IOException(e);
-            }
-        }
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public void writeTo(
-            Object entity,
-            Class<?> type, Type genericType, Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
-            OutputStream entityStream)
-        throws IOException, WebApplicationException {
-
-        if (Collection.class.isAssignableFrom(type) &&
-            nthTypeArgumentIs(0, genericType, BundleDTO.class)) {
-
-            writeBundleDTOListTo(
-                Collection.class.cast(entity), type, genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (Collection.class.isAssignableFrom(type) &&
-            nthTypeArgumentIs(0, genericType, ServiceReferenceDTO.class)) {
-
-            writeServiceReferenceDTOListTo(
-                Collection.class.cast(entity), type, genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (Dictionary.class.isAssignableFrom(type) &&
-            nthTypeArgumentIs(0, genericType, String.class) &&
-            nthTypeArgumentIs(1, genericType, String.class)) {
-
-            writeBundleHeadersTo(
-                Dictionary.class.cast(entity), type, genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (type == BundleDTO.class) {
-            writeBundleDTOTo(
-                BundleDTO.class.cast(entity), type, genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (BundlesDTO.class.equals(type)) {
-            writeBundlesDTOTo(
-                BundlesDTO.class.cast(entity), type, genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (BundleStateDTO.class.equals(type)) {
-            writeBundleStateDTOTo(
-                BundleStateDTO.class.cast(entity), type, genericType,
-                annotations, mediaType, httpHeaders, entityStream);
-        }
-        else if (BundleStartLevelDTO.class.equals(type)) {
-            writeBundleStartLevelDTOTo(
-                BundleStartLevelDTO.class.cast(entity), type, genericType,
-                annotations, mediaType, httpHeaders, entityStream);
-        }
-        else if (FrameworkStartLevelDTO.class.equals(type)) {
-            writeFrameworkStartLevelDTOTo(
-                FrameworkStartLevelDTO.class.cast(entity), type, genericType,
-                annotations, mediaType, httpHeaders, entityStream);
-        }
-        else if (FrameworkDTO.class.equals(type)) {
-            writeFrameworkDTOTo(
-                FrameworkDTO.class.cast(entity), type, genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (ServiceReferenceDTO.class.equals(type)) {
-            writeServiceReferenceDTOTo(
-                ServiceReferenceDTO.class.cast(entity), type, genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (ServicesDTO.class.equals(type)) {
-            writeServicesDTOTo(
-                ServicesDTO.class.cast(entity), type, genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-        else if (ServiceReferenceDTOs.class.equals(type)) {
-            writeServiceReferenceDTOsTo(
-                ServiceReferenceDTOs.class.cast(entity), type, genericType, annotations,
-                mediaType, httpHeaders, entityStream);
-        }
-    }
-
-    private boolean nthTypeArgumentIs(int n, Type type, Class<?> clazz) {
-        return ((ParameterizedType)type).getActualTypeArguments()[n].equals(clazz);
-    }
-
-}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOJsonDeserializer.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOJsonDeserializer.java
deleted file mode 100644
index f06b666..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOJsonDeserializer.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.handler;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-import org.osgi.framework.dto.ServiceReferenceDTO;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-
-@SuppressWarnings("serial")
-class ServiceReferenceDTOJsonDeserializer extends StdDeserializer<ServiceReferenceDTO> {
-
-    protected ServiceReferenceDTOJsonDeserializer() {
-        this(null);
-    }
-
-    protected ServiceReferenceDTOJsonDeserializer(Class<ServiceReferenceDTO> t) {
-        super(t);
-    }
-
-    @Override
-    public ServiceReferenceDTO deserialize(JsonParser jp, DeserializationContext ctxt)
-        throws IOException {
-
-        ServiceReferenceDTO referenceDTO = new ServiceReferenceDTO();
-        JsonNode node = jp.getCodec().readTree(jp);
-        referenceDTO.id = node.get("id").asLong();
-        referenceDTO.properties = new HashMap<>();
-        node.get("properties").fields().forEachRemaining(
-            entry -> {
-                referenceDTO.properties.put(entry.getKey(), Coerce.from(entry));
-            }
-        );
-
-        String bundleURL = node.get("bundle").asText();
-        referenceDTO.bundle = Long.parseLong(bundleURL.substring(bundleURL.lastIndexOf('/') + 1));
-
-        List<Long> usingBundles = new ArrayList<>();
-        for (JsonNode arrayNode : (ArrayNode)node.get("usingBundles")) {
-            bundleURL = arrayNode.asText();
-            usingBundles.add(Long.parseLong(bundleURL.substring(bundleURL.lastIndexOf('/') + 1)));
-        }
-
-        referenceDTO.usingBundles = usingBundles.stream().mapToLong(Long::longValue).toArray();
-        return referenceDTO;
-    }
-
-}
\ No newline at end of file
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOJsonSerializer.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOJsonSerializer.java
deleted file mode 100644
index 90faa6a..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOJsonSerializer.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.handler;
-
-import java.io.IOException;
-
-import javax.ws.rs.core.UriInfo;
-
-import org.osgi.framework.dto.ServiceReferenceDTO;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
-
-@SuppressWarnings("serial")
-class ServiceReferenceDTOJsonSerializer extends StdSerializer<ServiceReferenceDTO> {
-
-    private final UriInfo uriInfo;
-
-    protected ServiceReferenceDTOJsonSerializer(UriInfo uriInfo) {
-        this(uriInfo, null);
-    }
-
-    protected ServiceReferenceDTOJsonSerializer(UriInfo uriInfo, Class<ServiceReferenceDTO> t) {
-        super(t);
-        this.uriInfo = uriInfo;
-    }
-
-    @Override
-    public void serialize(
-            ServiceReferenceDTO value, JsonGenerator gen, SerializerProvider provider)
-        throws IOException {
-
-        gen.writeStartObject();
-        gen.writeNumberField("id", value.id);
-        gen.writeObjectField("properties", value.properties);
-        gen.writeStringField(
-            "bundle",
-            uriInfo.getBaseUriBuilder().path("framework").path("bundle").path("{id}").build(value.bundle).toASCIIString()
-        );
-        gen.writeArrayFieldStart("usingBundles");
-        for (long usingBundle : value.usingBundles) {
-            gen.writeString(
-                uriInfo.getBaseUriBuilder().path("framework").path("bundle").path("{id}").build(usingBundle).toASCIIString()
-            );
-        }
-        gen.writeEndArray();
-        gen.writeEndObject();
-    }
-
-}
\ No newline at end of file
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOXMLDeserializer.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOXMLDeserializer.java
deleted file mode 100644
index 583ab8d..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOXMLDeserializer.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.handler;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Consumer;
-
-import javax.xml.namespace.QName;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.XMLEvent;
-
-import org.osgi.framework.dto.ServiceReferenceDTO;
-
-class ServiceReferenceDTOXMLDeserializer {
-
-    private final XMLDeserializer deserializer;
-
-    public ServiceReferenceDTOXMLDeserializer(XMLDeserializer deserializer) {
-        this.deserializer = deserializer;
-    }
-
-    public ServiceReferenceDTO deserializeServiceReferenceDTO(InputStream entityStream) throws IOException {
-        AtomicReference<ServiceReferenceDTO> service = new AtomicReference<>();
-        deserialize(service::set, entityStream);
-        return service.get();
-    }
-
-    public List<ServiceReferenceDTO> deserializeServiceReferenceDTOList(InputStream entityStream) throws IOException {
-        List<ServiceReferenceDTO> services = new ArrayList<>();
-        deserialize(services::add, entityStream);
-        return services;
-    }
-
-    private void deserialize(
-            Consumer<ServiceReferenceDTO> collector, InputStream entityStream)
-        throws IOException {
-
-        AtomicReference<ServiceReferenceDTO> service = new AtomicReference<>();
-        AtomicBoolean inUsingBundles = new AtomicBoolean();
-        deserializer.deserialize((start, next) -> {
-            String el = start.getName().getLocalPart();
-            XMLEvent event = start;
-            if (el.equals("service")) {
-                service.set(new ServiceReferenceDTO());
-            }
-            else if (el.equals("id")) {
-                try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                service.get().id = Long.parseLong(event.asCharacters().getData());
-            }
-            else if (el.equals("properties")) {
-                service.get().properties = new HashMap<>();
-            }
-            else if (el.equals("property")) {
-                Attribute keyAT = start.getAttributeByName(new QName("name"));
-                Attribute typeAT = start.getAttributeByName(new QName("type"));
-                Attribute valueAT = start.getAttributeByName(new QName("value"));
-                String valueTxt = null;
-                boolean array = false;
-                if (valueAT == null) {
-                    try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                    if (!event.isEndElement()) {
-                        valueTxt = event.asCharacters().getData();
-                        array = true;
-                    }
-                }
-                else {
-                    valueTxt = valueAT.getValue();
-                }
-
-                service.get().properties.put(keyAT.getValue(), Coerce.from(keyAT, typeAT, valueTxt, array));
-            }
-            else if (el.equals("bundle") && inUsingBundles.get()) {
-                try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                long[] newArray = new long[service.get().usingBundles.length + 1];
-                System.arraycopy(service.get().usingBundles, 0, newArray, 0, service.get().usingBundles.length);
-                newArray[newArray.length - 1] = bundleIdFromURI(event.asCharacters().getData());
-                service.get().usingBundles = newArray;
-            }
-            else if (el.equals("bundle")) {
-                try {event = next.nextEvent();} catch (Exception e) {throw new RuntimeException(e);}
-                service.get().bundle = bundleIdFromURI(event.asCharacters().getData());
-            }
-            else if (el.equals("usingBundles")) {
-                service.get().usingBundles = new long[0];
-                inUsingBundles.set(true);
-            }
-            return event;
-        }, end -> {
-            String el = end.getName().getLocalPart();
-            if (el.equals("service")) {
-                collector.accept(service.get());
-                service.set(null);
-            }
-            else if (el.equals("usingBundles")) {
-                inUsingBundles.set(false);
-            }
-        }, entityStream);
-    }
-
-    long bundleIdFromURI(String bundleURI) {
-        final URI uri = URI.create(bundleURI);
-        final String uriPath = uri.getPath();
-        final Path path = Paths.get(uriPath);
-        final String bundleId = path.getFileName().toString();
-        return Long.parseLong(bundleId);
-    }
-
-}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOXMLSerializer.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOXMLSerializer.java
deleted file mode 100644
index 939707b..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/ServiceReferenceDTOXMLSerializer.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.handler;
-
-import static java.util.Collections.singleton;
-import static java.util.stream.Collectors.joining;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.Collection;
-
-import javax.ws.rs.core.UriInfo;
-
-import org.osgi.framework.dto.ServiceReferenceDTO;
-import org.w3c.dom.Element;
-
-class ServiceReferenceDTOXMLSerializer {
-
-    private final XMLSerializer serializer;
-
-    public ServiceReferenceDTOXMLSerializer(XMLSerializer serializer) {
-        this.serializer = serializer;
-    }
-
-    public void serialize(
-        ServiceReferenceDTO service, UriInfo uriInfo, OutputStream entityStream) throws IOException {
-
-        serialize(singleton(service), null, uriInfo, entityStream);
-    }
-
-
-    public void serialize(
-        Collection<ServiceReferenceDTO> services, UriInfo uriInfo, OutputStream entityStream) throws IOException {
-
-        serialize(services, "services", uriInfo, entityStream);
-    }
-
-    public void serialize(
-        Collection<ServiceReferenceDTO> services, String rootElement, UriInfo uriInfo, OutputStream entityStream) throws IOException {
-
-        try {
-            serializer.serialize(
-                rootElement,
-                (dom, parentNode) -> services.stream().map(
-                    serviceReferenceDTO -> {
-                        Element serviceEl = dom.createElement("service");
-
-                        Element idEl = dom.createElement("id");
-                        idEl.setTextContent(String.valueOf(serviceReferenceDTO.id));
-                        Element propertiesEl = dom.createElement("properties");
-                        serviceReferenceDTO.properties.forEach((k, v) -> {
-                            Element propertyEl = dom.createElement("property");
-                            propertyEl.setAttribute("name", k);
-                            boolean array = false;
-                            if (Long.class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Long");
-                            }
-                            else if (Long[].class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Long");
-                                array = true;
-                            }
-                            else if (Double.class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Double");
-                            }
-                            else if (Double[].class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Double");
-                                array = true;
-                            }
-                            else if (Float.class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Float");
-                            }
-                            else if (Float[].class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Float");
-                                array = true;
-                            }
-                            else if (Integer.class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Integer");
-                            }
-                            else if (Integer[].class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Integer");
-                                array = true;
-                            }
-                            else if (Byte.class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Byte");
-                            }
-                            else if (Byte[].class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Byte");
-                                array = true;
-                            }
-                            else if (Character.class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Character");
-                            }
-                            else if (Character[].class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Character");
-                                array = true;
-                            }
-                            else if (Boolean.class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Boolean");
-                            }
-                            else if (Boolean[].class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Boolean");
-                                array = true;
-                            }
-                            else if (Short.class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Short");
-                            }
-                            else if (Short[].class.isInstance(v)) {
-                                propertyEl.setAttribute("type", "Short");
-                                array = true;
-                            }
-                            else if (String[].class.isInstance(v)) {
-                                array = true;
-                            }
-
-                            if (!array) {
-                                propertyEl.setAttribute("value", String.valueOf(v));
-                            }
-                            else {
-                                propertyEl.setTextContent(
-                                    Arrays.stream((Object[])v).map(
-                                        String::valueOf
-                                    ).collect(
-                                        joining("\n")
-                                    )
-                                );
-                            }
-
-                            propertiesEl.appendChild(propertyEl);
-                        });
-
-                        Element bundleEl = dom.createElement("bundle");
-                        bundleEl.setTextContent(
-                            uriInfo.getBaseUriBuilder().path("framework").path("bundle").path("{id}").build(serviceReferenceDTO.bundle).toASCIIString()
-                        );
-                        Element usingBundlesEl = dom.createElement("usingBundles");
-                        for (long usingBundle : serviceReferenceDTO.usingBundles) {
-                            Element bEl = dom.createElement("bundle");
-                            bEl.setTextContent(
-                                uriInfo.getBaseUriBuilder().path("framework").path("bundle").path("{id}").build(usingBundle).toASCIIString()
-                            );
-                            usingBundlesEl.appendChild(bEl);
-                        }
-
-                        serviceEl.appendChild(idEl);
-                        serviceEl.appendChild(propertiesEl);
-                        serviceEl.appendChild(bundleEl);
-                        serviceEl.appendChild(usingBundlesEl);
-
-                        return serviceEl;
-                    }
-                ).forEach(
-                    bundleEL -> parentNode.appendChild(bundleEL)
-                ),
-                entityStream
-            );
-        }
-        catch (Exception e) {
-            throw new IOException(e);
-        }
-    }
-
-}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/XMLDeserializer.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/XMLDeserializer.java
deleted file mode 100644
index e3f803d..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/XMLDeserializer.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.handler;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.EndElement;
-import javax.xml.stream.events.StartElement;
-import javax.xml.stream.events.XMLEvent;
-
-class XMLDeserializer {
-
-    private final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
-
-    public <T> void deserialize(
-            BiFunction<StartElement, XMLEventReader, XMLEvent> startConsumer,
-            Consumer<EndElement> endConsumer, InputStream entityStream)
-        throws IOException {
-
-        try {
-            XMLEventReader eventReader = inputFactory.createXMLEventReader(entityStream);
-
-            while (eventReader.hasNext()) {
-                XMLEvent event = eventReader.nextEvent();
-
-                if (event.isStartElement()) {
-                    event = startConsumer.apply(event.asStartElement(), eventReader);
-                }
-
-                if (event.isEndElement()) {
-                    endConsumer.accept(event.asEndElement());
-                }
-            }
-        } catch (XMLStreamException e) {
-            throw new IOException(e);
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/XMLSerializer.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/XMLSerializer.java
deleted file mode 100644
index 1739236..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/XMLSerializer.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.handler;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.function.BiConsumer;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-class XMLSerializer {
-
-    private final DocumentBuilder db;
-
-    public XMLSerializer() {
-        try {
-            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-            db = dbf.newDocumentBuilder();
-        }
-        catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public void serialize(
-            String rootElement, BiConsumer<Document, Node> consumer,
-            OutputStream entityStream)
-        throws Exception {
-
-        try {
-            Document dom = db.newDocument();
-            Node parentNode = dom;
-            if (rootElement != null) {
-                parentNode = dom.createElement(rootElement);
-                dom.appendChild(parentNode);
-            }
-
-            consumer.accept(dom, parentNode);
-
-            Transformer tr = TransformerFactory.newInstance().newTransformer();
-            tr.setOutputProperty(OutputKeys.STANDALONE, "yes");
-            tr.setOutputProperty(OutputKeys.INDENT, "yes");
-            tr.setOutputProperty(OutputKeys.METHOD, "xml");
-            tr.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
-            tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
-
-            tr.transform(
-                new DOMSource(dom),
-                new StreamResult(entityStream)
-            );
-        }
-        catch (Exception e) {
-            throw new IOException(e);
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/BaseResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/BaseResource.java
new file mode 100644
index 0000000..755958c
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/BaseResource.java
@@ -0,0 +1,153 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.mapping;
+import static java.util.stream.Collectors.toList;
+import static org.osgi.framework.Bundle.ACTIVE;
+import static org.osgi.framework.Bundle.STARTING;
+import static org.osgi.framework.Bundle.STOPPING;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleStateSchema;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.dto.ServiceReferenceDTO;
+import org.osgi.framework.startlevel.BundleStartLevel;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleWiring;
+
+public abstract class BaseResource {
+
+    final BundleContext bundleContext;
+    final Bundle framework;
+
+    @Context
+    volatile UriInfo uriInfo;
+    @Context
+    volatile HttpHeaders headers;
+
+    public BaseResource(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+        this.framework = bundleContext.getBundle(0);
+    }
+
+    BundleStateSchema bundleStateSchema(Bundle bundle) {
+        int state = bundle.getState();
+        BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class);
+        return BundleStateSchema.build(
+            state, (bundleStartLevel.isActivationPolicyUsed() ? Bundle.START_ACTIVATION_POLICY : 0) |
+                (((state & (STARTING|ACTIVE|STOPPING)) != 0) ?
+                    (bundleStartLevel.isPersistentlyStarted() ? 0 : Bundle.START_TRANSIENT) : 0));
+    }
+
+    BundleSchema bundleSchema(Bundle bundle) {
+        return BundleSchema.build(
+            bundle.getBundleId(),
+            bundle.getLastModified(),
+            bundle.getState(),
+            bundle.getSymbolicName(),
+            bundle.getVersion().toString(),
+            bundle.getLocation()
+        );
+    }
+
+    static Predicate<Bundle> fromNamespaceQuery(UriInfo info) {
+        MultivaluedMap<String,String> parameters = info.getQueryParameters(true);
+
+        if (parameters.isEmpty()) {
+            return b -> true;
+        }
+
+        Map<String, List<Filter>> filters = parameters.entrySet().stream().flatMap(
+            e -> e.getValue().stream().map(v -> new SimpleEntry<>(e.getKey(), v))
+        ).map(
+            e -> new SimpleEntry<>(e.getKey(), create(e.getValue()))
+        ).collect(
+            groupingBy(Entry::getKey, mapping(Entry::getValue, toList()))
+        );
+
+        if (filters.isEmpty()) {
+            return b -> true;
+        }
+
+        return b -> {
+            BundleWiring wiring = b.adapt(BundleWiring.class);
+            return filters.entrySet().stream().allMatch(
+                entry -> {
+                    String namespace = entry.getKey();
+                    List<BundleCapability> caps = wiring.getCapabilities(namespace);
+                    return entry.getValue().stream().anyMatch(
+                        f ->
+                            caps.stream().anyMatch(
+                                cap ->
+                                    f.matches(cap.getAttributes())
+                            )
+                    );
+                }
+            );
+        };
+    }
+
+    static Predicate<ServiceReferenceDTO> fromFilterQuery(String filter) {
+        return Optional.ofNullable(
+            filter
+        ).map(
+            BaseResource::create
+        ).map(
+            toPredicate()
+        ).orElseGet(
+            () -> sr -> true
+        );
+    }
+
+    static Filter create(String filter) {
+        try {
+            return FrameworkUtil.createFilter(filter);
+        } catch (InvalidSyntaxException e) {
+            throw new WebApplicationException(
+                String.format("Malformed filter [%s]", filter),
+                Response.Status.BAD_REQUEST);
+        }
+    }
+
+    static Function<Filter, Predicate<ServiceReferenceDTO>> toPredicate() {
+        return f -> sr ->
+            f.matches(sr.properties);
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleHeaderResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleHeaderResource.java
new file mode 100644
index 0000000..88cc130
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleHeaderResource.java
@@ -0,0 +1,113 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static javax.ws.rs.core.HttpHeaders.ACCEPT_LANGUAGE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEHEADER_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEHEADER_XML;
+
+import java.util.Locale;
+import java.util.Optional;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.internal.map.CaseInsensitiveMap;
+import org.apache.aries.jax.rs.rest.management.schema.BundleHeaderSchema;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkBundleHeaderResource extends BaseResource {
+
+    public FrameworkBundleHeaderResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.6.1
+    @GET
+    @Produces({APPLICATION_BUNDLEHEADER_JSON, APPLICATION_BUNDLEHEADER_XML})
+    @Path("framework/bundle/{bundleid}/header{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/bundle/header",
+        summary = "Retrieves a Bundle Header Representation from the REST management service",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request has been served successfully",
+                content = @Content(schema = @Schema(implementation = BundleHeaderSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "There is no bundle with the given bundle id"
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        },
+        parameters = {
+            @Parameter(
+                name = ACCEPT_LANGUAGE,
+                description = "The raw header value is used unless an Accept-Language header is set on the HTTP request. If multiple accepted languages are set only the first is used to localize the header",
+                in = ParameterIn.HEADER
+            )
+        }
+    )
+    public Response bundleHeaders(
+        @PathParam("bundleid") long bundleid,
+        @Parameter(allowEmptyValue = true, schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        String language = headers.getAcceptableLanguages().stream().findFirst().map(Locale::toString).orElse(null);
+
+        Bundle bundle = bundleContext.getBundle(bundleid);
+
+        if (bundle == null) {
+            throw new WebApplicationException(404);
+        }
+
+        ResponseBuilder builder = Response.ok(
+            new BundleHeaderSchema(new CaseInsensitiveMap<>(bundle.getHeaders(language)))
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_BUNDLEHEADER_JSON : APPLICATION_BUNDLEHEADER_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleResource.java
new file mode 100644
index 0000000..aa1f68b
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleResource.java
@@ -0,0 +1,326 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_JSON_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_XML;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_XML_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_JSON_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_XML;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_VNDOSGIBUNDLE;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Optional;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.schema.BundleExceptionSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchema;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkBundleResource extends BaseResource {
+
+    public FrameworkBundleResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.4.1
+    @GET
+    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
+    @Path("framework/bundle/{bundleid}{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/bundle",
+        summary = "Retrieves a Bundle Representation from the REST management service",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request has been served successfully",
+                content = @Content(schema = @Schema(implementation = BundleSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "There is no bundle with the given bundle id"
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response bundle(
+        @PathParam("bundleid") long bundleid,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        Bundle bundle = bundleContext.getBundle(bundleid);
+
+        if (bundle == null) {
+            throw new WebApplicationException("There is no bundle with the given bundle id", 404);
+        }
+
+        ResponseBuilder builder = Response.ok(
+            bundleSchema(bundle)
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_BUNDLE_JSON : APPLICATION_BUNDLE_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+    // 137.3.4.2
+    @PUT
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
+    @Path("framework/bundle/{bundleid}{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "PUT/bundle",
+        summary = "Updates the bundle with a new version",
+        requestBody = @RequestBody(
+            description = "One of the following contents is allowed; a location string with content-type type 'text/plain' OR a bundle jar with content-type 'application/vnd.osgi.bundle'",
+            required = true,
+            content = {
+                @Content(mediaType = TEXT_PLAIN, schema = @Schema(description = "a location string", type = "string")),
+                @Content(mediaType = APPLICATION_VNDOSGIBUNDLE, schema = @Schema(description = "a bundle jar", type = "string", format = "binary"))
+            }
+        ),
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request was received and valid and the framework has issued the update",
+                content = @Content(schema = @Schema(implementation = BundleSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "400",
+                description = "the REST management service received a BundleException when trying to update",
+                content = {
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_JSON, schema = @Schema(implementation = BundleExceptionSchema.class)),
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_XML, schema = @Schema(implementation = BundleExceptionSchema.class))
+                }
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response bundle(
+        String location,
+        @PathParam("bundleid") long bundleid,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext,
+        @HeaderParam(CONTENT_TYPE) MediaType contentType) {
+
+        try {
+            Bundle bundle = bundleContext.getBundle(bundleid);
+
+            if (bundle == null) {
+                throw new WebApplicationException(String.valueOf(bundleid), 404);
+            }
+
+            if (location != null && !location.isEmpty()) {
+                bundle.update(new URL(location).openStream());
+            }
+            else {
+                bundle.update();
+            }
+
+            ResponseBuilder builder = Response.ok(
+                bundleSchema(bundle)
+            );
+
+            return Optional.ofNullable(
+                ext
+            ).map(
+                String::trim
+            ).map(
+                e -> ".json".equals(e) ? APPLICATION_BUNDLE_JSON : APPLICATION_BUNDLE_XML
+            ).map(
+                type -> builder.type(type)
+            ).orElse(
+                builder
+            ).build();
+        }
+        catch (BundleException exception) {
+            return Response.status(400).type(
+                contentType.equals(APPLICATION_BUNDLE_JSON_TYPE) ?
+                    APPLICATION_BUNDLEEXCEPTION_JSON_TYPE :
+                    APPLICATION_BUNDLEEXCEPTION_XML_TYPE
+            ).entity(
+                BundleExceptionSchema.build(exception.getType(), exception.getMessage())
+            ).build();
+        }
+        catch (Exception e) {
+            throw new WebApplicationException(e, 400);
+        }
+    }
+
+    // 137.3.4.3
+    @PUT
+    @Consumes(APPLICATION_VNDOSGIBUNDLE)
+    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
+    @Path("framework/bundle/{bundleid}{ext:(\\.json|\\.xml)*}")
+    @Operation(hidden = true)
+    public Response putBundle(
+        InputStream inputStream,
+        @PathParam("bundleid") long bundleid,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext,
+        @HeaderParam(CONTENT_TYPE) MediaType contentType) {
+
+        try {
+            Bundle bundle = bundleContext.getBundle(bundleid);
+
+            if (bundle == null) {
+                throw new WebApplicationException(String.valueOf(bundleid), 404);
+            }
+
+            bundle.update(inputStream);
+
+            ResponseBuilder builder = Response.ok(
+                bundleSchema(bundle)
+            );
+
+            return Optional.ofNullable(
+                ext
+            ).map(
+                String::trim
+            ).map(
+                e -> ".json".equals(e) ? APPLICATION_BUNDLE_JSON : APPLICATION_BUNDLE_XML
+            ).map(
+                type -> builder.type(type)
+            ).orElse(
+                builder
+            ).build();
+        }
+        catch (BundleException exception) {
+            return Response.status(400).type(
+                contentType.equals(APPLICATION_BUNDLE_JSON_TYPE) ?
+                    APPLICATION_BUNDLEEXCEPTION_JSON_TYPE :
+                    APPLICATION_BUNDLEEXCEPTION_XML_TYPE
+            ).entity(
+                BundleExceptionSchema.build(exception.getType(), exception.getMessage())
+            ).build();
+        }
+    }
+
+    // 137.3.4.4
+    @DELETE
+    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
+    @Path("framework/bundle/{bundleid}{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "DELETE/bundle",
+        summary = "Uninstalls the bundle from the framework",
+        responses = {
+            @ApiResponse(
+                responseCode = "204",
+                description = "The request was received and valid and the framework has uninstalled the bundle",
+                content = @Content(schema = @Schema(implementation = BundleSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "400",
+                description = "The REST management service received a BundleException when trying to uninstall",
+                content = {
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_JSON, schema = @Schema(implementation = BundleExceptionSchema.class)),
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_XML, schema = @Schema(implementation = BundleExceptionSchema.class))
+                }
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "There is no bundle with the given bundle id"
+            )
+        }
+    )
+    public Response deleteBundle(
+        @PathParam("bundleid") long bundleid,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext,
+        @HeaderParam(CONTENT_TYPE) MediaType contentType) {
+
+        try {
+            Bundle bundle = bundleContext.getBundle(bundleid);
+
+            if (bundle == null) {
+                throw new WebApplicationException(String.valueOf(bundleid), 404);
+            }
+
+            bundle.uninstall();
+
+            ResponseBuilder builder = Response.ok(
+                bundleSchema(bundle)
+            );
+
+            return Optional.ofNullable(
+                ext
+            ).map(
+                String::trim
+            ).map(
+                e -> ".json".equals(e) ? APPLICATION_BUNDLE_JSON : APPLICATION_BUNDLE_XML
+            ).map(
+                type -> builder.type(type)
+            ).orElse(
+                builder
+            ).build();
+        }
+        catch (BundleException exception) {
+            return Response.status(400).type(
+                contentType.equals(APPLICATION_BUNDLE_JSON_TYPE) ?
+                    APPLICATION_BUNDLEEXCEPTION_JSON_TYPE :
+                    APPLICATION_BUNDLEEXCEPTION_XML_TYPE
+            ).entity(
+                BundleExceptionSchema.build(exception.getType(), exception.getMessage())
+            ).build();
+        }
+        catch (Exception exception) {
+            throw new WebApplicationException(exception, 400);
+        }
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleStartLevelResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleStartLevelResource.java
new file mode 100644
index 0000000..77a3f6c
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleStartLevelResource.java
@@ -0,0 +1,199 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_JSON_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_XML;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_XML_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTARTLEVEL_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTARTLEVEL_JSON_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTARTLEVEL_XML;
+
+import java.util.Optional;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.schema.BundleExceptionSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleStartLevelSchema;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.startlevel.BundleStartLevel;
+import org.osgi.framework.startlevel.dto.BundleStartLevelDTO;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkBundleStartLevelResource extends BaseResource {
+
+    public FrameworkBundleStartLevelResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.7.1
+    @GET
+    @Produces({APPLICATION_BUNDLESTARTLEVEL_JSON, APPLICATION_BUNDLESTARTLEVEL_XML})
+    @Path("framework/bundle/{bundleid}/startlevel{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/bundle/startlevel",
+        summary = "Retrieves a Bundle Startlevel Representation from the REST management service",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request has been served successfully",
+                content = @Content(schema = @Schema(implementation = BundleStartLevelSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "There is no bundle with the given bundle id"
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response bundleStartlevel(
+        @PathParam("bundleid") long bundleid,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        Bundle bundle = bundleContext.getBundle(bundleid);
+
+        if (bundle == null) {
+            throw new WebApplicationException(404);
+        }
+
+        ResponseBuilder builder = Response.ok(
+            BundleStartLevelSchema.build(bundle.adapt(BundleStartLevelDTO.class))
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_BUNDLESTARTLEVEL_JSON : APPLICATION_BUNDLESTARTLEVEL_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+    // 137.3.7.2
+    @PUT
+    @Consumes({APPLICATION_BUNDLESTARTLEVEL_JSON, APPLICATION_BUNDLESTARTLEVEL_XML})
+    @Produces({APPLICATION_BUNDLESTARTLEVEL_JSON, APPLICATION_BUNDLESTARTLEVEL_XML})
+    @Path("framework/bundle/{bundleid}/startlevel{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "PUT/bundle/startlevel",
+        summary = "Sets the target bundle startlevel",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request was received and valid. The REST management service has changed the bundle startlevel according to the target value",
+                content = @Content(schema = @Schema(implementation = BundleStartLevelSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "400",
+                description = "Either the target startlevel state involved invalid values, e.g., a startlevel smaller or equal to zero and the REST management service got an IllegalArgumentException, or the REST management service received a BundleException when trying to perform the startlevel change",
+                content = {
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_JSON, schema = @Schema(implementation = BundleExceptionSchema.class)),
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_XML, schema = @Schema(implementation = BundleExceptionSchema.class))
+                }
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "There is no bundle with the given bundle id"
+            ),
+            @ApiResponse(
+                responseCode = "415",
+                description = "The request had a media type that is not supported by the REST management service"
+            )
+        }
+    )
+    public Response bundleStartlevel(
+        BundleStartLevelSchema update,
+        @PathParam("bundleid") long bundleid,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext,
+        @HeaderParam(CONTENT_TYPE) MediaType contentType) {
+
+        Bundle bundle = bundleContext.getBundle(bundleid);
+
+        if (bundle == null) {
+            throw new WebApplicationException(404);
+        }
+
+        try {
+            BundleStartLevel current = bundle.adapt(BundleStartLevel.class);
+
+            if (current.getStartLevel() != update.startLevel) {
+                current.setStartLevel(update.startLevel);
+            }
+
+            ResponseBuilder builder = Response.ok(
+                BundleStartLevelSchema.build(bundle.adapt(BundleStartLevelDTO.class))
+            );
+
+            return Optional.ofNullable(
+                ext
+            ).map(
+                String::trim
+            ).map(
+                e -> ".json".equals(e) ? APPLICATION_BUNDLESTARTLEVEL_JSON : APPLICATION_BUNDLESTARTLEVEL_XML
+            ).map(
+                type -> builder.type(type)
+            ).orElse(
+                builder
+            ).build();
+        }
+        catch (Exception exception) {
+            if (exception instanceof BundleException) {
+                return Response.status(400).type(
+                    contentType.equals(APPLICATION_BUNDLESTARTLEVEL_JSON_TYPE) ?
+                        APPLICATION_BUNDLEEXCEPTION_JSON_TYPE :
+                        APPLICATION_BUNDLEEXCEPTION_XML_TYPE
+                ).entity(
+                    BundleExceptionSchema.build(
+                        ((BundleException)exception).getType(), exception.getMessage())
+                ).build();
+            }
+            else {
+                throw new WebApplicationException(exception, 400);
+            }
+        }
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleStateResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleStateResource.java
new file mode 100644
index 0000000..a555ca2
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundleStateResource.java
@@ -0,0 +1,226 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_JSON_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_XML;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_XML_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTATE_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTATE_JSON_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTATE_XML;
+import static org.osgi.framework.Bundle.ACTIVE;
+import static org.osgi.framework.Bundle.INSTALLED;
+import static org.osgi.framework.Bundle.RESOLVED;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.schema.BundleExceptionSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleStateSchema;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.wiring.FrameworkWiring;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkBundleStateResource extends BaseResource {
+
+    public FrameworkBundleStateResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.5.1
+    @GET
+    @Produces({APPLICATION_BUNDLESTATE_JSON, APPLICATION_BUNDLESTATE_XML})
+    @Path("framework/bundle/{bundleid}/state{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/bundle/state",
+        summary = "Retrieves a Bundle State Representation from the REST management service",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request has been served successfully",
+                content = @Content(schema = @Schema(implementation = BundleStateSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "There is no bundle with the given bundle id"
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response bundleState(
+        @PathParam("bundleid") long bundleid,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        Bundle bundle = bundleContext.getBundle(bundleid);
+
+        if (bundle == null) {
+            throw new WebApplicationException(404);
+        }
+
+        ResponseBuilder builder = Response.ok(
+            bundleStateSchema(bundle)
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_BUNDLESTATE_JSON : APPLICATION_BUNDLESTATE_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+    // 137.3.5.2
+    @PUT
+    @Consumes({APPLICATION_BUNDLESTATE_JSON, APPLICATION_BUNDLESTATE_XML})
+    @Produces({APPLICATION_BUNDLESTATE_JSON, APPLICATION_BUNDLESTATE_XML})
+    @Path("framework/bundle/{bundleid}/state{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "PUT/bundle/state",
+        summary = "Sets the target state for the given bundle. This can, e.g., be state=32 for transitioning the bundle to started, or state=4 for stopping the bundle and transitioning it to resolved",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request was received and valid and the framework has performed a state change",
+                content = @Content(schema = @Schema(implementation = BundleStateSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "400",
+                description = "The REST management service received a BundleException when trying to perform the state transition",
+                content = {
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_JSON, schema = @Schema(implementation = BundleExceptionSchema.class)),
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_XML, schema = @Schema(implementation = BundleExceptionSchema.class))
+                }
+            ),
+            @ApiResponse(
+                responseCode = "402",
+                description = "The requested target state is not reachable from the current bundle state or is not a target state"
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "There is no bundle with the given bundle id"
+            ),
+            @ApiResponse(
+                responseCode = "415",
+                description = "The request had a media type that is not supported by the REST management service"
+            )
+        }
+    )
+    public Response bundleState(
+        BundleStateSchema bundleStateDTO,
+        @PathParam("bundleid") long bundleid,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext,
+        @HeaderParam(CONTENT_TYPE) MediaType contentType) {
+
+        try {
+            Bundle bundle = bundleContext.getBundle(bundleid);
+
+            if (bundle == null) {
+                throw new WebApplicationException("there is no bundle with the given bundle id", 404);
+            }
+
+            int currentState = bundle.getState();
+
+            if ((currentState & INSTALLED) == INSTALLED ||
+                (currentState & RESOLVED) == RESOLVED) {
+                if ((bundleStateDTO.state & ACTIVE) == ACTIVE) {
+                    bundle.start(bundleStateDTO.options);
+                }
+                else if ((bundleStateDTO.state & RESOLVED) == RESOLVED) {
+                    framework.adapt(
+                        FrameworkWiring.class
+                    ).resolveBundles(
+                        Collections.singleton(bundle)
+                    );
+                }
+            }
+            else if ((currentState & ACTIVE) == ACTIVE) {
+                if ((bundleStateDTO.state & RESOLVED) == RESOLVED) {
+                    bundle.stop(bundleStateDTO.options);
+                }
+            }
+            else {
+                throw new WebApplicationException(
+                    String.format(
+                        "the requested target state [%s] is not reachable " +
+                        "from the current bundle state [%s] or is not a " +
+                        "target state",
+                        bundleStateDTO.state, currentState), 402);
+            }
+
+            ResponseBuilder builder = Response.ok(
+                bundleStateSchema(bundle)
+            );
+
+            return Optional.ofNullable(
+                ext
+            ).map(
+                String::trim
+            ).map(
+                e -> ".json".equals(e) ? APPLICATION_BUNDLESTATE_JSON : APPLICATION_BUNDLESTATE_XML
+            ).map(
+                type -> builder.type(type)
+            ).orElse(
+                builder
+            ).build();
+        }
+        catch (BundleException exception) {
+            return Response.status(400).type(
+                contentType.equals(APPLICATION_BUNDLESTATE_JSON_TYPE) ?
+                    APPLICATION_BUNDLEEXCEPTION_JSON_TYPE :
+                    APPLICATION_BUNDLEEXCEPTION_XML_TYPE
+            ).entity(
+                BundleExceptionSchema.build(exception.getType(), exception.getMessage())
+            ).build();
+        }
+        catch (Exception exception) {
+            throw new WebApplicationException(exception, 400);
+        }
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundlesRepresentationsResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundlesRepresentationsResource.java
new file mode 100644
index 0000000..6a44a54
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundlesRepresentationsResource.java
@@ -0,0 +1,114 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static java.util.stream.Collectors.toList;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLES_REPRESENTATIONS_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLES_REPRESENTATIONS_XML;
+
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchemaListSchema;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkBundlesRepresentationsResource extends BaseResource {
+
+    public FrameworkBundlesRepresentationsResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.3.1
+    @GET
+    @Produces({APPLICATION_BUNDLES_REPRESENTATIONS_JSON, APPLICATION_BUNDLES_REPRESENTATIONS_XML})
+    @Path("framework/bundles/representations{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/bundles/representations",
+        summary = "Retrieve the bundle representation of each installed bundle",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request has been served successfully",
+                content = @Content(schema = @Schema(implementation = BundleSchemaListSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        },
+        parameters = {
+            @Parameter(
+                name = "<capability_namespace>",
+                in = ParameterIn.QUERY,
+                description = "A query parameter whose name is an osgi capability namespace and whose value is a filter expression that follows the Core Specifications Framework Filter Syntax; see OSGi Core, Chapter 3.2.7 Filter Syntax. Filters are matched against the attributes of capabilities in the respective namespaces. If multiple capabilities for a given namespace are present, then a filter succeeds when one of these capabilities matches. When multiple filter expressions across nam [...]
+                examples = @ExampleObject(
+                    summary = "format: <capability_namespace>=<filter_string>",
+                    value = "osgi.identity=(osgi.identity=foo)&osgi.package.wiring=(osgi.package.wiring=com.foo)"
+                )
+            )
+        }
+    )
+    public Response bundlesRepresentations(
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        Predicate<Bundle> predicate = fromNamespaceQuery(uriInfo);
+
+        ResponseBuilder builder = Response.ok(
+            BundleSchemaListSchema.build(
+                Stream.of(
+                    bundleContext.getBundles()
+                ).filter(
+                    predicate
+                ).map(
+                    this::bundleSchema
+                ).collect(toList())
+            )
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_BUNDLES_REPRESENTATIONS_JSON : APPLICATION_BUNDLES_REPRESENTATIONS_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundlesResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundlesResource.java
new file mode 100644
index 0000000..e5e53c4
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkBundlesResource.java
@@ -0,0 +1,281 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static java.util.stream.Collectors.toList;
+import static javax.ws.rs.core.HttpHeaders.CONTENT_LOCATION;
+import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_JSON_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_XML;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLEEXCEPTION_XML_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTATE_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTATE_XML;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLES_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLES_XML;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_JSON_TYPE;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_XML;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_VNDOSGIBUNDLE;
+
+import java.io.InputStream;
+import java.time.Instant;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.schema.BundleExceptionSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleListSchema;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkBundlesResource extends BaseResource {
+
+    public FrameworkBundlesResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.2.1
+    @GET
+    @Produces({APPLICATION_BUNDLES_JSON, APPLICATION_BUNDLES_XML})
+    @Path("framework/bundles{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/bundles",
+        summary = "Retrieves a Bundle List Representation from the REST management service",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request has been served successfully",
+                content = @Content(schema = @Schema(implementation = BundleListSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        },
+        parameters = {
+            @Parameter(
+                name = "<capability_namespace>",
+                in = ParameterIn.QUERY,
+                description = "A query parameter whose name is an osgi capability namespace and whose value is a filter expression that follows the Core Specifications Framework Filter Syntax; see OSGi Core, Chapter 3.2.7 Filter Syntax. Filters are matched against the attributes of capabilities in the respective namespaces. If multiple capabilities for a given namespace are present, then a filter succeeds when one of these capabilities matches. When multiple filter expressions across nam [...]
+                examples = @ExampleObject(
+                    summary = "format: <capability_namespace>=<filter_string>",
+                    value = "osgi.identity=(osgi.identity=foo)&osgi.package.wiring=(osgi.package.wiring=com.foo)"
+                )
+            )
+        }
+    )
+    public Response bundles(
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        Predicate<Bundle> predicate = fromNamespaceQuery(uriInfo);
+
+        ResponseBuilder builder = Response.status(
+            Response.Status.OK
+        ).entity(
+            BundleListSchema.build(
+                Stream.of(
+                    bundleContext.getBundles()
+                ).filter(
+                    predicate
+                ).map(
+                    Bundle::getBundleId
+                ).map(
+                    String::valueOf
+                ).map(
+                    id -> uriInfo.getBaseUriBuilder().path("framework").path("bundle").path("{id}").build(id).toASCIIString()
+                ).collect(toList())
+            )
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_BUNDLESTATE_JSON : APPLICATION_BUNDLESTATE_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+    // 137.3.2.2
+    @POST
+    @Consumes(TEXT_PLAIN)
+    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
+    @Path("framework/bundles{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "POST/bundles",
+        summary = "Installs a new bundle to the managed framework and thereby logically appends it to the bundles resource",
+        requestBody = @RequestBody(
+            description = "One of the following contents is allowed; a location string with content-type type 'text/plain' OR a bundle jar with content-type 'application/vnd.osgi.bundle'",
+            required = true,
+            content = {
+                @Content(mediaType = TEXT_PLAIN, schema = @Schema(description = "a location string", type = "string")),
+                @Content(mediaType = APPLICATION_VNDOSGIBUNDLE, schema = @Schema(description = "a bundle jar", type = "string", format = "binary"))
+            }
+        ),
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                content = @Content(schema = @Schema(implementation = BundleSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "400",
+                description = "the REST management service received a BundleException when trying to install",
+                content = {
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_JSON, schema = @Schema(implementation = BundleExceptionSchema.class)),
+                    @Content(mediaType = APPLICATION_BUNDLEEXCEPTION_XML, schema = @Schema(implementation = BundleExceptionSchema.class))
+                }
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        },
+        parameters = {
+            @Parameter(
+                name = CONTENT_LOCATION,
+                in = ParameterIn.HEADER,
+                description = "When posting a bundle jar a location string can be specified using the 'Content-Location' header",
+                required = false
+            )
+        }
+    )
+    public Response bundles(
+        String location,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext,
+        @HeaderParam(CONTENT_TYPE) MediaType contentType) {
+
+        try {
+            Instant now = Instant.now().minusMillis(2);
+            Bundle bundle = bundleContext.installBundle(location);
+
+            if (!now.isBefore(Instant.ofEpochMilli(bundle.getLastModified()))) {
+                throw new WebApplicationException(location, 409);
+            }
+
+            ResponseBuilder builder = Response.ok(
+                bundleSchema(bundle)
+            );
+
+            return Optional.ofNullable(
+                ext
+            ).map(
+                String::trim
+            ).map(
+                e -> ".json".equals(e) ? APPLICATION_BUNDLE_JSON : APPLICATION_BUNDLE_XML
+            ).map(
+                type -> builder.type(type)
+            ).orElse(
+                builder
+            ).build();
+        }
+        catch (BundleException exception) {
+            return Response.status(400).type(
+                contentType.equals(APPLICATION_BUNDLE_JSON_TYPE) ?
+                    APPLICATION_BUNDLEEXCEPTION_JSON_TYPE :
+                    APPLICATION_BUNDLEEXCEPTION_XML_TYPE
+            ).entity(
+                BundleExceptionSchema.build(exception.getType(), exception.getMessage())
+            ).build();
+        }
+    }
+
+    // 137.3.2.3
+    @POST
+    @Consumes(APPLICATION_VNDOSGIBUNDLE)
+    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
+    @Path("framework/bundles{ext:(\\.json|\\.xml)*}")
+    @Operation(hidden = true)
+    public Response bundles(
+        InputStream inputStream,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext,
+        @HeaderParam(CONTENT_LOCATION) String location,
+        @HeaderParam(CONTENT_TYPE) MediaType contentType) {
+
+        try {
+            location = Optional.ofNullable(location).orElseGet(
+                () -> "org.apache.aries.jax.rs.whiteboard:".concat(
+                    UUID.randomUUID().toString()));
+
+            Instant now = Instant.now().minusMillis(2);
+            Bundle bundle = bundleContext.installBundle(location, inputStream);
+
+            if (!now.isBefore(Instant.ofEpochMilli(bundle.getLastModified()))) {
+                throw new WebApplicationException(location, 409);
+            }
+
+            ResponseBuilder builder = Response.ok(
+                bundleSchema(bundle)
+            );
+
+            return Optional.ofNullable(
+                ext
+            ).map(
+                String::trim
+            ).map(
+                e -> ".json".equals(e) ? APPLICATION_BUNDLE_JSON : APPLICATION_BUNDLE_XML
+            ).map(
+                type -> builder.type(type)
+            ).orElse(
+                builder
+            ).build();
+        }
+        catch (BundleException exception) {
+            return Response.status(400).type(
+                contentType.equals(APPLICATION_BUNDLE_JSON_TYPE) ?
+                    APPLICATION_BUNDLEEXCEPTION_JSON_TYPE :
+                    APPLICATION_BUNDLEEXCEPTION_XML_TYPE
+            ).entity(
+                BundleExceptionSchema.build(exception.getType(), exception.getMessage())
+            ).build();
+        }
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkResource.java
index faa8fb4..fc8396a 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkResource.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkResource.java
@@ -17,678 +17,72 @@
 
 package org.apache.aries.jax.rs.rest.management.internal;
 
-import static java.util.stream.Collectors.groupingBy;
-import static java.util.stream.Collectors.mapping;
-import static java.util.stream.Collectors.toList;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.APPLICATION_XML;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.*;
-import static org.osgi.framework.Bundle.ACTIVE;
-import static org.osgi.framework.Bundle.INSTALLED;
-import static org.osgi.framework.Bundle.RESOLVED;
-import static org.osgi.framework.Bundle.STARTING;
-import static org.osgi.framework.Bundle.STOPPING;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLE_XML;
 
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URL;
-import java.time.Instant;
-import java.util.AbstractMap;
-import java.util.AbstractMap.SimpleEntry;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Optional;
-import java.util.Set;
-import java.util.UUID;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
-import javax.ws.rs.HeaderParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
 
-import org.apache.aries.jax.rs.rest.management.model.BundleStateDTO;
-import org.apache.aries.jax.rs.rest.management.model.BundlesDTO;
-import org.apache.aries.jax.rs.rest.management.model.ServiceReferenceDTOs;
-import org.apache.aries.jax.rs.rest.management.model.ServicesDTO;
-import org.osgi.framework.Bundle;
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchema;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.dto.BundleDTO;
-import org.osgi.framework.dto.FrameworkDTO;
-import org.osgi.framework.dto.ServiceReferenceDTO;
-import org.osgi.framework.startlevel.BundleStartLevel;
-import org.osgi.framework.startlevel.FrameworkStartLevel;
-import org.osgi.framework.startlevel.dto.BundleStartLevelDTO;
-import org.osgi.framework.startlevel.dto.FrameworkStartLevelDTO;
-import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.framework.wiring.FrameworkWiring;
 
-public class FrameworkResource {
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
 
-    private final BundleContext bundleContext;
-    private final Bundle framework;
-
-    @Context
-    volatile UriInfo uriInfo;
-    @Context
-    volatile HttpHeaders headers;
+public class FrameworkResource extends BaseResource {
 
     public FrameworkResource(BundleContext bundleContext) {
-        this.bundleContext = bundleContext;
-        this.framework = bundleContext.getBundle(0);
-    }
-
-    @GET
-    @Path("framework{type: (\\.json|\\.xml)*}")
-    @Produces({APPLICATION_JSON, APPLICATION_XML})
-    public Response framework(@PathParam("type") String type) {
-        ResponseBuilder builder = Response.status(
-            Response.Status.OK
-        ).entity(
-            framework.adapt(FrameworkDTO.class)
-        );
-
-        return Optional.ofNullable(
-            type
-        ).map(
-            String::trim
-        ).map(
-            t -> ".json".equals(t) ? APPLICATION_JSON : APPLICATION_XML
-        ).map(t -> builder.type(t)).orElse(
-            builder
-        ).build();
-    }
-
-    @GET
-    @Produces({APPLICATION_BUNDLESTATE_JSON, APPLICATION_BUNDLESTATE_XML})
-    @Path("framework/state{type:(\\.json|\\.xml)*}")
-    public Response state(@PathParam("type") String type) {
-        ResponseBuilder builder = Response.status(
-            Response.Status.OK
-        ).entity(
-            state(framework)
-        );
-
-        return Optional.ofNullable(
-            type
-        ).map(
-            String::trim
-        ).map(
-            t -> ".json".equals(t) ? APPLICATION_BUNDLESTATE_JSON : APPLICATION_BUNDLESTATE_XML
-        ).map(t -> builder.type(t)).orElse(
-            builder
-        ).build();
+        super(bundleContext);
     }
 
-    // 137.3.1.1
     @GET
-    @Produces({APPLICATION_FRAMEWORKSTARTLEVEL_JSON, APPLICATION_FRAMEWORKSTARTLEVEL_XML})
-    @Path("framework/startlevel{type:(\\.json|\\.xml)*}")
-    public Response startlevel(@PathParam("type") String type) {
+    @Path("framework{ext: (\\.json|\\.xml)*}")
+    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
+    @Operation(
+        summary = "Get the framework bundle by extension type",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The framework bundle",
+                content = @Content(schema = @Schema(implementation = BundleSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "Framework not found"
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response framework(
+        @Parameter(allowEmptyValue = true, schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
         ResponseBuilder builder = Response.status(
             Response.Status.OK
         ).entity(
-            framework.adapt(FrameworkStartLevelDTO.class)
+            bundleSchema(framework)
         );
 
         return Optional.ofNullable(
-            type
+            ext
         ).map(
             String::trim
         ).map(
-            t -> ".json".equals(t) ? APPLICATION_FRAMEWORKSTARTLEVEL_JSON : APPLICATION_FRAMEWORKSTARTLEVEL_XML
+            t -> ".json".equals(t) ? APPLICATION_BUNDLE_JSON : APPLICATION_BUNDLE_XML
         ).map(t -> builder.type(t)).orElse(
             builder
         ).build();
     }
 
-    // 137.3.1.2
-    @PUT
-    @Consumes({APPLICATION_FRAMEWORKSTARTLEVEL_JSON, APPLICATION_FRAMEWORKSTARTLEVEL_XML})
-    @Path("framework/startlevel")
-    public Response startlevel(FrameworkStartLevelDTO update) {
-        try {
-            FrameworkStartLevel current = framework.adapt(FrameworkStartLevel.class);
-
-            if (current.getStartLevel() != update.startLevel) {
-                current.setStartLevel(update.startLevel);
-            }
-            if (current.getInitialBundleStartLevel() != update.initialBundleStartLevel) {
-                current.setInitialBundleStartLevel(update.initialBundleStartLevel);
-            }
-
-            return Response.noContent().build();
-        }
-        catch (IllegalArgumentException exception) {
-            throw new WebApplicationException(exception, 400);
-        }
-    }
-
-    // 137.3.2.1
-    @GET
-    @Produces({APPLICATION_BUNDLES_JSON, APPLICATION_BUNDLES_XML})
-    @Path("framework/bundles")
-    public BundlesDTO bundles(@Context UriInfo info) {
-        Predicate<Bundle> predicate = fromNamespaceQuery(info);
-
-        return BundlesDTO.build(
-            Stream.of(
-                bundleContext.getBundles()
-            ).filter(
-                predicate
-            ).map(
-                Bundle::getBundleId
-            ).map(
-                String::valueOf
-            ).map(
-                id -> uriInfo.getBaseUriBuilder().path("framework").path("bundle").path("{id}").build(id).toASCIIString()
-            ).collect(toList())
-        );
-    }
-
-    // 137.3.2.2
-    @POST
-    @Consumes(MediaType.TEXT_PLAIN)
-    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
-    @Path("framework/bundles")
-    public Response postBundles(String location) {
-        try {
-            Instant now = Instant.now().minusMillis(2);
-            Bundle bundle = bundleContext.installBundle(location);
-
-            if (!now.isBefore(Instant.ofEpochMilli(bundle.getLastModified()))) {
-                throw new WebApplicationException(location, 409);
-            }
-
-            return Response.ok(
-                bundle.adapt(BundleDTO.class)
-            ).build();
-        }
-        catch (BundleException exception) {
-            throw new WebApplicationException(exception, 400);
-        }
-    }
-
-    // 137.3.2.3
-    @POST
-    @Consumes(APPLICATION_VNDOSGIBUNDLE)
-    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
-    @Path("framework/bundles")
-    public Response postBundles(
-        InputStream inputStream,
-        @HeaderParam(HttpHeaders.CONTENT_LOCATION) String location) {
-
-        try {
-            location = Optional.ofNullable(location).orElseGet(
-                () -> "org.apache.aries.jax.rs.whiteboard:".concat(
-                    UUID.randomUUID().toString()));
-
-            Instant now = Instant.now().minusMillis(2);
-            Bundle bundle = bundleContext.installBundle(location, inputStream);
-
-            if (!now.isBefore(Instant.ofEpochMilli(bundle.getLastModified()))) {
-                throw new WebApplicationException(location, 409);
-            }
-
-            return Response.ok(
-                bundle.adapt(BundleDTO.class)
-            ).build();
-        }
-        catch (BundleException exception) {
-            throw new WebApplicationException(exception, 400);
-        }
-    }
-
-    // 137.3.3.1
-    @GET
-    @Produces({APPLICATION_BUNDLES_REPRESENTATIONS_JSON, APPLICATION_BUNDLES_REPRESENTATIONS_XML})
-    @Path("framework/bundles/representations")
-    public Collection<BundleDTO> bundleDTOs(@Context UriInfo info) {
-        Predicate<Bundle> predicate = fromNamespaceQuery(info);
-
-        return Stream.of(
-            bundleContext.getBundles()
-        ).filter(
-            predicate
-        ).map(
-            b -> b.adapt(BundleDTO.class)
-        ).collect(Collectors.toList());
-    }
-
-    // 137.3.4.1
-    @GET
-    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
-    @Path("framework/bundle/{bundleid}")
-    public BundleDTO bundle(@PathParam("bundleid") long bundleid) {
-        Bundle bundle = bundleContext.getBundle(bundleid);
-
-        if (bundle == null) {
-            throw new WebApplicationException(404);
-        }
-
-        return bundle.adapt(BundleDTO.class);
-    }
-
-    // 137.3.4.2
-    @PUT
-    @Consumes(MediaType.TEXT_PLAIN)
-    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
-    @Path("framework/bundle/{bundleid}")
-    public Response postBundle(
-        @PathParam("bundleid") long bundleid, String location) {
-
-        try {
-            Bundle bundle = bundleContext.getBundle(bundleid);
-
-            if (bundle == null) {
-                throw new WebApplicationException(String.valueOf(bundleid), 404);
-            }
-
-            if (location != null && !location.isEmpty()) {
-                bundle.update(new URL(location).openStream());
-            }
-            else {
-                bundle.update();
-            }
-
-            return Response.ok(
-                bundle.adapt(BundleDTO.class)
-            ).build();
-        }
-        catch (Exception exception) {
-            throw new WebApplicationException(exception, 400);
-        }
-    }
-
-    // 137.3.4.3
-    @PUT
-    @Consumes(APPLICATION_VNDOSGIBUNDLE)
-    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
-    @Path("framework/bundle/{bundleid}")
-    public Response postBundle(
-        @PathParam("bundleid") long bundleid, InputStream inputStream) {
-
-        try {
-            Bundle bundle = bundleContext.getBundle(bundleid);
-
-            if (bundle == null) {
-                throw new WebApplicationException(String.valueOf(bundleid), 404);
-            }
-
-            bundle.update(inputStream);
-
-            return Response.ok(
-                bundle.adapt(BundleDTO.class)
-            ).build();
-        }
-        catch (Exception exception) {
-            throw new WebApplicationException(exception, 400);
-        }
-    }
-
-    // 137.3.4.4
-    @DELETE
-    @Produces({APPLICATION_BUNDLE_JSON, APPLICATION_BUNDLE_XML})
-    @Path("framework/bundle/{bundleid}")
-    public Response deleteBundle(@PathParam("bundleid") long bundleid) {
-
-        try {
-            Bundle bundle = bundleContext.getBundle(bundleid);
-
-            if (bundle == null) {
-                throw new WebApplicationException(String.valueOf(bundleid), 404);
-            }
-
-            bundle.uninstall();
-
-            return Response.ok(
-                bundle.adapt(BundleDTO.class)
-            ).build();
-        }
-        catch (Exception exception) {
-            throw new WebApplicationException(exception, 400);
-        }
-    }
-
-    // 137.3.5.1
-    @GET
-    @Produces({APPLICATION_BUNDLESTATE_JSON, APPLICATION_BUNDLESTATE_XML})
-    @Path("framework/bundle/{bundleid}/state")
-    public BundleStateDTO bundleState(@PathParam("bundleid") long bundleid) {
-        Bundle bundle = bundleContext.getBundle(bundleid);
-
-        if (bundle == null) {
-            throw new WebApplicationException(404);
-        }
-
-        return state(bundle);
-    }
-
-    // 137.3.5.2
-    @PUT
-    @Consumes({APPLICATION_BUNDLESTATE_JSON, APPLICATION_BUNDLESTATE_XML})
-    @Produces({APPLICATION_BUNDLESTATE_JSON, APPLICATION_BUNDLESTATE_XML})
-    @Path("framework/bundle/{bundleid}/state")
-    public BundleStateDTO bundleState(
-        @PathParam("bundleid") long bundleid,
-        BundleStateDTO bundleStateDTO) {
-
-        Bundle bundle = bundleContext.getBundle(bundleid);
-
-        if (bundle == null) {
-            throw new WebApplicationException(404);
-        }
-
-        int currentState = bundle.getState();
-
-        try {
-            if ((currentState & INSTALLED) == INSTALLED ||
-                (currentState & RESOLVED) == RESOLVED) {
-                if ((bundleStateDTO.state & ACTIVE) == ACTIVE) {
-                    bundle.start(bundleStateDTO.options);
-                }
-                else if ((bundleStateDTO.state & RESOLVED) == RESOLVED) {
-                    framework.adapt(
-                        FrameworkWiring.class
-                    ).resolveBundles(
-                        Collections.singleton(bundle)
-                    );
-                }
-            }
-            else if ((currentState & ACTIVE) == ACTIVE) {
-                if ((bundleStateDTO.state & RESOLVED) == RESOLVED) {
-                    bundle.stop(bundleStateDTO.options);
-                }
-            }
-            else {
-                throw new WebApplicationException(
-                    String.format(
-                        "the requested target state [%s] is not reachable " +
-                        "from the current bundle state [%s] or is not a " +
-                        "target state",
-                        bundleStateDTO.state, currentState), 402);
-            }
-        }
-        catch (BundleException exception) {
-            throw new WebApplicationException(exception, 400);
-        }
-
-        return state(bundle);
-    }
-
-    // 137.3.6.1
-    @GET
-    @Produces({APPLICATION_BUNDLEHEADER_JSON, APPLICATION_BUNDLEHEADER_XML})
-    @Path("framework/bundle/{bundleid}/header")
-    public Dictionary<String, String> bundleHeaders(
-        @PathParam("bundleid") long bundleid) {
-
-        Bundle bundle = bundleContext.getBundle(bundleid);
-
-        if (bundle == null) {
-            throw new WebApplicationException(404);
-        }
-
-        return bundle.getHeaders();
-    }
-
-    // 137.3.7.1
-    @GET
-    @Produces({APPLICATION_BUNDLESTARTLEVEL_JSON, APPLICATION_BUNDLESTARTLEVEL_XML})
-    @Path("framework/bundle/{bundleid}/startlevel")
-    public BundleStartLevelDTO bundleStartlevel(
-        @PathParam("bundleid") long bundleid) {
-
-        Bundle bundle = bundleContext.getBundle(bundleid);
-
-        if (bundle == null) {
-            throw new WebApplicationException(404);
-        }
-
-        return bundle.adapt(BundleStartLevelDTO.class);
-    }
-
-    // 137.3.7.2
-    @PUT
-    @Consumes({APPLICATION_BUNDLESTARTLEVEL_JSON, APPLICATION_BUNDLESTARTLEVEL_XML})
-    @Produces({APPLICATION_BUNDLESTARTLEVEL_JSON, APPLICATION_BUNDLESTARTLEVEL_XML})
-    @Path("framework/bundle/{bundleid}/startlevel")
-    public Response bundleStartlevel(
-        @PathParam("bundleid") long bundleid, BundleStartLevelDTO update) {
-
-        Bundle bundle = bundleContext.getBundle(bundleid);
-
-        if (bundle == null) {
-            throw new WebApplicationException(404);
-        }
-
-        try {
-            BundleStartLevel current = bundle.adapt(BundleStartLevel.class);
-
-            if (current.getStartLevel() != update.startLevel) {
-                current.setStartLevel(update.startLevel);
-            }
-
-            return Response.ok(bundle.adapt(BundleStartLevelDTO.class)).build();
-        }
-        catch (IllegalArgumentException exception) {
-            throw new WebApplicationException(exception, 400);
-        }
-    }
-
-    // 137.3.8.1
-    @GET
-    @Produces({APPLICATION_SERVICES_JSON, APPLICATION_SERVICES_XML})
-    @Path("framework/services")
-    public ServicesDTO services(@QueryParam("filter") String filter) {
-        Predicate<ServiceReferenceDTO> predicate = fromFilterQuery(filter);
-
-        return ServicesDTO.build(
-            framework.adapt(FrameworkDTO.class).services.stream().filter(
-                predicate
-            ).map(
-                sr -> String.valueOf(sr.id)
-            ).map(
-                id -> uriInfo.getBaseUriBuilder().path("framework").path("service").path(id)
-            ).map(
-                UriBuilder::build
-            ).map(
-                URI::toASCIIString
-            )
-            .collect(toList())
-        );
-    }
-
-    // 137.3.9.1
-    @GET
-    @Produces({APPLICATION_SERVICES_REPRESENTATIONS_JSON, APPLICATION_SERVICES_REPRESENTATIONS_XML})
-    @Path("framework/services/representations")
-    public ServiceReferenceDTOs serviceDTOs(@QueryParam("filter") String filter) {
-        Predicate<ServiceReferenceDTO> predicate = fromFilterQuery(filter);
-
-        return ServiceReferenceDTOs.build(
-            framework.adapt(
-                FrameworkDTO.class
-            ).services.stream().filter(
-                predicate
-            ).collect(toList())
-        );
-    }
-
-    // 137.3.9.1
-    @GET
-    @Produces({APPLICATION_SERVICE_JSON, APPLICATION_SERVICE_XML})
-    @Path("framework/service/{serviceid}")
-    public ServiceReferenceDTO service(
-        @PathParam("serviceid") long serviceid) {
-
-        return Stream.of(
-            bundleContext.getBundles()
-        ).flatMap(
-            bundle -> Optional.ofNullable(
-                bundle.adapt(ServiceReferenceDTO[].class)
-            ).map(
-                Stream::of
-            ).orElseGet(
-                Stream::empty
-            )
-        ).filter(
-            sr -> sr.id == serviceid
-        ).findFirst().orElseThrow(
-            () -> new WebApplicationException(404)
-        );
-    }
-
-    private BundleStateDTO state(Bundle bundle) {
-        final BundleStateDTO bundleState = new BundleStateDTO();
-        bundleState.state = bundle.getState();
-        BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class);
-        bundleState.options =
-            (bundleStartLevel.isActivationPolicyUsed() ? Bundle.START_ACTIVATION_POLICY : 0) |
-            (((bundleState.state & (STARTING|ACTIVE|STOPPING)) != 0) ?
-                (bundleStartLevel.isPersistentlyStarted() ? 0 : Bundle.START_TRANSIENT) : 0);
-        return bundleState;
-    }
-
-    static Predicate<Bundle> fromNamespaceQuery(UriInfo info) {
-        MultivaluedMap<String,String> parameters = info.getQueryParameters(true);
-
-        if (parameters.isEmpty()) {
-            return b -> true;
-        }
-
-        Map<String, List<Filter>> filters = parameters.entrySet().stream().flatMap(
-            e -> e.getValue().stream().map(v -> new SimpleEntry<>(e.getKey(), v))
-        ).map(
-            e -> new SimpleEntry<>(e.getKey(), create(e.getValue()))
-        ).collect(
-            groupingBy(Entry::getKey, mapping(Entry::getValue, toList()))
-        );
-
-        if (filters.isEmpty()) {
-            return b -> true;
-        }
-
-        return b -> {
-            BundleWiring wiring = b.adapt(BundleWiring.class);
-            return filters.entrySet().stream().allMatch(
-                entry -> {
-                    String namespace = entry.getKey();
-                    List<BundleCapability> caps = wiring.getCapabilities(namespace);
-                    return entry.getValue().stream().anyMatch(
-                        f ->
-                            caps.stream().anyMatch(
-                                cap ->
-                                    f.matches(cap.getAttributes())
-                            )
-                    );
-                }
-            );
-        };
-    }
-
-    static Predicate<ServiceReferenceDTO> fromFilterQuery(String filter) {
-        return Optional.ofNullable(
-            filter
-        ).map(
-            FrameworkResource::create
-        ).map(
-            toPredicate()
-        ).orElseGet(
-            () -> sr -> true
-        );
-    }
-
-    static Filter create(String filter) {
-        try {
-            return FrameworkUtil.createFilter(filter);
-        } catch (InvalidSyntaxException e) {
-            throw new WebApplicationException(
-                String.format("Malformed filter [%s]", filter),
-                Response.Status.BAD_REQUEST);
-        }
-    }
-
-    static Function<Filter, Predicate<ServiceReferenceDTO>> toPredicate() {
-        return f -> sr -> f.matches(new CaseInsensitiveMap(sr.properties));
-    }
-
-
-    /**
-     * This Map is used for case-insensitive key lookup during filter
-     * evaluation. This Map implementation only supports the get operation using
-     * a String key as no other operations are used by the Filter
-     * implementation.
-     */
-    private static final class CaseInsensitiveMap extends AbstractMap<String, Object> {
-        private final String[] keys;
-        private final Map<String, Object> properties;
-
-        /**
-         * Create a case insensitive map from the specified dictionary.
-         *
-         * @param properties
-         * @throws IllegalArgumentException If {@code dictionary} contains case
-         *             variants of the same key name.
-         */
-        CaseInsensitiveMap(Map<String, Object> properties) {
-            this.properties = properties;
-            List<String> keyList = new ArrayList<>(this.properties.size());
-            this.properties.forEach((k,v) -> {
-                for (String i : keyList) {
-                    if (k.equalsIgnoreCase(i)) {
-                        throw new IllegalArgumentException();
-                    }
-                }
-                keyList.add(k);
-            });
-            this.keys = keyList.toArray(new String[0]);
-        }
-
-        @Override
-        public Object get(Object o) {
-            String k = (String) o;
-            for (String key : keys) {
-                if (key.equalsIgnoreCase(k)) {
-                    return super.get(key);
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public Set<Entry<String, Object>> entrySet() {
-            return this.properties.entrySet();
-        }
-
-    }
-
 }
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkServiceResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkServiceResource.java
new file mode 100644
index 0000000..7d64da5
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkServiceResource.java
@@ -0,0 +1,110 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.*;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.schema.ServiceSchema;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.dto.ServiceReferenceDTO;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkServiceResource extends BaseResource {
+
+    public FrameworkServiceResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.9.1
+    @GET
+    @Produces({APPLICATION_SERVICE_JSON, APPLICATION_SERVICE_XML})
+    @Path("framework/service/{serviceid}{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/service",
+        summary = "Retrieves a Service Representation from the REST management service",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request has been served successfully",
+                content = @Content(schema = @Schema(implementation = ServiceSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "There is no service with the given service id"
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response service(
+        @PathParam("serviceid") long serviceid,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        ResponseBuilder builder = Response.ok(
+            Stream.of(
+                bundleContext.getBundles()
+            ).flatMap(
+                bundle -> Optional.ofNullable(
+                    bundle.adapt(ServiceReferenceDTO[].class)
+                ).map(
+                    Stream::of
+                ).orElseGet(
+                    Stream::empty
+                )
+            ).filter(
+                sr -> sr.id == serviceid
+            ).findFirst().map(
+                sr -> ServiceSchema.build(uriInfo, sr)
+            ).orElseThrow(
+                () -> new WebApplicationException(404)
+            )
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_SERVICE_JSON : APPLICATION_SERVICE_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkServicesRepresentationsResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkServicesRepresentationsResource.java
new file mode 100644
index 0000000..df45ad0
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkServicesRepresentationsResource.java
@@ -0,0 +1,125 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static java.util.stream.Collectors.toList;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_REPRESENTATIONS_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_REPRESENTATIONS_XML;
+
+import java.util.Optional;
+import java.util.function.Predicate;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.internal.map.CaseInsensitiveMap;
+import org.apache.aries.jax.rs.rest.management.schema.ServiceSchema;
+import org.apache.aries.jax.rs.rest.management.schema.ServiceSchemaListSchema;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.dto.FrameworkDTO;
+import org.osgi.framework.dto.ServiceReferenceDTO;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkServicesRepresentationsResource extends BaseResource {
+
+    public FrameworkServicesRepresentationsResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.9.1
+    @GET
+    @Produces({APPLICATION_SERVICES_REPRESENTATIONS_JSON, APPLICATION_SERVICES_REPRESENTATIONS_XML})
+    @Path("framework/services/representations{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/services/representations",
+        summary = "Retrieves the service representation of each available service",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request has been served successfully",
+                content = @Content(schema = @Schema(implementation = ServiceSchemaListSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "400",
+                description = "The provided filter expression was not valid"
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response serviceDTOs(
+        @Parameter(
+            name = "filter",
+            in = ParameterIn.QUERY,
+            description = "A filter parameter whose value is a filter expression that follows the Core Specifications Framework Filter Syntax; see OSGi Core, Chapter 3.2.7 Filter Syntax. The filter is matched against the service attributes and only services that match are returned",
+            examples = @ExampleObject(
+                summary = "format: filter=<filter_string>",
+                value = "filter=(&(osgi.vendor=Apache Aries)(objectClass=com.acme.Widget))"
+            )
+        )
+        @QueryParam("filter") String filter,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        Predicate<ServiceReferenceDTO> predicate = fromFilterQuery(filter);
+
+        ResponseBuilder builder = Response.ok(
+            ServiceSchemaListSchema.build(
+                framework.adapt(
+                    FrameworkDTO.class
+                ).services.stream().map(
+                    sr -> {
+                        sr.properties = new CaseInsensitiveMap<Object>(sr.properties);
+                        return sr;
+                    }
+                ).filter(
+                    predicate
+                ).map(
+                    sr -> ServiceSchema.build(uriInfo, sr)
+                ).collect(toList())
+            )
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_SERVICES_REPRESENTATIONS_JSON : APPLICATION_SERVICES_REPRESENTATIONS_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkServicesResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkServicesResource.java
new file mode 100644
index 0000000..099414f
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkServicesResource.java
@@ -0,0 +1,131 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static java.util.stream.Collectors.toList;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_XML;
+
+import java.net.URI;
+import java.util.Optional;
+import java.util.function.Predicate;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.internal.map.CaseInsensitiveMap;
+import org.apache.aries.jax.rs.rest.management.schema.ServiceListSchema;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.dto.FrameworkDTO;
+import org.osgi.framework.dto.ServiceReferenceDTO;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkServicesResource extends BaseResource {
+
+    public FrameworkServicesResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.8.1
+    @GET
+    @Produces({APPLICATION_SERVICES_JSON, APPLICATION_SERVICES_XML})
+    @Path("framework/services{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/services",
+        summary = "Retrieves a Service List Representation from the REST management service",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The request has been served successfully",
+                content = @Content(schema = @Schema(implementation = ServiceListSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "400",
+                description = "The provided filter expression was not valid"
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response services(
+        @Parameter(
+            name = "filter",
+            in = ParameterIn.QUERY,
+            description = "A filter parameter whose value is a filter expression that follows the Core Specifications Framework Filter Syntax; see OSGi Core, Chapter 3.2.7 Filter Syntax. The filter is matched against the service attributes and only services that match are returned",
+            examples = @ExampleObject(
+                summary = "format: filter=<filter_string>",
+                value = "filter=(&(osgi.vendor=Apache Aries)(objectClass=com.acme.Widget))"
+            )
+        )
+        @QueryParam("filter") String filter,
+        @Parameter(allowEmptyValue = true, description = "File extension", schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        Predicate<ServiceReferenceDTO> predicate = fromFilterQuery(filter);
+
+        ResponseBuilder builder = Response.ok(
+            ServiceListSchema.build(
+                framework.adapt(FrameworkDTO.class).services.stream().map(
+                    sr -> {
+                        sr.properties = new CaseInsensitiveMap<Object>(sr.properties);
+                        return sr;
+                    }
+                ).filter(
+                    predicate
+                ).map(
+                    sr -> String.valueOf(sr.id)
+                ).map(
+                    id -> uriInfo.getBaseUriBuilder().path("framework").path("service").path(id)
+                ).map(
+                    UriBuilder::build
+                ).map(
+                    URI::toASCIIString
+                )
+                .collect(toList())
+            )
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_SERVICES_JSON : APPLICATION_SERVICES_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkStartLevelResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkStartLevelResource.java
new file mode 100644
index 0000000..ac25e05
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkStartLevelResource.java
@@ -0,0 +1,136 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_FRAMEWORKSTARTLEVEL_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_FRAMEWORKSTARTLEVEL_XML;
+
+import java.util.Optional;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.schema.FrameworkStartLevelSchema;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.startlevel.FrameworkStartLevel;
+import org.osgi.framework.startlevel.dto.FrameworkStartLevelDTO;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkStartLevelResource extends BaseResource {
+
+    public FrameworkStartLevelResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    // 137.3.1.1
+    @GET
+    @Produces({APPLICATION_FRAMEWORKSTARTLEVEL_JSON, APPLICATION_FRAMEWORKSTARTLEVEL_XML})
+    @Path("framework/startlevel{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "GET/startlevel",
+        summary = "Retrieves a Framework Startlevel Representation from the REST management service",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The framework start level",
+                content = @Content(schema = @Schema(implementation = FrameworkStartLevelSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response startlevel(
+        @Parameter(allowEmptyValue = true, schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        ResponseBuilder builder = Response.status(
+            Response.Status.OK
+        ).entity(
+            FrameworkStartLevelSchema.build(framework.adapt(FrameworkStartLevelDTO.class))
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            t -> ".json".equals(t) ? APPLICATION_FRAMEWORKSTARTLEVEL_JSON : APPLICATION_FRAMEWORKSTARTLEVEL_XML
+        ).map(t -> builder.type(t)).orElse(
+            builder
+        ).build();
+    }
+
+    // 137.3.1.2
+    @PUT
+    @Consumes({APPLICATION_FRAMEWORKSTARTLEVEL_JSON, APPLICATION_FRAMEWORKSTARTLEVEL_XML})
+    @Path("framework/startlevel{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        operationId = "PUT/startlevel",
+        summary = "Set the target framework startlevel",
+        responses = {
+            @ApiResponse(
+                responseCode = "204",
+                description = "The request was received and valid. The framework will asynchronously start to adjust the framework startlevel until the target startlevel has been reached"
+            ),
+            @ApiResponse(
+                responseCode = "400",
+                description = "The REST management service received an IllegalArgumentException when trying to adjust the framework startlevel"
+            ),
+            @ApiResponse(
+                responseCode = "415",
+                description = "The request had a media type that is not supported by the REST management service"
+            )
+        }
+    )
+    public Response startlevel(
+        FrameworkStartLevelSchema update,
+        @Parameter(allowEmptyValue = true, schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        try {
+            FrameworkStartLevel current = framework.adapt(FrameworkStartLevel.class);
+
+            if (current.getStartLevel() != update.startLevel) {
+                current.setStartLevel(update.startLevel);
+            }
+            if (current.getInitialBundleStartLevel() != update.initialBundleStartLevel) {
+                current.setInitialBundleStartLevel(update.initialBundleStartLevel);
+            }
+
+            return Response.noContent().build();
+        }
+        catch (IllegalArgumentException exception) {
+            throw new WebApplicationException(exception, 400);
+        }
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkStateResource.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkStateResource.java
new file mode 100644
index 0000000..e832012
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/FrameworkStateResource.java
@@ -0,0 +1,91 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal;
+
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTATE_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_BUNDLESTATE_XML;
+
+import java.util.Optional;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import org.apache.aries.jax.rs.rest.management.schema.BundleStateSchema;
+import org.osgi.framework.BundleContext;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+
+public class FrameworkStateResource extends BaseResource {
+
+    public FrameworkStateResource(BundleContext bundleContext) {
+        super(bundleContext);
+    }
+
+    @GET
+    @Produces({APPLICATION_BUNDLESTATE_JSON, APPLICATION_BUNDLESTATE_XML})
+    @Path("framework/state{ext:(\\.json|\\.xml)*}")
+    @Operation(
+        summary = "Get the framework state by extension type",
+        responses = {
+            @ApiResponse(
+                responseCode = "200",
+                description = "The framework state",
+                content = @Content(schema = @Schema(implementation = BundleStateSchema.class))
+            ),
+            @ApiResponse(
+                responseCode = "404",
+                description = "Framework not found"
+            ),
+            @ApiResponse(
+                responseCode = "406",
+                description = "The REST management service does not support any of the requested representations"
+            )
+        }
+    )
+    public Response state(
+        @Parameter(allowEmptyValue = true, schema = @Schema(allowableValues = {".json", ".xml"}))
+        @PathParam("ext") String ext) {
+
+        ResponseBuilder builder = Response.status(
+            Response.Status.OK
+        ).entity(
+            bundleStateSchema(framework)
+        );
+
+        return Optional.ofNullable(
+            ext
+        ).map(
+            String::trim
+        ).map(
+            e -> ".json".equals(e) ? APPLICATION_BUNDLESTATE_JSON : APPLICATION_BUNDLESTATE_XML
+        ).map(
+            type -> builder.type(type)
+        ).orElse(
+            builder
+        ).build();
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestClientImpl.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestClientImpl.java
deleted file mode 100644
index d243dd5..0000000
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestClientImpl.java
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * 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.aries.jax.rs.rest.management.internal;
-
-import static javax.ws.rs.core.MediaType.*;
-import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.*;
-
-import java.io.InputStream;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.GenericType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.StatusType;
-
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
-import org.apache.aries.jax.rs.rest.management.model.BundleStateDTO;
-import org.apache.aries.jax.rs.rest.management.model.BundlesDTO;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.dto.BundleDTO;
-import org.osgi.framework.dto.ServiceReferenceDTO;
-import org.osgi.framework.startlevel.dto.BundleStartLevelDTO;
-import org.osgi.framework.startlevel.dto.FrameworkStartLevelDTO;
-import org.osgi.service.rest.client.RestClient;
-
-public class RestClientImpl implements RestClient {
-
-    private static final GenericType<List<BundleDTO>> BUNDLE_LIST =
-        new GenericType<List<BundleDTO>>() {};
-
-    private final WebTarget webTarget;
-
-    public RestClientImpl(WebTarget webTarget) {
-        this.webTarget = webTarget;
-
-        this.webTarget.register(RestManagementMessageBodyHandler.class);
-    }
-
-    @Override
-    public FrameworkStartLevelDTO getFrameworkStartLevel() throws Exception {
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "startlevel"
-            ).request().get()
-        )) {
-            return response.readEntity(FrameworkStartLevelDTO.class);
-        }
-    }
-
-    @Override
-    public void setFrameworkStartLevel(FrameworkStartLevelDTO startLevel) throws Exception {
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "startlevel"
-            ).request().put(
-                Entity.entity(
-                    startLevel, APPLICATION_FRAMEWORKSTARTLEVEL_JSON)
-            )
-        )) {}
-    }
-
-    @Override
-    public Collection<String> getBundlePaths() throws Exception {
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "bundles"
-            ).request().get()
-        )) {
-            return response.readEntity(BundlesDTO.class).bundles;
-        }
-    }
-
-    @Override
-    public Collection<BundleDTO> getBundles() throws Exception {
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "bundles"
-            ).path(
-                "representations"
-            ).request().get()
-        )) {
-            return response.readEntity(BUNDLE_LIST);
-        }
-    }
-
-    @Override
-    public BundleDTO getBundle(long id) throws Exception {
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "bundle"
-            ).path(
-                "{bundleid}"
-            ).resolveTemplate(
-                "bundleid", id
-            ).request().get()
-        )) {
-            return response.readEntity(BundleDTO.class);
-        }
-    }
-
-    @Override
-    public BundleDTO getBundle(String bundlePath) throws Exception {
-        try (Response response = maybeThrow(
-            webTarget.path(
-                bundlePath
-            ).request().get()
-        )) {
-            return response.readEntity(BundleDTO.class);
-        }
-    }
-
-    @Override
-    public int getBundleState(long id) throws Exception {
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "bundle"
-            ).path(
-                "{bundleid}"
-            ).path(
-                "state"
-            ).resolveTemplate(
-                "bundleid", id
-            ).request().get()
-        )) {
-            return response.readEntity(BundleStateDTO.class).state;
-        }
-    }
-
-    @Override
-    public int getBundleState(String bundlePath) throws Exception {
-        try (Response response = maybeThrow(
-            webTarget.path(
-                bundlePath
-            ).path(
-                "state"
-            ).request().get()
-        )) {
-            return response.readEntity(BundleStateDTO.class).state;
-        }
-    }
-
-    @Override
-    public void startBundle(long id) throws Exception {
-        BundleStateDTO bundleStateDTO = new BundleStateDTO();
-        bundleStateDTO.state = Bundle.ACTIVE;
-
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "bundle"
-            ).path(
-                "{bundleid}"
-            ).path(
-                "state"
-            ).resolveTemplate(
-                "bundleid", id
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            )
-        )) {
-        }
-    }
-
-    @Override
-    public void startBundle(String bundlePath) throws Exception {
-        BundleStateDTO bundleStateDTO = new BundleStateDTO();
-        bundleStateDTO.state = Bundle.ACTIVE;
-
-        try (Response response = maybeThrow(
-            webTarget.path(
-                bundlePath
-            ).path(
-                "state"
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            )
-        )) {
-        }
-    }
-
-    @Override
-    public void startBundle(long id, int options) throws Exception {
-        BundleStateDTO bundleStateDTO = new BundleStateDTO();
-        bundleStateDTO.state = Bundle.ACTIVE;
-        bundleStateDTO.options = options;
-
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "bundle"
-            ).path(
-                "{bundleid}"
-            ).path(
-                "state"
-            ).resolveTemplate(
-                "bundleid", id
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            )
-        )) {
-        }
-    }
-
-    @Override
-    public void startBundle(String bundlePath, int options) throws Exception {
-        BundleStateDTO bundleStateDTO = new BundleStateDTO();
-        bundleStateDTO.state = Bundle.ACTIVE;
-        bundleStateDTO.options = options;
-
-        try (Response response = maybeThrow(
-            webTarget.path(
-                bundlePath
-            ).path(
-                "state"
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            )
-        )) {
-        }
-    }
-
-    @Override
-    public void stopBundle(long id) throws Exception {
-        BundleStateDTO bundleStateDTO = new BundleStateDTO();
-        bundleStateDTO.state = Bundle.RESOLVED;
-
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "bundle"
-            ).path(
-                "{bundleid}"
-            ).path(
-                "state"
-            ).resolveTemplate(
-                "bundleid", id
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            )
-        )) {
-        }
-    }
-
-    @Override
-    public void stopBundle(String bundlePath) throws Exception {
-        BundleStateDTO bundleStateDTO = new BundleStateDTO();
-        bundleStateDTO.state = Bundle.RESOLVED;
-
-        try (Response response = maybeThrow(
-            webTarget.path(
-                bundlePath
-            ).path(
-                "state"
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            )
-        )) {
-        }
-    }
-
-    @Override
-    public void stopBundle(long id, int options) throws Exception {
-        BundleStateDTO bundleStateDTO = new BundleStateDTO();
-        bundleStateDTO.state = Bundle.RESOLVED;
-        bundleStateDTO.options = options;
-
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework"
-            ).path(
-                "bundle"
-            ).path(
-                "{bundleid}"
-            ).path(
-                "state"
-            ).resolveTemplate(
-                "bundleid", id
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            )
-        )) {
-        }
-    }
-
-    @Override
-    public void stopBundle(String bundlePath, int options) throws Exception {
-        BundleStateDTO bundleStateDTO = new BundleStateDTO();
-        bundleStateDTO.state = Bundle.RESOLVED;
-        bundleStateDTO.options = options;
-
-        try (Response response = maybeThrow(
-            webTarget.path(
-                bundlePath
-            ).path(
-                "state"
-            ).request().put(
-                Entity.entity(
-                    bundleStateDTO,
-                    APPLICATION_BUNDLESTATE_JSON_TYPE
-                )
-            )
-        )) {
-        }
-    }
-
-    @Override
-    public Map<String, String> getBundleHeaders(long id) throws Exception {
-//        try (Response response = maybeThrow(
-//            webTarget.path(
-//                "framework"
-//            ).path(
-//                "bundle"
-//            ).path(
-//                "{bundleid}"
-//            ).path(
-//                "header"
-//            ).resolveTemplate(
-//                    "bundleid", id
-//            ).request().get()
-//        )) {
-//        }
-        // TODO
-        return null;
-    }
-
-    @Override
-    public Map<String, String> getBundleHeaders(String bundlePath) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public BundleStartLevelDTO getBundleStartLevel(long id) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public BundleStartLevelDTO getBundleStartLevel(String bundlePath) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public void setBundleStartLevel(long id, int startLevel) throws Exception {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void setBundleStartLevel(String bundlePath, int startLevel) throws Exception {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public BundleDTO installBundle(String location) throws Exception {
-        try (Response response = maybeThrow(
-            webTarget.path(
-                "framework/bundles"
-            ).request(APPLICATION_BUNDLE_JSON).post(
-                Entity.entity(location, TEXT_PLAIN)
-            )
-        )) {
-            return response.readEntity(
-                BundleDTO.class
-            );
-        }
-    }
-
-    @Override
-    public BundleDTO installBundle(String location, InputStream in) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public BundleDTO uninstallBundle(long id) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public BundleDTO uninstallBundle(String bundlePath) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public BundleDTO updateBundle(long id) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public BundleDTO updateBundle(long id, String url) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public BundleDTO updateBundle(long id, InputStream in) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Collection<String> getServicePaths() throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Collection<String> getServicePaths(String filter) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Collection<ServiceReferenceDTO> getServiceReferences() throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Collection<ServiceReferenceDTO> getServiceReferences(String filter) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public ServiceReferenceDTO getServiceReference(long id) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public ServiceReferenceDTO getServiceReference(String servicePath) throws Exception {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    private Response maybeThrow(Response response) throws Exception {
-        StatusType statusInfo = response.getStatusInfo();
-
-        if (statusInfo.getStatusCode() >= 300) {
-            throw new Exception(statusInfo.getReasonPhrase());
-        }
-
-        return response;
-    }
-
-}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestManagementActivator.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestManagementActivator.java
index 0b7cccc..e742c83 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestManagementActivator.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestManagementActivator.java
@@ -22,22 +22,20 @@ import static org.apache.aries.component.dsl.OSGi.ignore;
 import static org.apache.aries.component.dsl.OSGi.register;
 import static org.apache.aries.component.dsl.OSGi.service;
 import static org.apache.aries.component.dsl.OSGi.serviceReferences;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.SPECIFICATION_VERSION;
 import static org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_APPLICATION_SELECT;
 import static org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_EXTENSION;
-import static org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_EXTENSION_SELECT;
 import static org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_NAME;
-import static org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_RESOURCE;
 
 import java.util.HashMap;
 import java.util.function.BiFunction;
 
 import javax.ws.rs.client.ClientBuilder;
 import javax.ws.rs.core.Application;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
 
 import org.apache.aries.component.dsl.OSGiResult;
-import org.apache.aries.jax.rs.rest.management.handler.RestManagementMessageBodyHandler;
+import org.apache.aries.jax.rs.rest.management.feature.RestManagementFeature;
+import org.apache.aries.jax.rs.rest.management.internal.client.RestClientFactoryImpl;
 import org.osgi.annotation.bundle.Header;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
@@ -48,9 +46,11 @@ import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
 import org.osgi.service.rest.client.RestClientFactory;
 
+import io.swagger.v3.oas.models.ExternalDocumentation;
 import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.info.Contact;
 import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
 
 @Header(name = Constants.BUNDLE_ACTIVATOR, value = "${@class}")
 public class RestManagementActivator implements BundleActivator {
@@ -65,7 +65,7 @@ public class RestManagementActivator implements BundleActivator {
             ignore(
                 register(
                     Application.class,
-                    () -> new RestManagementApplication(),
+                    () -> new RestManagementApplication(bundleContext),
                     () -> {
                         HashMap<String, Object> map = new HashMap<>();
 
@@ -90,17 +90,14 @@ public class RestManagementActivator implements BundleActivator {
             ),
             ignore(
                 register(
-                    new String[] {
-                        MessageBodyReader.class.getName(),
-                        MessageBodyWriter.class.getName()
-                    },
-                    () -> new PrototypeWrapper<>(
-                        (b, r) -> new RestManagementMessageBodyHandler()
+                    javax.ws.rs.core.Feature.class,
+                    new PrototypeWrapper<>(
+                        (b, r) -> new RestManagementFeature()
                     ),
                     () -> {
                         HashMap<String, Object> map = new HashMap<>();
 
-                        map.put(JAX_RS_NAME, RestManagementMessageBodyHandler.class.getSimpleName());
+                        map.put(JAX_RS_NAME, RestManagementFeature.class.getSimpleName());
                         map.put(
                             JAX_RS_APPLICATION_SELECT,
                             String.format(
@@ -114,40 +111,34 @@ public class RestManagementActivator implements BundleActivator {
             ),
             ignore(
                 register(
-                    FrameworkResource.class,
-                    () -> new FrameworkResource(bundleContext),
-                    () -> {
-                        HashMap<String, Object> map = new HashMap<>();
-
-                        map.put(
-                            JAX_RS_APPLICATION_SELECT,
-                            String.format(
-                                "(%s=%s)", JAX_RS_NAME,
-                                RestManagementApplication.class.getSimpleName()));
-                        map.put(JAX_RS_RESOURCE, true);
-                        map.put(JAX_RS_EXTENSION_SELECT, new String[] {
-                            String.format(
-                                "(%s=%s)", JAX_RS_NAME,
-                                RestManagementMessageBodyHandler.class.getSimpleName())
-                        });
-
-                        return map;
-                    }
-                )
-            ),
-            ignore(
-                register(
                     OpenAPI.class,
                     () -> {
                         OpenAPI openAPI = new OpenAPI();
 
                         openAPI.info(
-                            new Info()
-                                .title("Apache Aries OSGi Rest Management Service")
-                                .description("Apache Aries OSGi Rest Management Service REST API")
-                                .contact(
-                                    new Contact()
-                                        .email("dev@aries.apache.org"))
+                            new Info().title(
+                                "Apache Aries OSGi Rest Management Service"
+                            ).description(
+                                "A REST API to manage an OSGi Framework"
+                            ).license(
+                                new License().name(
+                                    "Apache 2.0"
+                                ).url(
+                                    "https://www.apache.org/licenses/LICENSE-2.0.html"
+                                )
+                            ).version(
+                                SPECIFICATION_VERSION
+                            ).contact(
+                                new Contact().email(
+                                    "dev@aries.apache.org"
+                                )
+                            )
+                        ).externalDocs(
+                            new ExternalDocumentation().description(
+                                "OSGi Compendium Chapter 137 - REST Management Service Specification"
+                            ).url(
+                                "https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.rest.html"
+                            )
                         );
 
                         return openAPI;
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestManagementApplication.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestManagementApplication.java
index 7899130..d7d5ab3 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestManagementApplication.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestManagementApplication.java
@@ -17,7 +17,41 @@
 
 package org.apache.aries.jax.rs.rest.management.internal;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import javax.ws.rs.core.Application;
 
+import org.apache.aries.jax.rs.rest.management.internal.jaxb.ServiceSchemaContextResolver;
+import org.osgi.framework.BundleContext;
+
 public class RestManagementApplication extends Application {
+
+    private final BundleContext bundleContext;
+
+    public RestManagementApplication(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public Set<Object> getSingletons() {
+        Set<Object> singletons = new HashSet<>();
+
+        singletons.add(new ServiceSchemaContextResolver());
+
+        singletons.add(new FrameworkBundleHeaderResource(bundleContext));
+        singletons.add(new FrameworkBundleResource(bundleContext));
+        singletons.add(new FrameworkBundlesRepresentationsResource(bundleContext));
+        singletons.add(new FrameworkBundlesResource(bundleContext));
+        singletons.add(new FrameworkBundleStartLevelResource(bundleContext));
+        singletons.add(new FrameworkBundleStateResource(bundleContext));
+        singletons.add(new FrameworkResource(bundleContext));
+        singletons.add(new FrameworkServiceResource(bundleContext));
+        singletons.add(new FrameworkServicesRepresentationsResource(bundleContext));
+        singletons.add(new FrameworkServicesResource(bundleContext));
+        singletons.add(new FrameworkStartLevelResource(bundleContext));
+        singletons.add(new FrameworkStateResource(bundleContext));
+        return singletons;
+    }
+
 }
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestClientFactoryImpl.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/client/RestClientFactoryImpl.java
similarity index 95%
rename from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestClientFactoryImpl.java
rename to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/client/RestClientFactoryImpl.java
index 9ef5bd4..6dee095 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/RestClientFactoryImpl.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/client/RestClientFactoryImpl.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.aries.jax.rs.rest.management.internal;
+package org.apache.aries.jax.rs.rest.management.internal.client;
 
 import java.net.URI;
 
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/client/RestClientImpl.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/client/RestClientImpl.java
new file mode 100644
index 0000000..e69cfb3
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/client/RestClientImpl.java
@@ -0,0 +1,786 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal.client;
+
+import static java.util.stream.Collectors.toList;
+import static javax.ws.rs.core.HttpHeaders.CONTENT_LOCATION;
+import static javax.ws.rs.core.MediaType.*;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.*;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.StatusType;
+
+import org.apache.aries.jax.rs.rest.management.feature.RestManagementFeature;
+import org.apache.aries.jax.rs.rest.management.schema.BundleExceptionSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleHeaderSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleStateSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleListSchema;
+import org.apache.aries.jax.rs.rest.management.schema.BundleSchemaListSchema;
+import org.apache.aries.jax.rs.rest.management.schema.FrameworkStartLevelSchema;
+import org.apache.aries.jax.rs.rest.management.schema.ServiceSchemaListSchema;
+import org.apache.aries.jax.rs.rest.management.schema.ServiceListSchema;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.dto.BundleDTO;
+import org.osgi.framework.dto.ServiceReferenceDTO;
+import org.osgi.framework.startlevel.dto.BundleStartLevelDTO;
+import org.osgi.framework.startlevel.dto.FrameworkStartLevelDTO;
+import org.osgi.service.rest.client.RestClient;
+
+public class RestClientImpl implements RestClient {
+
+    private final WebTarget webTarget;
+
+    public RestClientImpl(WebTarget webTarget) {
+        this.webTarget = webTarget;
+
+        this.webTarget.register(RestManagementFeature.class);
+    }
+
+    @Override
+    public FrameworkStartLevelDTO getFrameworkStartLevel() throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "startlevel"
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(FrameworkStartLevelSchema.class);
+        }
+    }
+
+    @Override
+    public void setFrameworkStartLevel(FrameworkStartLevelDTO startLevel) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "startlevel"
+            ).request(
+            ).put(
+                Entity.entity(
+                    FrameworkStartLevelSchema.build(startLevel), APPLICATION_FRAMEWORKSTARTLEVEL_JSON
+                )
+            )
+        )) {}
+    }
+
+    @Override
+    public Collection<String> getBundlePaths() throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundles"
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(BundleListSchema.class).bundles;
+        }
+    }
+
+    @Override
+    public Collection<BundleDTO> getBundles() throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundles"
+            ).path(
+                "representations"
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(
+                BundleSchemaListSchema.class
+            ).bundles.stream().map(
+                BundleDTO.class::cast
+            ).collect(toList());
+        }
+    }
+
+    @Override
+    public BundleDTO getBundle(long id) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(BundleSchema.class);
+        }
+    }
+
+    @Override
+    public BundleDTO getBundle(String bundlePath) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(BundleSchema.class);
+        }
+    }
+
+    @Override
+    public int getBundleState(long id) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).path(
+                "state"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(BundleStateSchema.class).state;
+        }
+    }
+
+    @Override
+    public int getBundleState(String bundlePath) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).path(
+                "state"
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(BundleStateSchema.class).state;
+        }
+    }
+
+    @Override
+    public void startBundle(long id) throws Exception {
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.ACTIVE;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).path(
+                "state"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStateDTO,
+                    APPLICATION_BUNDLESTATE_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public void startBundle(String bundlePath) throws Exception {
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.ACTIVE;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).path(
+                "state"
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStateDTO,
+                    APPLICATION_BUNDLESTATE_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public void startBundle(long id, int options) throws Exception {
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.ACTIVE;
+        bundleStateDTO.options = options;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).path(
+                "state"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStateDTO,
+                    APPLICATION_BUNDLESTATE_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public void startBundle(String bundlePath, int options) throws Exception {
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.ACTIVE;
+        bundleStateDTO.options = options;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).path(
+                "state"
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStateDTO,
+                    APPLICATION_BUNDLESTATE_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public void stopBundle(long id) throws Exception {
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.RESOLVED;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).path(
+                "state"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStateDTO,
+                    APPLICATION_BUNDLESTATE_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public void stopBundle(String bundlePath) throws Exception {
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.RESOLVED;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).path(
+                "state"
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStateDTO,
+                    APPLICATION_BUNDLESTATE_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public void stopBundle(long id, int options) throws Exception {
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.RESOLVED;
+        bundleStateDTO.options = options;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).path(
+                "state"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStateDTO,
+                    APPLICATION_BUNDLESTATE_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public void stopBundle(String bundlePath, int options) throws Exception {
+        BundleStateSchema bundleStateDTO = new BundleStateSchema();
+        bundleStateDTO.state = Bundle.RESOLVED;
+        bundleStateDTO.options = options;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).path(
+                "state"
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStateDTO,
+                    APPLICATION_BUNDLESTATE_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public Map<String, String> getBundleHeaders(long id) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).path(
+                "header"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(BundleHeaderSchema.class);
+        }
+    }
+
+    @Override
+    public Map<String, String> getBundleHeaders(String bundlePath) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(BundleHeaderSchema.class);
+        }
+    }
+
+    @Override
+    public BundleStartLevelDTO getBundleStartLevel(long id) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).path(
+                "startlevel"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(BundleStartLevelDTO.class);
+        }
+    }
+
+    @Override
+    public BundleStartLevelDTO getBundleStartLevel(String bundlePath) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).path(
+                "startlevel"
+            ).request(
+            ).get()
+        )) {
+            return response.readEntity(BundleStartLevelDTO.class);
+        }
+    }
+
+    @Override
+    public void setBundleStartLevel(long id, int startLevel) throws Exception {
+        BundleStartLevelDTO bundleStartLevelDTO = new BundleStartLevelDTO();
+        bundleStartLevelDTO.startLevel = startLevel;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).path(
+                "startlevel"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStartLevelDTO,
+                    APPLICATION_BUNDLESTARTLEVEL_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public void setBundleStartLevel(String bundlePath, int startLevel) throws Exception {
+        BundleStartLevelDTO bundleStartLevelDTO = new BundleStartLevelDTO();
+        bundleStartLevelDTO.startLevel = startLevel;
+
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).path(
+                "startlevel"
+            ).request(
+            ).put(
+                Entity.entity(
+                    bundleStartLevelDTO,
+                    APPLICATION_BUNDLESTARTLEVEL_JSON_TYPE
+                )
+            )
+        )) {
+        }
+    }
+
+    @Override
+    public BundleDTO installBundle(String location) throws Exception {
+        try (Response response = maybeThrow(() -> {
+            Response r = webTarget.path(
+                "framework"
+            ).path(
+                "bundles"
+            ).request(
+                APPLICATION_BUNDLE_JSON
+            ).post(
+                Entity.entity(location, TEXT_PLAIN)
+            );
+
+            StatusType statusInfo = r.getStatusInfo();
+            if (statusInfo.getStatusCode() == 400) {
+                BundleExceptionSchema bundleExceptionSchema = r.readEntity(BundleExceptionSchema.class);
+                throw new BundleException(bundleExceptionSchema.message, bundleExceptionSchema.typecode);
+            }
+
+            return r;
+        })) {
+            return response.readEntity(
+                BundleSchema.class
+            );
+        }
+    }
+
+    @Override
+    public BundleDTO installBundle(String location, InputStream in) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundles"
+            ).request(
+                APPLICATION_BUNDLE_JSON
+            ).header(
+                CONTENT_LOCATION, location
+            ).post(
+                Entity.entity(in, APPLICATION_OCTET_STREAM_TYPE)
+            )
+        )) {
+            return response.readEntity(
+                BundleSchema.class
+            );
+        }
+    }
+
+    @Override
+    public BundleDTO uninstallBundle(long id) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+                APPLICATION_BUNDLE_JSON
+            ).delete()
+        )) {
+            return response.readEntity(
+                BundleSchema.class
+            );
+        }
+    }
+
+    @Override
+    public BundleDTO uninstallBundle(String bundlePath) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                bundlePath
+            ).request(
+                APPLICATION_BUNDLE_JSON
+            ).delete()
+        )) {
+            return response.readEntity(
+                BundleSchema.class
+            );
+        }
+    }
+
+    @Override
+    public BundleDTO updateBundle(long id) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+                APPLICATION_BUNDLE_JSON
+            ).put(
+                Entity.entity("", TEXT_PLAIN_TYPE)
+            )
+        )) {
+            return response.readEntity(
+                BundleSchema.class
+            );
+        }
+    }
+
+    @Override
+    public BundleDTO updateBundle(long id, String url) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+                APPLICATION_BUNDLE_JSON
+            ).put(
+                Entity.entity(url, TEXT_PLAIN_TYPE)
+            )
+        )) {
+            return response.readEntity(
+                BundleSchema.class
+            );
+        }
+    }
+
+    @Override
+    public BundleDTO updateBundle(long id, InputStream in) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "bundle"
+            ).path(
+                "{bundleid}"
+            ).resolveTemplate(
+                "bundleid", id
+            ).request(
+                APPLICATION_BUNDLE_JSON
+            ).put(
+                Entity.entity(in, APPLICATION_OCTET_STREAM_TYPE)
+            )
+        )) {
+            return response.readEntity(
+                BundleSchema.class
+            );
+        }
+    }
+
+    @Override
+    public Collection<String> getServicePaths() throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "services"
+            ).request(
+                APPLICATION_SERVICES_JSON_TYPE
+            ).get()
+        )) {
+            return response.readEntity(
+                ServiceListSchema.class
+            ).services;
+        }
+    }
+
+    @Override
+    public Collection<String> getServicePaths(String filter) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "services"
+            ).queryParam(
+                "filter", filter
+            ).request(
+                APPLICATION_SERVICES_JSON_TYPE
+            ).get()
+        )) {
+            return response.readEntity(
+                ServiceListSchema.class
+            ).services;
+        }
+    }
+
+    @Override
+    public Collection<ServiceReferenceDTO> getServiceReferences() throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "services"
+            ).path(
+                "representations"
+            ).request(
+                APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE
+            ).get()
+        )) {
+            return response.readEntity(
+                ServiceSchemaListSchema.class
+            ).services.stream().map(
+                ServiceReferenceDTO.class::cast
+            ).collect(toList());
+        }
+    }
+
+    @Override
+    public Collection<ServiceReferenceDTO> getServiceReferences(String filter) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "services"
+            ).path(
+                "representations"
+            ).queryParam(
+                "filter", filter
+            ).request(
+                APPLICATION_SERVICES_REPRESENTATIONS_JSON_TYPE
+            ).get()
+        )) {
+            return response.readEntity(
+                ServiceSchemaListSchema.class
+            ).services.stream().map(
+                ServiceReferenceDTO.class::cast
+            ).collect(toList());
+        }
+    }
+
+    @Override
+    public ServiceReferenceDTO getServiceReference(long id) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                "framework"
+            ).path(
+                "service"
+            ).path(
+                "{serviceid}"
+            ).resolveTemplate(
+                "serviceid", id
+            ).request(
+                APPLICATION_SERVICE_JSON_TYPE
+            ).get()
+        )) {
+            return response.readEntity(
+                ServiceReferenceDTO.class
+            );
+        }
+    }
+
+    @Override
+    public ServiceReferenceDTO getServiceReference(String servicePath) throws Exception {
+        try (Response response = maybeThrow(
+            webTarget.path(
+                servicePath
+            ).request(
+                APPLICATION_SERVICE_JSON_TYPE
+            ).get()
+        )) {
+            return response.readEntity(
+                ServiceReferenceDTO.class
+            );
+        }
+    }
+
+    private Response maybeThrow(Response response) throws Exception {
+        return maybeThrow(() -> response);
+    }
+
+    private Response maybeThrow(Callable<Response> alternate) throws Exception {
+        Response response = alternate.call();
+
+        StatusType statusInfo = response.getStatusInfo();
+
+        if (statusInfo.getStatusCode() >= 300) {
+            throw new Exception(statusInfo.getReasonPhrase());
+        }
+
+        return response;
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/Coerce.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/coerce/Coerce.java
similarity index 96%
rename from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/Coerce.java
rename to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/coerce/Coerce.java
index 249a698..f7e6528 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/handler/Coerce.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/coerce/Coerce.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.aries.jax.rs.rest.management.handler;
+package org.apache.aries.jax.rs.rest.management.internal.coerce;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -49,7 +49,7 @@ public class Coerce {
         return list;
     }
 
-    public static String type(Attribute typeAT, String name) {
+    public static String type(String type, String name) {
         if (Constants.SERVICE_ID.equals(name) ||
             Constants.SERVICE_BUNDLEID.equals(name)) {
             return "Long";
@@ -63,10 +63,10 @@ public class Coerce {
             return "String";
         }
 
-        if (typeAT == null) {
+        if (type == null) {
             return "String";
         }
-        return typeAT.getValue();
+        return type;
     }
 
     public static String type(JsonNode node, String name) {
@@ -134,7 +134,7 @@ public class Coerce {
             s -> s.trim().split("\\s*\\n\\s*")
         ).map(Arrays::asList).orElseGet(ArrayList::new);
 
-        return from(type(typeAT, keyAT.getValue()), array, valueParts);
+        return from(type((typeAT == null ? null : typeAT.getValue()), keyAT.getValue()), array, valueParts);
     }
 
     public static Object from(
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/jaxb/ServiceSchemaContextResolver.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/jaxb/ServiceSchemaContextResolver.java
new file mode 100644
index 0000000..6a5cacd
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/jaxb/ServiceSchemaContextResolver.java
@@ -0,0 +1,55 @@
+package org.apache.aries.jax.rs.rest.management.internal.jaxb;
+
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_REPRESENTATIONS_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICES_REPRESENTATIONS_XML;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICE_JSON;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.APPLICATION_SERVICE_XML;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ContextResolver;
+import javax.ws.rs.ext.Provider;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+
+import org.apache.aries.jax.rs.rest.management.schema.ServiceSchema;
+import org.apache.aries.jax.rs.rest.management.schema.ServiceSchemaListSchema;
+
+@Provider
+@Produces({
+    APPLICATION_SERVICE_JSON,
+    APPLICATION_SERVICE_XML,
+    APPLICATION_SERVICES_REPRESENTATIONS_JSON,
+    APPLICATION_SERVICES_REPRESENTATIONS_XML
+})
+public class ServiceSchemaContextResolver implements ContextResolver<JAXBContext> {
+
+    private JAXBContext ctx;
+
+    public ServiceSchemaContextResolver() {
+        try {
+            this.ctx = JAXBContext.newInstance(
+                ArrayList.class,
+                AtomicLong.class,
+                Response.class,
+                ServiceSchema.class,
+                ServiceSchemaListSchema.class,
+                String[].class
+            );
+        }
+        catch (JAXBException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public JAXBContext getContext(Class<?> type) {
+        return (
+            type.equals(ServiceSchema.class) ||
+            type.equals(ServiceSchemaListSchema.class)? ctx : null
+        );
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/map/CaseInsensitiveMap.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/map/CaseInsensitiveMap.java
new file mode 100644
index 0000000..691b9d6
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/map/CaseInsensitiveMap.java
@@ -0,0 +1,116 @@
+/*
+ * 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.aries.jax.rs.rest.management.internal.map;
+
+import static java.util.stream.Collectors.toCollection;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * This Map is used for case-insensitive key lookup during filter
+ * evaluation. This Map implementation only supports the get operation using
+ * a String key as no other operations are used by the Filter
+ * implementation.
+ */
+public class CaseInsensitiveMap<T> extends AbstractMap<String, T> {
+    private final String[] keys;
+    private final Set<Map.Entry<String, T>> properties;
+
+    /**
+     * Create a case insensitive map from the specified dictionary.
+     *
+     * @param dictionary
+     * @throws IllegalArgumentException If {@code dictionary} contains case
+     *             variants of the same key name.
+     */
+    @SuppressWarnings("serial")
+    public CaseInsensitiveMap(final Dictionary<String, T> dictionary) {
+        this(() -> {
+            Set<Map.Entry<String, T>> entries = new HashSet<>(dictionary.size());
+            for (Enumeration<String> e = dictionary.keys(); e.hasMoreElements();) {
+                final String k = e.nextElement();
+                entries.add(
+                    new SimpleImmutableEntry<String, T>(k, null) {
+                        public T getValue() {
+                            return dictionary.get(getKey());
+                        }
+                    }
+                );
+            }
+            return entries;
+        });
+    }
+
+    /**
+     * Create a case insensitive map from the specified map.
+     *
+     * @param properties
+     * @throws IllegalArgumentException If {@code dictionary} contains case
+     *             variants of the same key name.
+     */
+    public CaseInsensitiveMap(final Map<String, T> properties) {
+        this(() -> properties.entrySet());
+    }
+
+    CaseInsensitiveMap(final Supplier<Set<Map.Entry<String, T>>> properties) {
+        this.properties = properties.get().stream().sorted(
+            (a, b) -> a.getKey().compareTo(b.getKey())
+        ).collect(
+            toCollection(LinkedHashSet::new)
+        );
+
+        List<String> keyList = new ArrayList<>(this.properties.size());
+
+        this.properties.forEach(e -> {
+            for (String i : keyList) {
+                if (e.getKey().equalsIgnoreCase(i)) {
+                    throw new IllegalArgumentException();
+                }
+            }
+            keyList.add(e.getKey());
+        });
+
+        this.keys = keyList.toArray(new String[0]);
+    }
+
+    @Override
+    public T get(Object o) {
+        String k = (String) o;
+        for (String key : keys) {
+            if (key.equalsIgnoreCase(k)) {
+                return super.get(key);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Set<Entry<String, T>> entrySet() {
+        return this.properties;
+    }
+
+}
\ No newline at end of file
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/package-info.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/package-info.java
index 6100eb1..90379a3 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/package-info.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/internal/package-info.java
@@ -19,10 +19,8 @@
     namespace = IMPLEMENTATION_NAMESPACE,
     name = "org.apache.aries.jax.rs.openapi"
 )
-@Version("1.0.0")
 package org.apache.aries.jax.rs.rest.management.internal;
 
 import static org.osgi.namespace.implementation.ImplementationNamespace.IMPLEMENTATION_NAMESPACE;
 
 import org.osgi.annotation.bundle.Requirement;
-import org.osgi.annotation.versioning.Version;
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/package-info.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/package-info.java
index 5621024..008d751 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/package-info.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/package-info.java
@@ -17,7 +17,24 @@
 
 @Export
 @Version("1.0.0")
+@Capability(
+    name = SPECIFICATION_IMPLEMENTATION,
+    namespace = IMPLEMENTATION_NAMESPACE,
+    version = SPECIFICATION_VERSION,
+    uses = org.osgi.service.rest.RestApiExtension.class
+)
+@org.osgi.annotation.bundle.Capability(
+    attribute = "objectClass:List<String>='org.osgi.service.rest.client.RestClientFactory'",
+    namespace = SERVICE_NAMESPACE,
+    uses = org.osgi.service.rest.client.RestClientFactory.class
+)
 package org.apache.aries.jax.rs.rest.management;
 
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.SPECIFICATION_IMPLEMENTATION;
+import static org.apache.aries.jax.rs.rest.management.RestManagementConstants.SPECIFICATION_VERSION;
+import static org.osgi.namespace.implementation.ImplementationNamespace.IMPLEMENTATION_NAMESPACE;
+import static org.osgi.namespace.service.ServiceNamespace.SERVICE_NAMESPACE;
+
+import org.osgi.annotation.bundle.Capability;
 import org.osgi.annotation.bundle.Export;
 import org.osgi.annotation.versioning.Version;
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServiceReferenceDTOs.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleExceptionSchema.java
similarity index 60%
rename from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServiceReferenceDTOs.java
rename to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleExceptionSchema.java
index 7f553e4..a0e9260 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServiceReferenceDTOs.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleExceptionSchema.java
@@ -15,19 +15,22 @@
  * limitations under the License.
  */
 
-package org.apache.aries.jax.rs.rest.management.model;
+package org.apache.aries.jax.rs.rest.management.schema;
 
-import java.util.List;
+import javax.xml.bind.annotation.XmlRootElement;
 
-import org.osgi.framework.dto.ServiceReferenceDTO;
+@XmlRootElement(name = "bundleexception")
+public class BundleExceptionSchema {
 
-public class ServiceReferenceDTOs {
-    public List<ServiceReferenceDTO> services;
+    public int typecode;
 
-    public static ServiceReferenceDTOs build(List<ServiceReferenceDTO> services) {
-        ServiceReferenceDTOs serviceReferenceDTOs = new ServiceReferenceDTOs();
-        serviceReferenceDTOs.services = services;
-        return serviceReferenceDTOs;
+    public String message;
+
+    public static BundleExceptionSchema build(int typecode, String message) {
+        final BundleExceptionSchema bundleExceptionSchema = new BundleExceptionSchema();
+        bundleExceptionSchema.typecode = typecode;
+        bundleExceptionSchema.message = message;
+        return bundleExceptionSchema;
     }
 
 }
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleHeaderAdapter.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleHeaderAdapter.java
new file mode 100644
index 0000000..67cd005
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleHeaderAdapter.java
@@ -0,0 +1,45 @@
+package org.apache.aries.jax.rs.rest.management.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+public class BundleHeaderAdapter extends XmlAdapter<BundleHeaderAdapter.BundleHeaderAdapted, BundleHeaderSchema> {
+
+    @XmlRootElement(name = "bundleHeader")
+    public static class BundleHeaderAdapted {
+        public List<Header> entry = new ArrayList<>();
+    }
+
+    public static class Header {
+        @XmlAttribute(name = "key", required = true)
+        public String key;
+        @XmlAttribute(name = "value", required = true)
+        public String value;
+    }
+
+    @Override
+    public BundleHeaderAdapted marshal(BundleHeaderSchema bundleHeaderSchema) throws Exception {
+        BundleHeaderAdapted adapter = new BundleHeaderAdapted();
+        bundleHeaderSchema.forEach((k, v) -> adapter.entry.add(build(k, v)));
+        return adapter;
+    }
+
+    @Override
+    public BundleHeaderSchema unmarshal(BundleHeaderAdapted adapter) throws Exception {
+        BundleHeaderSchema map = new BundleHeaderSchema();
+        adapter.entry.forEach(header -> map.put(header.key, header.value));
+        return map;
+    }
+
+    static Header build(String key, String value) {
+        final Header header = new Header();
+        header.key = key;
+        header.value = value;
+        return header;
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServicesDTO.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleHeaderSchema.java
similarity index 60%
copy from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServicesDTO.java
copy to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleHeaderSchema.java
index 1bf866e..f01e249 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServicesDTO.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleHeaderSchema.java
@@ -15,20 +15,25 @@
  * limitations under the License.
  */
 
-package org.apache.aries.jax.rs.rest.management.model;
+package org.apache.aries.jax.rs.rest.management.schema;
 
-import java.util.List;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
-import org.osgi.dto.DTO;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
-public class ServicesDTO extends DTO {
+@SuppressWarnings("serial")
+@XmlRootElement(name = "bundleHeader")
+@XmlJavaTypeAdapter(BundleHeaderAdapter.class)
+public class BundleHeaderSchema extends LinkedHashMap<String, String> {
 
-    public List<String> services;
+    public BundleHeaderSchema() {
+        super();
+    }
 
-    public static ServicesDTO build(List<String> services) {
-        ServicesDTO servicesDTO = new ServicesDTO();
-        servicesDTO.services = services;
-        return servicesDTO;
+    public BundleHeaderSchema(Map<String, String> map) {
+        super(map);
     }
 
 }
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/BundlesDTO.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleListSchema.java
similarity index 59%
copy from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/BundlesDTO.java
copy to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleListSchema.java
index 25961e1..f3a90ff 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/BundlesDTO.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleListSchema.java
@@ -15,19 +15,28 @@
  * limitations under the License.
  */
 
-package org.apache.aries.jax.rs.rest.management.model;
+package org.apache.aries.jax.rs.rest.management.schema;
+
+import static javax.xml.bind.annotation.XmlAccessType.FIELD;
 
 import java.util.List;
 
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
 import org.osgi.dto.DTO;
 
-public class BundlesDTO extends DTO {
+@XmlRootElement(name = "bundles")
+@XmlAccessorType(FIELD)
+public class BundleListSchema extends DTO {
+    @XmlElement(name = "uri")
     public List<String> bundles;
 
-    public static BundlesDTO build(List<String> bundles) {
-        BundlesDTO bundlesDTO = new BundlesDTO();
-        bundlesDTO.bundles = bundles;
-        return bundlesDTO;
+    public static BundleListSchema build(List<String> bundles) {
+        final BundleListSchema bundleListSchema = new BundleListSchema();
+        bundleListSchema.bundles = bundles;
+        return bundleListSchema;
     }
 
 }
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleSchema.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleSchema.java
new file mode 100644
index 0000000..2c26463
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleSchema.java
@@ -0,0 +1,51 @@
+/*
+ * 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.aries.jax.rs.rest.management.schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.osgi.framework.dto.BundleDTO;
+
+@XmlRootElement(name = "bundle")
+public class BundleSchema extends BundleDTO {
+
+    public String location;
+
+    public static BundleSchema build(
+        long id, long lastModified, int state, String symbolicName, String version, String location) {
+        final BundleSchema bundleSchema = new BundleSchema();
+        bundleSchema.id = id;
+        bundleSchema.lastModified = lastModified;
+        bundleSchema.state = state;
+        bundleSchema.symbolicName = symbolicName;
+        bundleSchema.version = version;
+        bundleSchema.location = location;
+        return bundleSchema;
+    }
+
+    public static BundleSchema build(BundleDTO bundleDTO) {
+        final BundleSchema bundleSchema = new BundleSchema();
+        bundleSchema.id = bundleDTO.id;
+        bundleSchema.lastModified = bundleDTO.lastModified;
+        bundleSchema.state = bundleDTO.state;
+        bundleSchema.symbolicName = bundleDTO.symbolicName;
+        bundleSchema.version = bundleDTO.version;
+        return bundleSchema;
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/BundlesDTO.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleSchemaListSchema.java
similarity index 61%
rename from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/BundlesDTO.java
rename to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleSchemaListSchema.java
index 25961e1..ef7141b 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/BundlesDTO.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleSchemaListSchema.java
@@ -15,19 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.aries.jax.rs.rest.management.model;
+package org.apache.aries.jax.rs.rest.management.schema;
 
 import java.util.List;
 
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
 import org.osgi.dto.DTO;
 
-public class BundlesDTO extends DTO {
-    public List<String> bundles;
+@XmlRootElement(name = "bundles")
+public class BundleSchemaListSchema extends DTO {
+    @XmlElement(name = "bundle")
+    public List<BundleSchema> bundles;
 
-    public static BundlesDTO build(List<String> bundles) {
-        BundlesDTO bundlesDTO = new BundlesDTO();
-        bundlesDTO.bundles = bundles;
-        return bundlesDTO;
+    public static BundleSchemaListSchema build(List<BundleSchema> bundles) {
+        final BundleSchemaListSchema bundlesSchema = new BundleSchemaListSchema();
+        bundlesSchema.bundles = bundles;
+        return bundlesSchema;
     }
 
 }
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleStartLevelSchema.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleStartLevelSchema.java
new file mode 100644
index 0000000..84b910e
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleStartLevelSchema.java
@@ -0,0 +1,45 @@
+/*
+ * 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.aries.jax.rs.rest.management.schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.osgi.framework.startlevel.dto.BundleStartLevelDTO;
+
+@XmlRootElement(name = "bundleStartLevel")
+public class BundleStartLevelSchema extends BundleStartLevelDTO {
+
+    public static BundleStartLevelSchema build(boolean activationPolicyUsed, long bundle, boolean persistentlyStarted, int startLevel) {
+        final BundleStartLevelSchema bundleStartLevelSchema = new BundleStartLevelSchema();
+        bundleStartLevelSchema.activationPolicyUsed = activationPolicyUsed;
+        bundleStartLevelSchema.bundle = bundle;
+        bundleStartLevelSchema.persistentlyStarted = persistentlyStarted;
+        bundleStartLevelSchema.startLevel = startLevel;
+        return bundleStartLevelSchema;
+    }
+
+    public static BundleStartLevelSchema build(BundleStartLevelDTO bundleStartLevelDTO) {
+        final BundleStartLevelSchema bundleStartLevelSchema = new BundleStartLevelSchema();
+        bundleStartLevelSchema.activationPolicyUsed = bundleStartLevelDTO.activationPolicyUsed;
+        bundleStartLevelSchema.bundle = bundleStartLevelDTO.bundle;
+        bundleStartLevelSchema.persistentlyStarted = bundleStartLevelDTO.persistentlyStarted;
+        bundleStartLevelSchema.startLevel = bundleStartLevelDTO.startLevel;
+        return bundleStartLevelSchema;
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/BundleStateDTO.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleStateSchema.java
similarity index 66%
rename from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/BundleStateDTO.java
rename to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleStateSchema.java
index 8ec7895..e32df17 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/BundleStateDTO.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/BundleStateSchema.java
@@ -15,14 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.aries.jax.rs.rest.management.model;
+package org.apache.aries.jax.rs.rest.management.schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
 
 import org.osgi.dto.DTO;
 
-public class BundleStateDTO extends DTO {
+@XmlRootElement(name = "bundleState")
+public class BundleStateSchema extends DTO {
 
     public int state;
 
     public int options;
 
+    public static BundleStateSchema build(int state, int options) {
+        final BundleStateSchema bundleState = new BundleStateSchema();
+        bundleState.state = state;
+        bundleState.options = options;
+        return bundleState;
+    }
+
 }
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/FrameworkStartLevelSchema.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/FrameworkStartLevelSchema.java
new file mode 100644
index 0000000..b141d75
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/FrameworkStartLevelSchema.java
@@ -0,0 +1,41 @@
+/*
+ * 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.aries.jax.rs.rest.management.schema;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.osgi.framework.startlevel.dto.FrameworkStartLevelDTO;
+
+@XmlRootElement(name = "frameworkStartLevel")
+public class FrameworkStartLevelSchema extends FrameworkStartLevelDTO {
+
+    public static FrameworkStartLevelSchema build(int initialBundleStartLevel, int startLevel) {
+        final FrameworkStartLevelSchema frameworkStartLevelSchema = new FrameworkStartLevelSchema();
+        frameworkStartLevelSchema.initialBundleStartLevel = initialBundleStartLevel;
+        frameworkStartLevelSchema.startLevel = startLevel;
+        return frameworkStartLevelSchema;
+    }
+
+    public static FrameworkStartLevelSchema build(FrameworkStartLevelDTO frameworkStartLevelDTO) {
+        final FrameworkStartLevelSchema frameworkStartLevelSchema = new FrameworkStartLevelSchema();
+        frameworkStartLevelSchema.initialBundleStartLevel = frameworkStartLevelDTO.initialBundleStartLevel;
+        frameworkStartLevelSchema.startLevel = frameworkStartLevelDTO.startLevel;
+        return frameworkStartLevelSchema;
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/PropertiesAdapter.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/PropertiesAdapter.java
new file mode 100644
index 0000000..08ed1a7
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/PropertiesAdapter.java
@@ -0,0 +1,149 @@
+package org.apache.aries.jax.rs.rest.management.schema;
+
+import static java.util.stream.Collectors.joining;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+import org.apache.aries.jax.rs.rest.management.internal.coerce.Coerce;
+
+public class PropertiesAdapter extends XmlAdapter<PropertiesAdapter.PropertiesAdapted, Map<String, Object>> {
+
+    public static class PropertiesAdapted {
+        public List<Property> property = new ArrayList<>();
+    }
+
+    public static class Property {
+        @XmlAttribute(name = "name", required = true)
+        public String key;
+        @XmlAttribute(name = "type")
+        public String type;
+        @XmlAttribute(name = "value")
+        public String attributeValue;
+        @XmlValue
+        public String elementValue;
+    }
+
+    @Override
+    public PropertiesAdapted marshal(Map<String, Object> map) throws Exception {
+        PropertiesAdapted adapter = new PropertiesAdapted();
+        for(Map.Entry<String, Object> entry : map.entrySet()) {
+            Property property = new Property();
+            property.key = entry.getKey();
+            Object v = entry.getValue();
+
+            boolean array = false;
+            if (Long.class.isInstance(v)) {
+                property.type = "Long";
+            }
+            else if (Long[].class.isInstance(v)) {
+                property.type = "Long";
+                array = true;
+            }
+            else if (Double.class.isInstance(v)) {
+                property.type = "Double";
+            }
+            else if (Double[].class.isInstance(v)) {
+                property.type = "Double";
+                array = true;
+            }
+            else if (Float.class.isInstance(v)) {
+                property.type = "Float";
+            }
+            else if (Float[].class.isInstance(v)) {
+                property.type = "Float";
+                array = true;
+            }
+            else if (Integer.class.isInstance(v)) {
+                property.type = "Integer";
+            }
+            else if (Integer[].class.isInstance(v)) {
+                property.type = "Integer";
+                array = true;
+            }
+            else if (Byte.class.isInstance(v)) {
+                property.type = "Byte";
+            }
+            else if (Byte[].class.isInstance(v)) {
+                property.type = "Byte";
+                array = true;
+            }
+            else if (Character.class.isInstance(v)) {
+                property.type = "Character";
+            }
+            else if (Character[].class.isInstance(v)) {
+                property.type = "Character";
+                array = true;
+            }
+            else if (Boolean.class.isInstance(v)) {
+                property.type = "Boolean";
+            }
+            else if (Boolean[].class.isInstance(v)) {
+                property.type = "Boolean";
+                array = true;
+            }
+            else if (Short.class.isInstance(v)) {
+                property.type = "Short";
+            }
+            else if (Short[].class.isInstance(v)) {
+                property.type = "Short";
+                array = true;
+            }
+            else if (String[].class.isInstance(v)) {
+                array = true;
+            }
+
+            if (!array) {
+                property.attributeValue = String.valueOf(v);
+            }
+            else {
+                property.elementValue = Arrays.stream(
+                    (Object[])v
+                ).map(
+                    String::valueOf
+                ).collect(
+                    joining("\n")
+                );
+            }
+
+            adapter.property.add(property);
+        }
+        return adapter;
+    }
+
+    @Override
+    public Map<String, Object> unmarshal(PropertiesAdapted adapter) throws Exception {
+        Map<String, Object> map = new HashMap<>();
+        for(Property property : adapter.property) {
+            String valueTxt = property.attributeValue;
+            boolean array = false;
+            if (property.elementValue != null) {
+                valueTxt = property.elementValue;
+                array = true;
+            }
+            map.put(
+                property.key,
+                Coerce.from(
+                    Coerce.type(property.type, property.key),
+                    array,
+                    Optional.ofNullable(
+                        valueTxt
+                    ).map(
+                        s -> s.trim().split("\\s*\\n\\s*")
+                    ).map(Arrays::asList).orElseGet(ArrayList::new)
+                )
+            );
+        }
+
+        return map;
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServicesDTO.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceListSchema.java
similarity index 65%
copy from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServicesDTO.java
copy to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceListSchema.java
index 1bf866e..80d0a16 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServicesDTO.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceListSchema.java
@@ -15,20 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.aries.jax.rs.rest.management.model;
+package org.apache.aries.jax.rs.rest.management.schema;
 
 import java.util.List;
 
-import org.osgi.dto.DTO;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
 
-public class ServicesDTO extends DTO {
+import org.osgi.dto.DTO;
 
+@XmlRootElement(name = "services")
+public class ServiceListSchema extends DTO {
+    @XmlElement(name = "uri")
     public List<String> services;
 
-    public static ServicesDTO build(List<String> services) {
-        ServicesDTO servicesDTO = new ServicesDTO();
-        servicesDTO.services = services;
-        return servicesDTO;
+    public static ServiceListSchema build(List<String> services) {
+        ServiceListSchema serviceListSchema = new ServiceListSchema();
+        serviceListSchema.services = services;
+        return serviceListSchema;
     }
 
 }
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceSchema.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceSchema.java
new file mode 100644
index 0000000..fe93b56
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceSchema.java
@@ -0,0 +1,40 @@
+package org.apache.aries.jax.rs.rest.management.schema;
+
+import java.util.Map;
+
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.osgi.framework.dto.ServiceReferenceDTO;
+
+@XmlRootElement(name = "service")
+@XmlJavaTypeAdapter(ServiceSchemaAdapter.class)
+public class ServiceSchema extends ServiceReferenceDTO {
+
+    public String bundle;
+    public String[] usingBundles;
+
+    public static ServiceSchema build(
+        String bundle, long id, Map<String, Object> properties, String[] usingBundles) {
+        final ServiceSchema serviceSchema = new ServiceSchema();
+        serviceSchema.bundle = bundle;
+        serviceSchema.id = id;
+        serviceSchema.properties = properties;
+        serviceSchema.usingBundles = usingBundles;
+        return serviceSchema;
+    }
+
+    public static ServiceSchema build(UriInfo uriInfo, ServiceReferenceDTO serviceReferenceDTO) {
+        final ServiceSchema serviceSchema = new ServiceSchema();
+        serviceSchema.bundle = uriInfo.getBaseUriBuilder().path("framework").path("bundle").path("{id}").build(serviceReferenceDTO.bundle).toASCIIString();
+        serviceSchema.id = serviceReferenceDTO.id;
+        serviceSchema.properties = serviceReferenceDTO.properties;
+        serviceSchema.usingBundles = new String[serviceReferenceDTO.usingBundles.length];
+        for (int i = 0; i < serviceReferenceDTO.usingBundles.length; i++) {
+            serviceSchema.usingBundles[i] = uriInfo.getBaseUriBuilder().path("framework").path("bundle").path("{id}").build(serviceReferenceDTO.usingBundles[i]).toASCIIString();
+        }
+        return serviceSchema;
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceSchemaAdapter.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceSchemaAdapter.java
new file mode 100644
index 0000000..5f39bd9
--- /dev/null
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceSchemaAdapter.java
@@ -0,0 +1,40 @@
+package org.apache.aries.jax.rs.rest.management.schema;
+
+import java.util.Map;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+public class ServiceSchemaAdapter extends XmlAdapter<ServiceSchemaAdapter.ServiceSchemaAdapted, ServiceSchema> {
+
+    @XmlRootElement(name = "service")
+    public static class ServiceSchemaAdapted {
+        public long id;
+        public String bundle;
+        @XmlJavaTypeAdapter(PropertiesAdapter.class)
+        public Map<String, Object> properties;
+        public String[] usingBundles;
+    }
+
+    @Override
+    public ServiceSchemaAdapted marshal(ServiceSchema serviceSchema) throws Exception {
+        ServiceSchemaAdapted adapter = new ServiceSchemaAdapted();
+        adapter.id = serviceSchema.id;
+        adapter.bundle = serviceSchema.bundle;
+        adapter.properties = serviceSchema.properties;
+        adapter.usingBundles = serviceSchema.usingBundles;
+        return adapter;
+    }
+
+    @Override
+    public ServiceSchema unmarshal(ServiceSchemaAdapted adapter) throws Exception {
+        ServiceSchema serviceSchema = new ServiceSchema();
+        serviceSchema.id = adapter.id;
+        serviceSchema.bundle = adapter.bundle;
+        serviceSchema.properties = adapter.properties;
+        serviceSchema.usingBundles = adapter.usingBundles;
+        return serviceSchema;
+    }
+
+}
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServicesDTO.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceSchemaListSchema.java
similarity index 59%
rename from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServicesDTO.java
rename to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceSchemaListSchema.java
index 1bf866e..b617b1f 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/ServicesDTO.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/ServiceSchemaListSchema.java
@@ -15,20 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.aries.jax.rs.rest.management.model;
+package org.apache.aries.jax.rs.rest.management.schema;
 
 import java.util.List;
 
-import org.osgi.dto.DTO;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
 
-public class ServicesDTO extends DTO {
+import org.osgi.dto.DTO;
 
-    public List<String> services;
+@XmlRootElement(name = "services")
+public class ServiceSchemaListSchema extends DTO {
+    @XmlElement(name = "service")
+    public List<ServiceSchema> services;
 
-    public static ServicesDTO build(List<String> services) {
-        ServicesDTO servicesDTO = new ServicesDTO();
-        servicesDTO.services = services;
-        return servicesDTO;
+    public static ServiceSchemaListSchema build(List<ServiceSchema> services) {
+        final ServiceSchemaListSchema serviceSchemaListSchema = new ServiceSchemaListSchema();
+        serviceSchemaListSchema.services = services;
+        return serviceSchemaListSchema;
     }
 
 }
diff --git a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/package-info.java b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/package-info.java
similarity index 94%
rename from integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/package-info.java
rename to integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/package-info.java
index 4b23f73..9360930 100644
--- a/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/model/package-info.java
+++ b/integrations/rest-management/rest-management/src/main/java/org/apache/aries/jax/rs/rest/management/schema/package-info.java
@@ -17,7 +17,7 @@
 
 @Export
 @Version("1.0.0")
-package org.apache.aries.jax.rs.rest.management.model;
+package org.apache.aries.jax.rs.rest.management.schema;
 
 import org.osgi.annotation.bundle.Export;
 import org.osgi.annotation.versioning.Version;
diff --git a/jax-rs.itests/itest.bndrun b/jax-rs.itests/itest.bndrun
index b73a8bc..0050270 100644
--- a/jax-rs.itests/itest.bndrun
+++ b/jax-rs.itests/itest.bndrun
@@ -48,7 +48,7 @@
 	org.apache.aries.spifly.auto.providers=com.sun.*
 
 -runbundles: \
-	assertj-core;version='[3.17.2,3.17.3)',\
+	assertj-core;version='[3.19.0,3.19.1)',\
 	com.fasterxml.woodstox.woodstox-core;version='[6.2.3,6.2.4)',\
 	com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\
 	jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\
diff --git a/pom.xml b/pom.xml
index 303f36e..896bc1c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,6 +49,8 @@
         <openapi.version>2.1.7</openapi.version>
         <shiro.version>1.7.1</shiro.version>
         <slf4j.version>1.7.30</slf4j.version>
+        <junit.jupiter.version>5.6.0</junit.jupiter.version>
+        <junit.platform.version>1.6.0</junit.platform.version>
     </properties>
 
     <scm>
@@ -286,6 +288,33 @@
                 <version>2.2</version>
             </dependency>
             <dependency>
+                <groupId>org.junit.jupiter</groupId>
+                <artifactId>junit-jupiter-api</artifactId>
+                <version>${junit.jupiter.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.junit.jupiter</groupId>
+                <artifactId>junit-jupiter-params</artifactId>
+                <version>${junit.jupiter.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.junit.jupiter</groupId>
... 39 lines suppressed ...