diff --git a/docker-compose.yaml b/docker-compose.yaml
index a94ea7245088ab0597397eefdcaeb17af42416c2..c0aa52b8c7fe179d769a63e9eb9d5926347e702d 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -5,7 +5,7 @@ services:
       context: .
       dockerfile: ./src/main/docker/Dockerfile.jvm
     ports:
-      - "8090:8080"
+      - "10126:8090"
     volumes:
       - ./config:/config
     deploy:
diff --git a/makefile b/makefile
index 7e843ec0db0c2a1d895bafa50c1a6f92d3021c64..0245e87839054c8591cb6216fdf34765e08b245c 100644
--- a/makefile
+++ b/makefile
@@ -1,11 +1,10 @@
 SHELL = /bin/bash
 
 dev-start:;
-	mvn compile quarkus:dev
+	mvn compile -e quarkus:dev
 
 clean:;
 	mvn clean
-	docker compose down
 
 compile-java:;
 	mvn compile package
diff --git a/pom.xml b/pom.xml
index 939f9db928719538cbb7d43b485c81dcb67858b4..af5bc7da7a911f5c903e993519c6db9db7a5c26c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,154 +1,187 @@
 <?xml version="1.0"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
-	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-	<modelVersion>4.0.0</modelVersion>
-	<groupId>org.eclipsefoundation</groupId>
-	<artifactId>eclipsefdn-project-adopters</artifactId>
-	<version>0.0.1</version>
-	<properties>
-		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-		<surefire-plugin.version>2.22.0</surefire-plugin.version>
-		<quarkus.version>1.6.1.Final</quarkus.version>
-		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-		<maven.compiler.source>11</maven.compiler.source>
-		<maven.compiler.target>11</maven.compiler.target>
-		<maven.compiler.parameters>true</maven.compiler.parameters>
-		<compiler-plugin.version>3.8.1</compiler-plugin.version>
-		<sonar.sources>src/main</sonar.sources>
-		<sonar.tests>src/test</sonar.tests>
-		<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
-		<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
-		<sonar.jacoco.reportPaths>${project.build.directory}/jacoco-report</sonar.jacoco.reportPaths>
-		<sonar.junit.reportPath>${project.build.directory}/surefire-reports</sonar.junit.reportPath>
-	</properties>
-	<dependencyManagement>
-		<dependencies>
-			<dependency>
-				<groupId>io.quarkus</groupId>
-				<artifactId>quarkus-bom</artifactId>
-				<version>${quarkus.version}</version>
-				<type>pom</type>
-				<scope>import</scope>
-			</dependency>
-		</dependencies>
-	</dependencyManagement>
-	<dependencies>
-		<dependency>
-			<groupId>io.quarkus</groupId>
-			<artifactId>quarkus-resteasy</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>io.quarkus</groupId>
-			<artifactId>quarkus-resteasy-jsonb</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>io.quarkus</groupId>
-			<artifactId>quarkus-rest-client</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>io.quarkus</groupId>
-			<artifactId>quarkus-cache</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>io.quarkus</groupId>
-			<artifactId>quarkus-smallrye-context-propagation</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>com.google.guava</groupId>
-			<artifactId>guava</artifactId>
-		</dependency>
-		
-		<!-- Testing -->
-		<dependency>
-			<groupId>io.quarkus</groupId>
-			<artifactId>quarkus-junit5</artifactId>
-			<scope>test</scope>
-		</dependency>
-		<dependency>
-			<groupId>io.rest-assured</groupId>
-			<artifactId>rest-assured</artifactId>
-			<scope>test</scope>
-		</dependency>
-	</dependencies>
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>io.quarkus</groupId>
-				<artifactId>quarkus-maven-plugin</artifactId>
-				<version>${quarkus.version}</version>
-				<executions>
-					<execution>
-						<goals>
-							<goal>build</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-			<plugin>
-				<artifactId>maven-surefire-plugin</artifactId>
-				<version>${surefire-plugin.version}</version>
-				<configuration>
-					<argLine>${argLine} -Xmx2048m</argLine>
-					<includes>
-						<include>**/*Test.java</include>
-					</includes>
-				</configuration>
-			</plugin>
-			<plugin>
-				<groupId>org.jacoco</groupId>
-				<artifactId>jacoco-maven-plugin</artifactId>
-				<version>0.8.4</version>
-				<configuration>
-					<skip>${maven.test.skip}</skip>
-					<destFile>${basedir}/target/coverage-reports/jacoco-unit.exec</destFile>
-					<dataFile>${basedir}/target/coverage-reports/jacoco-unit.exec</dataFile>
-					<output>file</output>
-					<append>true</append>
-				</configuration>
-				<executions>
-					<execution>
-						<id>jacoco-initialize</id>
-						<goals>
-							<goal>prepare-agent</goal>
-						</goals>
-					</execution>
-					<execution>
-						<id>report</id>
-						<phase>verify</phase>
-						<goals>
-							<goal>report</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-		</plugins>
-	</build>
-	<profiles>
-		<profile>
-			<id>native</id>
-			<properties>
-				<quarkus.package.type>native</quarkus.package.type>
-			</properties>
-			<activation>
-				<property>
-					<name>native</name>
-				</property>
-			</activation>
-		</profile>
-		<profile>
-			<id>sonar-dev</id>
-			<build>
-				<plugins>
-					<plugin>
-						<groupId>org.sonarsource.scanner.maven</groupId>
-						<artifactId>sonar-maven-plugin</artifactId>
-						<version>3.6.0.1398</version>
-					</plugin>
-				</plugins>
-			</build>
-			<properties>
-				<sonar.host.url>https://sonarqube.dev.docker</sonar.host.url>
-			</properties>
-		</profile>
-	</profiles>
-</project>
+<project
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.eclipsefoundation</groupId>
+  <artifactId>eclipsefdn-project-adopters</artifactId>
+  <version>0.0.1</version>
+
+  <properties>
+    <compiler-plugin.version>3.8.1</compiler-plugin.version>
+    <maven.compiler.source>11</maven.compiler.source>
+    <maven.compiler.target>11</maven.compiler.target>
+    <maven.compiler.parameters>true</maven.compiler.parameters>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+    <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
+    <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
+    <quarkus.platform.version>2.14.2.Final</quarkus.platform.version>
+    <surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
+    <sonar.sources>src/main</sonar.sources>
+    <sonar.tests>src/test</sonar.tests>
+    <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
+    <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
+    <sonar.jacoco.reportPaths>${project.build.directory}/jacoco-report</sonar.jacoco.reportPaths>
+    <sonar.junit.reportPath>${project.build.directory}/surefire-reports</sonar.junit.reportPath>
+    <auto-value.version>1.8.2</auto-value.version>
+    <eclipse-api-version>0.7.1</eclipse-api-version>
+  </properties>
+
+  <repositories>
+    <repository>
+      <id>eclipsefdn</id>
+      <url>https://repo.eclipse.org/content/repositories/eclipsefdn/</url>
+      <releases>
+        <enabled>true</enabled>
+      </releases>
+      <snapshots>
+        <enabled>true</enabled>
+      </snapshots>
+    </repository>
+  </repositories>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>${quarkus.platform.group-id}</groupId>
+        <artifactId>${quarkus.platform.artifact-id}</artifactId>
+        <version>${quarkus.platform.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipsefoundation</groupId>
+      <artifactId>quarkus-core</artifactId>
+      <version>${eclipse-api-version}</version>
+      <!-- Can be removed once dependency is removed from base package
+      https://stackoverflow.com/questions/67510802/logging-in-quarkus-works-in-dev-mode-but-doesnt-output-in-jvm-docker-image -->
+      <exclusions>
+        <exclusion>
+          <groupId>org.jboss.logmanager</groupId>
+          <artifactId>jboss-logmanager</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-resteasy-jackson</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.quarkus</groupId>
+      <artifactId>quarkus-rest-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+
+    <!--
+    Annotation preprocessors - reduce all of the boiler plate -->
+    <dependency>
+      <groupId>com.google.auto.value</groupId>
+      <artifactId>auto-value</artifactId>
+      <version>${auto-value.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.auto.value</groupId>
+      <artifactId>auto-value-annotations</artifactId>
+      <version>${auto-value.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.code.findbugs</groupId>
+      <artifactId>jsr305</artifactId>
+      <version>3.0.0</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>${quarkus.platform.group-id}</groupId>
+        <artifactId>quarkus-maven-plugin</artifactId>
+        <version>${quarkus.platform.version}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>build</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>${surefire-plugin.version}</version>
+        <configuration>
+          <argLine>${argLine}
+            -Xmx2048m</argLine>
+          <includes>
+            <include>**/*Test.java</include>
+          </includes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <version>0.8.4</version>
+        <configuration>
+          <skip>${maven.test.skip}</skip>
+          <destFile>${basedir}/target/coverage-reports/jacoco-unit.exec</destFile>
+          <dataFile>
+            ${basedir}/target/coverage-reports/jacoco-unit.exec</dataFile>
+          <output>file</output>
+          <append>true</append>
+        </configuration>
+        <executions>
+          <execution>
+            <id>jacoco-initialize</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>report</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <profiles>
+    <profile>
+      <id>native</id>
+      <properties>
+        <quarkus.package.type>native</quarkus.package.type>
+      </properties>
+      <activation>
+        <property>
+          <name>native</name>
+        </property>
+      </activation>
+    </profile>
+    <profile>
+      <id>sonar-dev</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.sonarsource.scanner.maven</groupId>
+            <artifactId>sonar-maven-plugin</artifactId>
+            <version>3.6.0.1398</version>
+          </plugin>
+        </plugins>
+      </build>
+      <properties>
+        <sonar.host.url>https://sonarqube.dev.docker</sonar.host.url>
+      </properties>
+    </profile>
+  </profiles>
+</project>
\ No newline at end of file
diff --git a/spec/openapi.yaml b/spec/openapi.yaml
index 240fa7f318bb7f07091bec98609d7d286bc34bd1..c64f8217a13d12981225304d187f8b2aa45a00c9 100644
--- a/spec/openapi.yaml
+++ b/spec/openapi.yaml
@@ -1,12 +1,12 @@
-openapi: '3.1.0'
+openapi: "3.1.0"
 
 info:
   version: 1.0.0
   title: PROJECT ADOPTERS API
   description: Access information on Eclipse Foundation project adopters
   license:
-      name: Eclipse Public License - 2.0
-      url: https://www.eclipse.org/legal/epl-2.0/    
+    name: Eclipse Public License - 2.0
+    url: https://www.eclipse.org/legal/epl-2.0/
 
 servers:
   - url: https://api.eclipse.org/adopters
@@ -32,13 +32,13 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/adopted_projects'
+                $ref: "#/components/schemas/adopted_projects"
         500:
           description: Error while retrieving data.
-    
+
   /projects/{projectId}:
     parameters:
-    -  name: projectId
+      - name: projectId
         in: path
         description: The id of the project to retreive
         required: true
@@ -53,21 +53,21 @@ paths:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/adopted_project'
+                $ref: "#/components/schemas/adopted_project"
         500:
-          description: Error while retrieving data.  
+          description: Error while retrieving data.
 
 components:
   schemas:
     adopted_projects:
       type: array
       items:
-        $ref: '#/components/schemas/adopted_project'
+        $ref: "#/components/schemas/adopted_project"
     adopted_project:
       type: object
       properties:
         adopters:
-            $ref: '#/components/schemas/adopter'
+          $ref: "#/components/schemas/adopter"
         logo:
           type: string
           description: The URL containing the project logo.
@@ -83,7 +83,7 @@ components:
     adopters:
       type: array
       items:
-        $ref: '#/components/schemas/adopter'
+        $ref: "#/components/schemas/adopter"
     adopter:
       type: object
       properties:
@@ -99,4 +99,3 @@ components:
         name:
           type: string
           description: The adopter's company name.
-
diff --git a/src/main/docker/Dockerfile.jvm b/src/main/docker/Dockerfile.jvm
index 796219ff8e584be31303a565f7a4c2a6a61da619..2674345997a9f6d07dbfd01d75222606eec75c58 100644
--- a/src/main/docker/Dockerfile.jvm
+++ b/src/main/docker/Dockerfile.jvm
@@ -14,21 +14,21 @@
 # docker run -i --rm -p 8080:8080 eclipsefdn/eclipsefdn-project-adopters
 #
 ###
-FROM fabric8/java-alpine-openjdk11-jre
-ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
-ENV AB_ENABLED=jmx_exporter
 
-# Be prepared for running in OpenShift too
-RUN adduser -G root --no-create-home --disabled-password 1001 \
-  && chown -R 1001 /deployments \
-  && chmod -R "g+rwX" /deployments \
-  && chown -R 1001:root /deployments
 
-COPY target/lib/* /deployments/lib/
-COPY target/*-runner.jar /deployments/app.jar
-EXPOSE 8080
+FROM registry.access.redhat.com/ubi8/openjdk-11:1.11
+
+ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
 
-# run with user 1001
-USER 1001
 
-ENTRYPOINT [ "/deployments/run-java.sh" ]
\ No newline at end of file
+# We make four distinct layers so if there are application changes the library layers can be re-used
+COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
+COPY --chown=185 target/quarkus-app/*.jar /deployments/
+COPY --chown=185 target/quarkus-app/app/ /deployments/app/
+COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
+
+EXPOSE 8080
+USER 185
+ENV AB_JOLOKIA_OFF=""
+ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
+ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
\ No newline at end of file
diff --git a/src/main/java/org/eclipsefoundation/adopters/api/ProjectsAPI.java b/src/main/java/org/eclipsefoundation/adopters/api/ProjectsAPI.java
index b3574f9486254e8fbafd6e8f05343a557536ed52..40a536076c8b1a02a360bb0afaa6280f6c527848 100644
--- a/src/main/java/org/eclipsefoundation/adopters/api/ProjectsAPI.java
+++ b/src/main/java/org/eclipsefoundation/adopters/api/ProjectsAPI.java
@@ -11,15 +11,14 @@
 **********************************************************************/
 package org.eclipsefoundation.adopters.api;
 
-import java.util.List;
-
+import javax.ws.rs.BeanParam;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
 
 import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
-import org.eclipsefoundation.adopters.model.Project;
+import org.eclipsefoundation.core.service.APIMiddleware.BaseAPIParameters;
 
 /**
  * Interface for interacting with the PMI Projects API. Used to link Git
@@ -35,10 +34,10 @@ public interface ProjectsAPI {
 	/**
 	 * Retrieves all projects with the given repo URL.
 	 * 
-	 * @param repoUrl the target repos URL
+	 * @param params the pagination parameters
 	 * @return a list of Eclipse Foundation projects.
 	 */
 	@GET
 	@Produces("application/json")
-	List<Project> getProject(@QueryParam("page") int page, @QueryParam("pagesize") int pageSize);
+	Response getProjects(@BeanParam BaseAPIParameters params);
 }
diff --git a/src/main/java/org/eclipsefoundation/adopters/config/JsonBConfig.java b/src/main/java/org/eclipsefoundation/adopters/config/JsonBConfig.java
deleted file mode 100644
index 150aa743d688d7f3ca649097aa1ae76f71303561..0000000000000000000000000000000000000000
--- a/src/main/java/org/eclipsefoundation/adopters/config/JsonBConfig.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*********************************************************************
-* Copyright (c) 2019 Eclipse Foundation.
-*
-* This program and the accompanying materials are made
-* available under the terms of the Eclipse Public License 2.0
-* which is available at https://www.eclipse.org/legal/epl-2.0/
-*
-* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
-*
-* SPDX-License-Identifier: EPL-2.0
-**********************************************************************/
-package org.eclipsefoundation.adopters.config;
-
-import javax.json.bind.Jsonb;
-import javax.json.bind.JsonbBuilder;
-import javax.json.bind.JsonbConfig;
-import javax.json.bind.config.PropertyNamingStrategy;
-import javax.ws.rs.ext.ContextResolver;
-import javax.ws.rs.ext.Provider;
-
-/**
- * Updates JSONB config to use a naming convention when interacting with objects
- * that match the API best practices set by internal documentation.
- * 
- * @author Martin Lowe
- */
-@Provider
-public class JsonBConfig implements ContextResolver<Jsonb> {
-
-	@Override
-	public Jsonb getContext(Class<?> type) {
-		JsonbConfig config = new JsonbConfig();
-
-		// following strategy is defined as default by internal API guidelines
-		config.withPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES)
-				.withDateFormat("uuuu-MM-dd'T'HH:mm:ssXXX", null);
-		return JsonbBuilder.create(config);
-	}
-}
diff --git a/src/main/java/org/eclipsefoundation/adopters/model/AdoptedProject.java b/src/main/java/org/eclipsefoundation/adopters/model/AdoptedProject.java
index 91e436d890d89bf4412770e4ee1d1e8d543c6d3a..ddd3f612b4a9cc75f589d5e128c7fd56a3db3115 100644
--- a/src/main/java/org/eclipsefoundation/adopters/model/AdoptedProject.java
+++ b/src/main/java/org/eclipsefoundation/adopters/model/AdoptedProject.java
@@ -1,19 +1,22 @@
 /*********************************************************************
-* Copyright (c) 2020 Eclipse Foundation.
+* Copyright (c) 2020, 2023 Eclipse Foundation.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
+*		Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
 *
 * SPDX-License-Identifier: EPL-2.0
 **********************************************************************/
 package org.eclipsefoundation.adopters.model;
 
-import java.util.ArrayList;
 import java.util.List;
 
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.google.auto.value.AutoValue;
 
 /**
  * A project with information about its adopters (read from the file system)
@@ -22,81 +25,38 @@ import java.util.List;
  * @author Martin Lowe
  *
  */
-public class AdoptedProject {
-
-	private String projectId;
-	private String name;
-	private String url;
-	private String logo;
-	private List<Adopter> adopters;
-
-	/**
-	 * @return the projectId
-	 */
-	public String getProjectId() {
-		return projectId;
-	}
+@AutoValue
+@JsonDeserialize(builder = AutoValue_AdoptedProject.Builder.class)
+public abstract class AdoptedProject {
 
-	/**
-	 * @param projectId the projectId to set
-	 */
-	public void setProjectId(String projectId) {
-		this.projectId = projectId;
-	}
+	public abstract String getProjectId();
 
-	/**
-	 * @return the name
-	 */
-	public String getName() {
-		return name;
-	}
+	public abstract String getName();
 
-	/**
-	 * @param name the name to set
-	 */
-	public void setName(String name) {
-		this.name = name;
-	}
+	public abstract String getUrl();
 
-	/**
-	 * @return the url
-	 */
-	public String getUrl() {
-		return url;
-	}
+	public abstract String getLogo();
 
-	/**
-	 * @param url the url to set
-	 */
-	public void setUrl(String url) {
-		this.url = url;
-	}
+	public abstract List<Adopter> getAdopters();
 
-	/**
-	 * @return the logo
-	 */
-	public String getLogo() {
-		return logo;
+	public static Builder builder() {
+		return new AutoValue_AdoptedProject.Builder();
 	}
 
-	/**
-	 * @param logo the logo to set
-	 */
-	public void setLogo(String logo) {
-		this.logo = logo;
-	}
+	@AutoValue.Builder
+	@JsonPOJOBuilder(withPrefix = "set")
+	public abstract static class Builder {
 
-	/**
-	 * @return the adopters
-	 */
-	public List<Adopter> getAdopters() {
-		return new ArrayList<>(adopters);
-	}
+		public abstract Builder setProjectId(String id);
+
+		public abstract Builder setName(String name);
+
+		public abstract Builder setUrl(String url);
+
+		public abstract Builder setLogo(String logo);
+
+		public abstract Builder setAdopters(List<Adopter> adopters);
 
-	/**
-	 * @param adopters the adopters to set
-	 */
-	public void setAdopters(List<Adopter> adopters) {
-		this.adopters = new ArrayList<>(adopters);
+		public abstract AdoptedProject build();
 	}
 }
diff --git a/src/main/java/org/eclipsefoundation/adopters/model/Adopter.java b/src/main/java/org/eclipsefoundation/adopters/model/Adopter.java
index a6e2889d982e484901d7ef848951cab312d2324a..ff52b7f04c4424fff8f6a62dd00ffbd1f58d6e40 100644
--- a/src/main/java/org/eclipsefoundation/adopters/model/Adopter.java
+++ b/src/main/java/org/eclipsefoundation/adopters/model/Adopter.java
@@ -1,21 +1,23 @@
 /*********************************************************************
-* Copyright (c) 2020 Eclipse Foundation.
+* Copyright (c) 2020, 2023 Eclipse Foundation.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
+*		Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
 *
 * SPDX-License-Identifier: EPL-2.0
 **********************************************************************/
 package org.eclipsefoundation.adopters.model;
 
-import java.util.ArrayList;
 import java.util.List;
 
-import javax.json.bind.annotation.JsonbProperty;
-import javax.json.bind.annotation.JsonbTransient;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.google.auto.value.AutoValue;
 
 /**
  * Represents an adopter from the serialized adopter.json file.
@@ -23,88 +25,42 @@ import javax.json.bind.annotation.JsonbTransient;
  * @author Martin Lowe
  *
  */
-public class Adopter {
-	private String name;
-	@JsonbProperty("homepage_url")
-	private String homepageUrl;
-	private String logo;
-	@JsonbProperty("logo_white")
-	private String logoWhite;
-	private List<String> projects;
-
-	public Adopter() {
-		this.projects = new ArrayList<>();
-	}
+@AutoValue
+@JsonDeserialize(builder = AutoValue_Adopter.Builder.class)
+public abstract class Adopter {
+	public abstract String getName();
 
-	/**
-	 * @return the name
-	 */
-	public String getName() {
-		return name;
-	}
+	@JsonProperty("homepage_url")
+	public abstract String getHomepageUrl();
 
-	/**
-	 * @param name the name to set
-	 */
-	public void setName(String name) {
-		this.name = name;
-	}
+	public abstract String getLogo();
 
-	/**
-	 * @return the homepageUrl
-	 */
-	public String getHomepageUrl() {
-		return homepageUrl;
-	}
+	@JsonProperty("logo_white")
+	public abstract String getLogoWhite();
 
-	/**
-	 * @param homepageUrl the homepageUrl to set
-	 */
-	public void setHomepageUrl(String homepageUrl) {
-		this.homepageUrl = homepageUrl;
-	}
+	public abstract List<String> getProjects();
 
-	/**
-	 * @return the logo
-	 */
-	public String getLogo() {
-		return logo;
+	public static Builder builder() {
+		return new AutoValue_Adopter.Builder();
 	}
 
-	/**
-	 * @param logo the logo to set
-	 */
-	public void setLogo(String logo) {
-		this.logo = logo;
-	}
+	@AutoValue.Builder
+	@JsonPOJOBuilder(withPrefix = "set")
+	public abstract static class Builder {
 
-	/**
-	 * @return the logoWhite
-	 */
-	public String getLogoWhite() {
-		return logoWhite;
-	}
+		public abstract Builder setName(String name);
 
-	/**
-	 * @param logoWhite the logoWhite to set
-	 */
-	public void setLogoWhite(String logoWhite) {
-		this.logoWhite = logoWhite;
-	}
+		@JsonProperty("homepage_url")
+		public abstract Builder setHomepageUrl(String url);
 
-	/**
-	 * @return the projects
-	 */
-	@JsonbTransient
-	public List<String> getProjects() {
-		return new ArrayList<>(projects);
-	}
+		public abstract Builder setLogo(String logo);
 
-	/**
-	 * @param projects the projects to set
-	 */
-	public void setProjects(List<String> projects) {
-		this.projects = new ArrayList<>(projects);
-	}
+		@JsonProperty("logo_white")
+		public abstract Builder setLogoWhite(String logoWhite);
 
+		public abstract Builder setProjects(List<String> projects);
+
+		public abstract Adopter build();
+
+	}
 }
diff --git a/src/main/java/org/eclipsefoundation/adopters/model/AdopterList.java b/src/main/java/org/eclipsefoundation/adopters/model/AdopterList.java
index c2c3a8a4bb07e24d66ae7704f1b6802f80c2e101..b5658b93fa7fdc4723c242169143edcb878a4d5a 100644
--- a/src/main/java/org/eclipsefoundation/adopters/model/AdopterList.java
+++ b/src/main/java/org/eclipsefoundation/adopters/model/AdopterList.java
@@ -1,40 +1,44 @@
 /*********************************************************************
-* Copyright (c) 2020 Eclipse Foundation.
+* Copyright (c) 2020, 2023 Eclipse Foundation.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
+*		Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
 *
 * SPDX-License-Identifier: EPL-2.0
 **********************************************************************/
 package org.eclipsefoundation.adopters.model;
 
-import java.util.ArrayList;
 import java.util.List;
 
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.google.auto.value.AutoValue;
+
 /**
  * Root object for adopters.json serialized content.
  * 
  * @author Martin Lowe
  *
  */
-public class AdopterList {
-	private List<Adopter> adopters = new ArrayList<>();
+@AutoValue
+@JsonDeserialize(builder = AutoValue_AdopterList.Builder.class)
+public abstract class AdopterList {
 
-	/**
-	 * @return the adopters
-	 */
-	public List<Adopter> getAdopters() {
-		return new ArrayList<>(adopters);
-	}
+	public abstract List<Adopter> getAdopters();
 
-	/**
-	 * @param adopters the adopters to set
-	 */
-	public void setAdopters(List<Adopter> adopters) {
-		this.adopters = new ArrayList<>(adopters);
+	public static Builder builder() {
+		return new AutoValue_AdopterList.Builder();
 	}
 
+	@AutoValue.Builder
+	@JsonPOJOBuilder(withPrefix = "set")
+	public abstract static class Builder {
+		public abstract Builder setAdopters(List<Adopter> adopters);
+
+		public abstract AdopterList build();
+	}
 }
diff --git a/src/main/java/org/eclipsefoundation/adopters/model/Project.java b/src/main/java/org/eclipsefoundation/adopters/model/Project.java
index a432a3a6d545844f9a1ad13dbf6ac5394f8024da..08c0fd94e5bd9eb9ce11dcc94f6018b8b6a2c513 100644
--- a/src/main/java/org/eclipsefoundation/adopters/model/Project.java
+++ b/src/main/java/org/eclipsefoundation/adopters/model/Project.java
@@ -1,19 +1,22 @@
 /*********************************************************************
-* Copyright (c) 2020 Eclipse Foundation.
+* Copyright (c) 2020, 2023 Eclipse Foundation.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
+*		Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
 *
 * SPDX-License-Identifier: EPL-2.0
 **********************************************************************/
 package org.eclipsefoundation.adopters.model;
 
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.google.auto.value.AutoValue;
 
 /**
  * Represents a project from the Eclipse API.
@@ -21,133 +24,37 @@ import java.util.Objects;
  * @author Martin Lowe
  *
  */
-public class Project {
-	private String projectId;
-	private String name;
-	private String url;
-	private String logo;
-	private List<WorkingGroup> workingGroups = new ArrayList<>();
-
-	/**
-	 * @return the projectId
-	 */
-	public String getProjectId() {
-		return projectId;
-	}
-
-	/**
-	 * @param projectId the projectId to set
-	 */
-	public void setProjectId(String projectId) {
-		this.projectId = projectId;
-	}
-
-	/**
-	 * @return the name
-	 */
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * @param name the name to set
-	 */
-	public void setName(String name) {
-		this.name = name;
-	}
+@AutoValue
+@JsonDeserialize(builder = AutoValue_Project.Builder.class)
+public abstract class Project {
 
-	/**
-	 * @return the url
-	 */
-	public String getUrl() {
-		return url;
-	}
+	public abstract String getProjectId();
 
-	/**
-	 * @param url the url to set
-	 */
-	public void setUrl(String url) {
-		this.url = url;
-	}
+	public abstract String getName();
 
-	/**
-	 * @return the logo
-	 */
-	public String getLogo() {
-		return logo;
-	}
+	public abstract String getUrl();
 
-	/**
-	 * @param logo the logo to set
-	 */
-	public void setLogo(String logo) {
-		this.logo = logo;
-	}
+	public abstract String getLogo();
 
-	/**
-	 * @return the workingGroups
-	 */
-	public List<WorkingGroup> getWorkingGroups() {
-		return new ArrayList<>(workingGroups);
-	}
-
-	/**
-	 * @param workingGroups the workingGroups to set
-	 */
-	public void setWorkingGroups(List<WorkingGroup> workingGroups) {
-		this.workingGroups = new ArrayList<>(workingGroups);
-	}
-
-	@Override
-	public int hashCode() {
-		return Objects.hash(logo, name, projectId, url, workingGroups);
-	}
+	public abstract List<WorkingGroup> getWorkingGroups();
 
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		Project other = (Project) obj;
-		return Objects.equals(logo, other.logo) && Objects.equals(name, other.name)
-				&& Objects.equals(projectId, other.projectId) && Objects.equals(url, other.url)
-				&& Objects.equals(workingGroups, other.workingGroups);
+	public static Builder builder() {
+		return new AutoValue_Project.Builder();
 	}
 
-	public static class WorkingGroup {
-		private String name;
-		private String id;
+	@AutoValue.Builder
+	@JsonPOJOBuilder(withPrefix = "set")
+	public abstract static class Builder {
+		public abstract Builder setProjectId(String id);
 
-		/**
-		 * @return the name
-		 */
-		public String getName() {
-			return name;
-		}
+		public abstract Builder setName(String name);
 
-		/**
-		 * @param name the name to set
-		 */
-		public void setName(String name) {
-			this.name = name;
-		}
+		public abstract Builder setUrl(String url);
 
-		/**
-		 * @return the id
-		 */
-		public String getId() {
-			return id;
-		}
+		public abstract Builder setLogo(String logo);
 
-		/**
-		 * @param id the id to set
-		 */
-		public void setId(String id) {
-			this.id = id;
-		}
+		public abstract Builder setWorkingGroups(List<WorkingGroup> workingGroups);
 
+		public abstract Project build();
 	}
 }
diff --git a/src/main/java/org/eclipsefoundation/adopters/model/WorkingGroup.java b/src/main/java/org/eclipsefoundation/adopters/model/WorkingGroup.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a53c2eb1815f1766b77bd44c30d20f36689b96d
--- /dev/null
+++ b/src/main/java/org/eclipsefoundation/adopters/model/WorkingGroup.java
@@ -0,0 +1,40 @@
+/*********************************************************************
+* Copyright (c) 2023 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* Author: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.adopters.model;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+@JsonDeserialize(builder = AutoValue_WorkingGroup.Builder.class)
+public abstract class WorkingGroup {
+
+    public abstract String getName();
+
+    public abstract String getId();
+
+    public static Builder builder() {
+        return new AutoValue_WorkingGroup.Builder();
+    }
+
+    @AutoValue.Builder
+    @JsonPOJOBuilder(withPrefix = "set")
+    public abstract static class Builder {
+
+        public abstract Builder setName(String name);
+
+        public abstract Builder setId(String id);
+
+        public abstract WorkingGroup build();
+    }
+}
diff --git a/src/main/java/org/eclipsefoundation/adopters/resource/mappers/RuntimeMapper.java b/src/main/java/org/eclipsefoundation/adopters/resource/mappers/RuntimeMapper.java
deleted file mode 100644
index 0f7cadc65343ebc77939389f3b798c259ea5e0c6..0000000000000000000000000000000000000000
--- a/src/main/java/org/eclipsefoundation/adopters/resource/mappers/RuntimeMapper.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*********************************************************************
-* Copyright (c) 2019 Eclipse Foundation.
-*
-* This program and the accompanying materials are made
-* available under the terms of the Eclipse Public License 2.0
-* which is available at https://www.eclipse.org/legal/epl-2.0/
-*
-* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
-*
-* SPDX-License-Identifier: EPL-2.0
-**********************************************************************/
-package org.eclipsefoundation.adopters.resource.mappers;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Catch-all exception mapper to ensure that any error thrown by the service
- * will log the error and quit out safely while limiting the response to a
- * simple error.
- * 
- * @author Martin Lowe
- *
- */
-@Provider
-public class RuntimeMapper implements ExceptionMapper<RuntimeException> {
-	private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeMapper.class);
-
-	@Override
-	public Response toResponse(RuntimeException exception) {
-		LOGGER.error(exception.getMessage(), exception);
-		// return an empty response with a server error response
-		return Response.status(Status.INTERNAL_SERVER_ERROR).build();
-	}
-
-}
diff --git a/src/main/java/org/eclipsefoundation/adopters/response/PaginatedResultsFilter.java b/src/main/java/org/eclipsefoundation/adopters/response/PaginatedResultsFilter.java
deleted file mode 100644
index 5babf7c0002cf3abb49d0fc62530dfbffc2cf9e5..0000000000000000000000000000000000000000
--- a/src/main/java/org/eclipsefoundation/adopters/response/PaginatedResultsFilter.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*********************************************************************
-* Copyright (c) 2020 Eclipse Foundation.
-*
-* This program and the accompanying materials are made
-* available under the terms of the Eclipse Public License 2.0
-* which is available at https://www.eclipse.org/legal/epl-2.0/
-*
-* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
-*
-* SPDX-License-Identifier: EPL-2.0
-**********************************************************************/
-package org.eclipsefoundation.adopters.response;
-
-import java.io.IOException;
-import java.util.List;
-
-import javax.enterprise.inject.Instance;
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerResponseContext;
-import javax.ws.rs.container.ContainerResponseFilter;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.ws.rs.ext.Provider;
-
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.jboss.resteasy.core.ResteasyContext;
-import org.jboss.resteasy.spi.LinkHeader;
-
-
-/**
- * Adds pagination and Link headers to the response by slicing the response
- * entity if its a list entity. This will not dig into complex entities to avoid
- * false positives.
- * 
- * @author Martin Lowe
- *
- */
-@Provider
-public class PaginatedResultsFilter implements ContainerResponseFilter {
-	@ConfigProperty(name= "eclipse.pagination.page-size.default", defaultValue = "10")
-	Instance<Integer> defaultPageSize;
-
-	// Force scheme of header links to be a given value, useful for proxied requests
-	@ConfigProperty(name= "eclipse.pagination.scheme.enforce", defaultValue = "true")
-	Instance<Boolean> enforceLinkScheme;
-	@ConfigProperty(name= "eclipse.pagination.scheme.value", defaultValue = "https")
-	Instance<String> linkScheme;
-
-	@Override
-	public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
-			throws IOException {
-		int pageSize = defaultPageSize.get();
-		Object entity = responseContext.getEntity();
-		// only try and paginate if there are multiple entities
-		if (entity instanceof List) {
-			List<?> listEntity = (List<?>) entity;
-			int page = getRequestedPage(listEntity);
-			int lastPage = (int) Math.ceil((double) listEntity.size() / pageSize);
-			// set the sliced array as the entity
-			responseContext.setEntity(
-					listEntity.subList(getArrayLimitedNumber(listEntity, Math.max(0, page - 1) * pageSize),
-							getArrayLimitedNumber(listEntity, pageSize * page)));
-
-			// add link headers for paginated page hints
-			UriBuilder builder = getUriInfo().getRequestUriBuilder();
-			LinkHeader lh = new LinkHeader();
-			// add first + last page link headers
-			lh.addLink("this page of results", "self", buildHref(builder, page), "");
-			lh.addLink("first page of results", "first", buildHref(builder, 1), "");
-			lh.addLink("last page of results", "last", buildHref(builder, lastPage), "");
-			// add next/prev if needed
-			if (page > 1) {
-				lh.addLink("previous page of results", "prev", buildHref(builder, page - 1), "");
-			}
-			if (page < lastPage) {
-				lh.addLink("next page of results", "next", buildHref(builder, page + 1), "");
-			}
-			// set the link header to the response
-			responseContext.getHeaders().add("Link", lh);
-		}
-
-	}
-
-	/**
-	 * Gets the current requested page, rounding down to max if larger than the max
-	 * page number, and up if below 1.
-	 * 
-	 * @param listEntity list entity used to determine the number of pages present
-	 *                   for current call.
-	 * @return the current page number if set, the last page if greater, or 1 if not
-	 *         set or negative.
-	 */
-	private int getRequestedPage(List<?> listEntity) {
-		MultivaluedMap<String, String> params = getUriInfo().getQueryParameters();
-		if (params.containsKey("page")) {
-			try {
-				int page = Integer.parseInt(params.getFirst("page"));
-				// use double cast int to allow ceil call to round up for pages
-				int maxPage = (int) Math.ceil((double) listEntity.size() / defaultPageSize.get());
-				// get page, with min of 1 and max of last page
-				return Math.min(Math.max(1, page), maxPage);
-			} catch (NumberFormatException e) {
-				// page isn't a number, just return
-				return 1;
-			}
-		}
-		return 1;
-	}
-
-	/**
-	 * Builds an href for a paginated link using the BaseUri UriBuilder from the
-	 * UriInfo object, replacing just the page query parameter.
-	 * 
-	 * @param builder base URI builder from the UriInfo object.
-	 * @param page    the page to link to in the returned link
-	 * @return fully qualified HREF for the paginated results
-	 */
-	private String buildHref(UriBuilder builder, int page) {
-		if (enforceLinkScheme.get()) {
-			return builder.scheme(linkScheme.get()).replaceQueryParam("page", page).build().toString();
-			
-		}
-		return builder.replaceQueryParam("page", page).build().toString();
-	}
-
-	/**
-	 * Gets an int bound by the size of a list.
-	 * 
-	 * @param list the list to bind the number by
-	 * @param num  the number to check for exceeding bounds.
-	 * @return the passed number if its within the size of the given array, 0 if the
-	 *         number is negative, and the array size if greater than the maximum
-	 *         bounds.
-	 */
-	private int getArrayLimitedNumber(List<?> list, int num) {
-		if (num < 0) {
-			return 0;
-		} else if (num > list.size()) {
-			return list.size();
-		}
-		return num;
-	}
-
-	private UriInfo getUriInfo() {
-		return ResteasyContext.getContextData(UriInfo.class);
-	}
-}
diff --git a/src/main/java/org/eclipsefoundation/adopters/service/impl/DefaultAdopterService.java b/src/main/java/org/eclipsefoundation/adopters/service/impl/DefaultAdopterService.java
index 6941a7b7c8a21316d23f0d22f5ca4a02d88492fe..3c25744544f69c1e3ad79e986d402befcb4876f4 100644
--- a/src/main/java/org/eclipsefoundation/adopters/service/impl/DefaultAdopterService.java
+++ b/src/main/java/org/eclipsefoundation/adopters/service/impl/DefaultAdopterService.java
@@ -35,7 +35,6 @@ import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
-import javax.json.bind.Jsonb;
 
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.eclipsefoundation.adopters.model.AdoptedProject;
@@ -46,6 +45,8 @@ import org.eclipsefoundation.adopters.service.AdopterService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 import io.quarkus.runtime.Startup;
 
 /**
@@ -68,7 +69,7 @@ public class DefaultAdopterService implements AdopterService {
 	long retryTimeout;
 
 	@Inject
-	Jsonb json;
+	ObjectMapper objectMapper;
 
 	/**
 	 * All updates to the adopters list should be done through the setAdopters
@@ -89,7 +90,8 @@ public class DefaultAdopterService implements AdopterService {
 		// read in the initial file if it exists
 		if (Files.exists(adoptersLocation)) {
 			LOGGER.debug("Found an adopters file at path {}, reading in", adoptersLocation);
-			List<Adopter> initialAdopters = readInAdopters(adoptersLocation, json);
+			List<Adopter> initialAdopters = readInAdopters(adoptersLocation, objectMapper);
+
 			if (initialAdopters != null) {
 				setAdopters(initialAdopters);
 			}
@@ -159,7 +161,7 @@ public class DefaultAdopterService implements AdopterService {
 		} else {
 			// indicates an update or created file on the given
 			// retrieve the new adopters and set them if the read operation was successful
-			List<Adopter> newAdopters = readInAdopters(adoptersLocation, json);
+			List<Adopter> newAdopters = readInAdopters(adoptersLocation, objectMapper);
 			if (newAdopters != null) {
 				setAdopters(newAdopters);
 			}
@@ -167,12 +169,12 @@ public class DefaultAdopterService implements AdopterService {
 
 	}
 
-	private static List<Adopter> readInAdopters(Path adoptersPath, Jsonb json) {
+	private static List<Adopter> readInAdopters(Path adoptersPath, ObjectMapper mapper) {
 		LOGGER.debug("Detected an update for adopters file, reading in {}", adoptersPath);
 		// get a json processor, and read in the file
 		if (Files.exists(adoptersPath)) {
 			try (InputStream is = new BufferedInputStream(Files.newInputStream(adoptersPath))) {
-				AdopterList al = json.fromJson(is, AdopterList.class);
+				AdopterList al = mapper.readValue(is, AdopterList.class);
 				return al.getAdopters();
 			} catch (IOException e) {
 				LOGGER.warn("Error reading file at path: {}\n", adoptersPath, e);
@@ -204,14 +206,14 @@ public class DefaultAdopterService implements AdopterService {
 	}
 
 	private AdoptedProject getAdoptedProject(Project p) {
-		AdoptedProject ap = new AdoptedProject();
-		ap.setProjectId(p.getProjectId());
-		ap.setName(p.getName());
-		ap.setLogo(p.getLogo());
-        ap.setUrl(p.getUrl());
-        ap.setAdopters(getAdopters().stream().filter(a -> a.getProjects().contains(p.getProjectId()))
-                .sorted(Comparator.comparing(a -> a.getName().toLowerCase())).collect(Collectors.toList()));
-		return ap;
+		return AdoptedProject.builder()
+				.setProjectId(p.getProjectId())
+				.setName(p.getName())
+				.setLogo(p.getLogo())
+				.setUrl(p.getUrl())
+				.setAdopters(getAdopters().stream().filter(a -> a.getProjects().contains(p.getProjectId()))
+						.sorted(Comparator.comparing(a -> a.getName().toLowerCase())).collect(Collectors.toList()))
+				.build();
 	}
 
 }
diff --git a/src/main/java/org/eclipsefoundation/adopters/service/impl/PaginationProjectsService.java b/src/main/java/org/eclipsefoundation/adopters/service/impl/PaginationProjectsService.java
index 9bd41a0f21ccd80fe9c30b1f4fcab0a699ab207e..5702946f16e3040ea32c845076147f56a30a1be6 100644
--- a/src/main/java/org/eclipsefoundation/adopters/service/impl/PaginationProjectsService.java
+++ b/src/main/java/org/eclipsefoundation/adopters/service/impl/PaginationProjectsService.java
@@ -11,7 +11,6 @@
 **********************************************************************/
 package org.eclipsefoundation.adopters.service.impl;
 
-import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -25,6 +24,7 @@ import org.eclipse.microprofile.rest.client.inject.RestClient;
 import org.eclipsefoundation.adopters.api.ProjectsAPI;
 import org.eclipsefoundation.adopters.model.Project;
 import org.eclipsefoundation.adopters.service.ProjectService;
+import org.eclipsefoundation.core.service.APIMiddleware;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,6 +53,9 @@ public class PaginationProjectsService implements ProjectService {
 	@Inject
 	@RestClient
 	ProjectsAPI projects;
+	@Inject
+	APIMiddleware middleware;
+
 	// this class has a separate cache as this data is long to load and should be
 	// always available.
 	LoadingCache<String, List<Project>> internalCache;
@@ -116,23 +119,12 @@ public class PaginationProjectsService implements ProjectService {
 	}
 
 	/**
-	 * Logic for retrieving projects from API. Will loop until there are no more
-	 * projects to be found
+	 * Logic for retrieving projects from API.
 	 * 
-	 * @return list of projects for the
+	 * @return list of projects 
 	 */
 	private List<Project> getProjectsInternal() {
-		int page = 0;
-		int pageSize = 100;
-		List<Project> out = new LinkedList<>();
-		List<Project> in;
-		do {
-			page++;
-			in = projects.getProject(page, pageSize);
-			out.addAll(in);
-		} while (in != null && !in.isEmpty());
-		return out;
-
+		return middleware.getAll(p -> projects.getProjects(p), Project.class);
 	}
 
 }
diff --git a/src/main/k8s/production.yml b/src/main/k8s/production.yml
index b6a0406ee089f4a30cd18083035277e77fee2846..96e16f52bafab950232800c064af0d88733800c4 100644
--- a/src/main/k8s/production.yml
+++ b/src/main/k8s/production.yml
@@ -33,7 +33,7 @@ spec:
         image: eclipsefdn/eclipsefdn-project-adopters:latest
         imagePullPolicy: Always
         ports:
-        - containerPort: 8080
+        - containerPort: 8090
         resources:
           limits:
             cpu: '1'
@@ -63,7 +63,7 @@ spec:
   - name: "http"
     port: 80
     protocol: "TCP"
-    targetPort: 8080
+    targetPort: 8090
   selector:
     app: eclipsefdn-project-adopters
     environment: production
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 00a78f1d7f1a14da329effa78a43ab2b7169d513..1e85c0ab6e458ac6334eafcf5fe4ff79e743c17b 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,14 +1,15 @@
 org.eclipsefoundation.adopters.api.ProjectsAPI/mp-rest/url=https://projects.eclipse.org
 
 ## OAUTH CONFIG
-quarkus.http.port=8080
 quarkus.http.root-path=/adopters
 
 ## CORS settings
 quarkus.http.cors=false
 
+quarkus.log.level=INFO
+quarkus.oidc.enabled=false
+
 ## Adopters raw location
 eclipse.adopters.path.json=/config/adopters.json
 %dev.eclipse.adopters.path.json=/tmp/config/adopters.json
 %dev.eclipse.pagination.scheme.enforce=false
-%dev.quarkus.http.port=8090
\ No newline at end of file