Merge pull request #103 from apache/constructors

Replace field injection with constructors
diff --git a/scim-server-examples/scim-server-jersey/pom.xml b/scim-server-examples/scim-server-jersey/pom.xml
index c8b05ff..f7ff32d 100644
--- a/scim-server-examples/scim-server-jersey/pom.xml
+++ b/scim-server-examples/scim-server-jersey/pom.xml
@@ -28,7 +28,7 @@
   <name>SCIM - Server - Examples - Jersey</name>
 
   <properties>
-    <jersey.version>3.0.6</jersey.version>
+    <jersey.version>3.0.5</jersey.version>
   </properties>
 
   <dependencyManagement>
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/provider/ProviderRegistry.java b/scim-server/src/main/java/org/apache/directory/scim/server/provider/ProviderRegistry.java
index 2c674ff..14b0339 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/provider/ProviderRegistry.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/provider/ProviderRegistry.java
@@ -84,26 +84,25 @@
   private static final String BYTE_ARRAY_TYPE_IDENTIFIER = "class [B";
   private static final String RESOURCE_REFERENCE_TYPE_IDENTIFIER = "class org.apache.directory.scim.spec.schema.ResourceReference$ReferenceType";
 
-  @Inject
-  Registry registry;
+  private Registry registry;
 
-  @Inject
-  ScimExtensionRegistry scimExtensionRegistry;
+  private ScimExtensionRegistry scimExtensionRegistry;
 
   // Weld needs the '? extends' or the providers will not be found, some CDI
   // implementations work fine with just <ScimResources>
-  @Inject
-  Instance<Provider<? extends ScimResource>> scimProviderInstances;
+  private Instance<Provider<? extends ScimResource>> scimProviderInstances;
 
   private Map<Class<? extends ScimResource>, Provider<? extends ScimResource>> providerMap = new HashMap<>();
-  
-  public ProviderRegistry() {}
-  
-  public ProviderRegistry(Registry registry, ScimExtensionRegistry scimExtensionRegistry) {
+
+  @Inject
+  public ProviderRegistry(Registry registry, ScimExtensionRegistry scimExtensionRegistry, Instance<Provider<? extends ScimResource>> scimProviderInstances) {
     this.registry = registry;
     this.scimExtensionRegistry = scimExtensionRegistry;
+    this.scimProviderInstances = scimProviderInstances;
   }
 
+  ProviderRegistry() {}
+
   @Override
   @SuppressWarnings("unchecked")
   public void configure() {
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/provider/UpdateRequest.java b/scim-server/src/main/java/org/apache/directory/scim/server/provider/UpdateRequest.java
index fc58542..8dae3dc 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/provider/UpdateRequest.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/provider/UpdateRequest.java
@@ -54,8 +54,6 @@
 import org.apache.directory.scim.spec.schema.Schema;
 import org.apache.directory.scim.spec.schema.Schema.Attribute;
 
-import jakarta.inject.Inject;
-import jakarta.inject.Named;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -69,7 +67,6 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 
-@Named
 @Slf4j
 @EqualsAndHashCode
 @ToString
@@ -94,8 +91,7 @@
   private Registry registry;
 
   private Map<Attribute, Integer> addRemoveOffsetMap = new HashMap<>();
-  
-  @Inject
+
   public UpdateRequest(Registry registry) {
     this.registry = registry;
 
@@ -104,21 +100,21 @@
     objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
   }
 
-  public void initWithResource(String id, T original, T resource) {
+  public UpdateRequest(String id, T original, T resource, Registry registry) {
+    this(registry);
     this.id = id;
-    schema = registry.getSchema(original.getBaseUrn());
-
     this.original = original;
     this.resource = resource;
-
+    this.schema = registry.getSchema(original.getBaseUrn());
     initialized = true;
   }
 
-  public void initWithPatch(String id, T original, List<PatchOperation> patchOperations) {
+  public UpdateRequest(String id, T original, List<PatchOperation> patchOperations, Registry registry) {
+    this(registry);
     this.id = id;
     this.original = original;
     this.patchOperations = patchOperations;
-    schema = registry.getSchema(original.getBaseUrn());
+    this.schema = registry.getSchema(original.getBaseUrn());
 
     initialized = true;
   }
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImpl.java
index c086170..0e5d7aa 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImpl.java
@@ -29,19 +29,15 @@
 import java.util.Optional;
 import java.util.Set;
 
-import jakarta.enterprise.inject.Instance;
 import jakarta.enterprise.inject.spi.CDI;
-import jakarta.inject.Inject;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.EntityTag;
-import jakarta.ws.rs.core.Request;
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.Response.ResponseBuilder;
 import jakarta.ws.rs.core.Response.Status;
 import jakarta.ws.rs.core.Response.Status.Family;
-import jakarta.ws.rs.core.UriInfo;
 
 import org.apache.directory.scim.server.provider.ProviderRegistry;
+import org.apache.directory.scim.server.schema.Registry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,7 +57,6 @@
 import org.apache.directory.scim.server.provider.extensions.ScimRequestContext;
 import org.apache.directory.scim.server.provider.extensions.exceptions.ClientFilterException;
 import org.apache.directory.scim.server.utility.AttributeUtil;
-import org.apache.directory.scim.server.utility.EndpointUtil;
 import org.apache.directory.scim.server.utility.EtagGenerator;
 import org.apache.directory.scim.spec.adapter.FilterWrapper;
 import org.apache.directory.scim.spec.protocol.BaseResourceTypeResource;
@@ -85,30 +80,24 @@
 
   private static final Logger LOG = LoggerFactory.getLogger(BaseResourceTypeResourceImpl.class);
 
-  @Context
-  UriInfo uriInfo;
+  private final Registry registry;
 
-  @Context
-  Request request;
+  private final ProviderRegistry providerRegistry;
 
-  @Inject
-  ProviderRegistry providerRegistry;
+  private final  AttributeUtil attributeUtil;
 
-  @Inject
-  private AttributeUtil attributeUtil;
+  RequestContext requestContext;
 
-  @Inject
-  private EndpointUtil endpointUtil;
-
-  @Inject
-  private EtagGenerator etagGenerator;
-
-  @Inject
-  private Instance<UpdateRequest<T>> updateRequestInstance;
+  private final  EtagGenerator etagGenerator;
 
   private final Class<T> resourceClass;
 
-  protected BaseResourceTypeResourceImpl(Class<T> resourceClass) {
+  public BaseResourceTypeResourceImpl(Registry registry, ProviderRegistry providerRegistry, AttributeUtil attributeUtil, RequestContext requestContext, EtagGenerator etagGenerator, Class<T> resourceClass) {
+    this.registry = registry;
+    this.providerRegistry = providerRegistry;
+    this.attributeUtil = attributeUtil;
+    this.requestContext = requestContext;
+    this.etagGenerator = etagGenerator;
     this.resourceClass = resourceClass;
   }
 
@@ -126,7 +115,7 @@
 
   @Override
   public Response getById(String id, AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) {
-    if (uriInfo.getQueryParameters().getFirst("filter") != null) {
+    if (requestContext.getUriInfo().getQueryParameters().getFirst("filter") != null) {
       return Response.status(Status.FORBIDDEN)
                      .build();
     }
@@ -134,7 +123,6 @@
     try {
       Provider<T> provider = getProviderInternal();
 
-      endpointUtil.process(uriInfo);
       T resource = null;
       try {
         resource = provider.get(id);
@@ -158,7 +146,7 @@
           return createETagErrorResponse();
         }
 
-        ResponseBuilder evaluatePreconditionsResponse = request.evaluatePreconditions(backingETag);
+        ResponseBuilder evaluatePreconditionsResponse = requestContext.getRequest().evaluatePreconditions(backingETag);
 
         if (evaluatePreconditionsResponse != null) {
           return Response.status(Status.NOT_MODIFIED)
@@ -262,7 +250,6 @@
         return createAmbiguousAttributeParametersResponse();
       }
 
-      endpointUtil.process(uriInfo);
       T created;
       try {
         created = provider.create(resource);
@@ -363,7 +350,6 @@
 
       ListResponse<T> listResponse = new ListResponse<>();
 
-      endpointUtil.process(uriInfo);
       FilterResponse<T> filterResp = null;
       try {
         filterResp = provider.find(filter, pageRequest, sortRequest);
@@ -454,7 +440,6 @@
         return createAmbiguousAttributeParametersResponse();
       }
 
-      endpointUtil.process(uriInfo);
       T stored;
       try {
         stored = provider.get(id);
@@ -478,7 +463,7 @@
         return createETagErrorResponse();
       }
 
-      ResponseBuilder evaluatePreconditionsResponse = request.evaluatePreconditions(backingETag);
+      ResponseBuilder evaluatePreconditionsResponse = requestContext.getRequest().evaluatePreconditions(backingETag);
 
       if (evaluatePreconditionsResponse != null) {
         return createPreconditionFailedResponse(id, evaluatePreconditionsResponse);
@@ -486,8 +471,7 @@
 
       T updated;
       try {
-        UpdateRequest<T> updateRequest = updateRequestInstance.get();
-        updateRequest.initWithResource(id, stored, resource);
+        UpdateRequest<T> updateRequest = new UpdateRequest<>(id, stored, resource, registry);
         updated = provider.update(updateRequest);
       } catch (UnableToUpdateResourceException e1) {
         return createGenericExceptionResponse(e1, e1.getStatus());
@@ -556,7 +540,6 @@
         return createAmbiguousAttributeParametersResponse();
       }
 
-      endpointUtil.process(uriInfo);
       T stored;
       try {
         stored = provider.get(id);
@@ -580,7 +563,7 @@
         return createETagErrorResponse();
       }
 
-      ResponseBuilder evaluatePreconditionsResponse = request.evaluatePreconditions(backingETag);
+      ResponseBuilder evaluatePreconditionsResponse = requestContext.getRequest().evaluatePreconditions(backingETag);
 
       if (evaluatePreconditionsResponse != null) {
         return createPreconditionFailedResponse(id, evaluatePreconditionsResponse);
@@ -588,8 +571,7 @@
 
       T updated;
       try {
-        UpdateRequest<T> updateRequest = updateRequestInstance.get();
-        updateRequest.initWithPatch(id, stored, patchRequest.getPatchOperationList());
+        UpdateRequest<T> updateRequest = new UpdateRequest<>(id, stored, patchRequest.getPatchOperationList(), registry);
         updated = provider.update(updateRequest);
       } catch (UnableToUpdateResourceException e1) {
         return createGenericExceptionResponse(e1, e1.getStatus());
@@ -652,7 +634,6 @@
       Provider<T> provider = getProviderInternal();
 
       try {
-        endpointUtil.process(uriInfo);
         response = Response.noContent()
                            .build();
 
@@ -705,7 +686,7 @@
       LOG.warn("Provider must supply an id for a resource");
       id = "unknown";
     }
-    return uriInfo.getAbsolutePathBuilder()
+    return requestContext.getUriInfo().getAbsolutePathBuilder()
                   .path(id)
                   .build();
   }
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java
index 79c324a..f301878 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/BulkResourceImpl.java
@@ -31,7 +31,6 @@
 import java.util.regex.Pattern;
 
 import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.enterprise.inject.Instance;
 import jakarta.inject.Inject;
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.Response.Status;
@@ -96,14 +95,19 @@
 //    METHOD_NOT_IMPLEMENTED_STATUS.setCode(METHOD_NOT_IMPLEMENTED);
 //  }
 
-  @Inject
-  Registry registry;
+  private final Registry registry;
+
+  private final ProviderRegistry providerRegistry;
 
   @Inject
-  ProviderRegistry providerRegistry;
-  
-  @Inject
-  Instance<UpdateRequest<ScimResource>> updateRequestInstance;
+  public BulkResourceImpl(Registry registry, ProviderRegistry providerRegistry) {
+    this.registry = registry;
+    this.providerRegistry = providerRegistry;
+  }
+
+  BulkResourceImpl() {
+    this(null, null);
+  }
 
   @Override
   public Response doBulk(BulkRequest request, UriInfo uriInfo) {
@@ -284,8 +288,7 @@
 
         ScimResource original = provider.get(scimResourceId);
 
-        UpdateRequest<ScimResource> updateRequest = updateRequestInstance.get();
-        updateRequest.initWithResource(scimResourceId, original, scimResource);
+        UpdateRequest<ScimResource> updateRequest = new UpdateRequest<>(scimResourceId, original, scimResource, registry);
         provider.update(updateRequest);
       } catch (UnresolvableOperationException unresolvableOperationException) {
         log.error("Could not complete final resolution pass, unresolvable bulkId", unresolvableOperationException);
@@ -454,8 +457,7 @@
       try {
         ScimResource original = provider.get(id);
 
-        UpdateRequest<ScimResource> updateRequest = updateRequestInstance.get();
-        updateRequest.initWithResource(id, original, scimResource);
+        UpdateRequest<ScimResource> updateRequest = new UpdateRequest<>(id, original, scimResource, registry);
         
         provider.update(updateRequest);
         operationResult.setStatus(StatusWrapper.wrap(Status.OK));
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/GroupResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/GroupResourceImpl.java
index 3801e6e..51cc3f7 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/GroupResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/GroupResourceImpl.java
@@ -23,15 +23,26 @@
 package org.apache.directory.scim.server.rest;
 
 import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.directory.scim.server.provider.ProviderRegistry;
+import org.apache.directory.scim.server.schema.Registry;
+import org.apache.directory.scim.server.utility.AttributeUtil;
+import org.apache.directory.scim.server.utility.EtagGenerator;
 import org.apache.directory.scim.spec.protocol.GroupResource;
 import org.apache.directory.scim.spec.resources.ScimGroup;
+import org.apache.directory.scim.spec.resources.ScimUser;
 
 @Slf4j
 @ApplicationScoped
 public class GroupResourceImpl extends BaseResourceTypeResourceImpl<ScimGroup> implements GroupResource {
 
-  public GroupResourceImpl() {
-    super(ScimGroup.class);
+  @Inject
+  public GroupResourceImpl(Registry registry, ProviderRegistry providerRegistry, AttributeUtil attributeUtil, RequestContext requestContext, EtagGenerator etagGenerator) {
+    super(registry, providerRegistry, attributeUtil, requestContext, etagGenerator, ScimGroup.class);
+  }
+
+  GroupResourceImpl() {
+    this(null, null, null, null, null);
   }
 }
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/RequestContext.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/RequestContext.java
new file mode 100644
index 0000000..db1516b
--- /dev/null
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/RequestContext.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.directory.scim.server.rest;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Request;
+import jakarta.ws.rs.core.SecurityContext;
+import jakarta.ws.rs.core.UriInfo;
+import lombok.Data;
+
+/**
+ * Container of JAXRS Context classes. These classes are likely inject via a proxy, so keeping them in a single place
+ * removes the need to have field injection for @Context classes in other places.
+ */
+@Data
+@ApplicationScoped
+public class RequestContext {
+
+  @Context
+  private UriInfo uriInfo;
+
+  @Context
+  private Request request;
+
+  @Context
+  private SecurityContext securityContext;
+}
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/ResourceTypesResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/ResourceTypesResourceImpl.java
index 71a487e..0ae55f1 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/ResourceTypesResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/ResourceTypesResourceImpl.java
@@ -39,12 +39,20 @@
 @ApplicationScoped
 public class ResourceTypesResourceImpl implements ResourceTypesResource {
 
+  private final Registry registry;
+
+  private final RequestContext requestContext;
+
   @Inject
-  private Registry registry;
-  
-  @Context 
-  private UriInfo uriInfo;
-  
+  public ResourceTypesResourceImpl(Registry registry, RequestContext requestContext) {
+    this.registry = registry;
+    this.requestContext = requestContext;
+  }
+
+  ResourceTypesResourceImpl() {
+    this(null, null);
+  }
+
   @Override
   public Response getAllResourceTypes(String filter) {
     
@@ -56,7 +64,7 @@
     
     for (ResourceType resourceType : resourceTypes) {
       Meta meta = new Meta();
-      meta.setLocation(uriInfo.getAbsolutePathBuilder().path(resourceType.getName()).build().toString());
+      meta.setLocation(requestContext.getUriInfo().getAbsolutePathBuilder().path(resourceType.getName()).build().toString());
       meta.setResourceType(resourceType.getResourceType());
       
       resourceType.setMeta(meta);
@@ -81,7 +89,7 @@
     }
     
     Meta meta = new Meta();
-    meta.setLocation(uriInfo.getAbsolutePath().toString());
+    meta.setLocation(requestContext.getUriInfo().getAbsolutePath().toString());
     meta.setResourceType(resourceType.getResourceType());
     
     resourceType.setMeta(meta);
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/SchemaResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/SchemaResourceImpl.java
index e587ba1..e4de3d1 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/SchemaResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/SchemaResourceImpl.java
@@ -38,15 +38,20 @@
 
 @ApplicationScoped
 public class SchemaResourceImpl implements SchemaResource {
-  
+
+  private final Registry registry;
+
   @Inject
-  Registry registry;
-  
-  @Context 
-  private UriInfo uriInfo;
-  
+  public SchemaResourceImpl(Registry registry) {
+    this.registry = registry;
+  }
+
+  SchemaResourceImpl() {
+    this(null);
+  }
+
   @Override
-  public Response getAllSchemas(String filter) {
+  public Response getAllSchemas(String filter, UriInfo uriInfo) {
 
     if (filter != null) {
       return Response.status(Status.FORBIDDEN).build();
@@ -74,7 +79,7 @@
   }
 
   @Override
-  public Response getSchema(String urn) {
+  public Response getSchema(String urn, UriInfo uriInfo) {
     
     Schema schema = registry.getSchema(urn);
     if (schema == null){
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/SelfResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/SelfResourceImpl.java
index 32c789e..f5d728a 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/SelfResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/SelfResourceImpl.java
@@ -24,11 +24,9 @@
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.enterprise.inject.Instance;
 import jakarta.inject.Inject;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.Response.Status;
 
-import jakarta.ws.rs.core.SecurityContext;
 import org.apache.directory.scim.server.exception.UnableToResolveIdResourceException;
 import org.apache.directory.scim.server.provider.SelfIdResolver;
 import org.apache.directory.scim.spec.protocol.SelfResource;
@@ -44,14 +42,22 @@
 @ApplicationScoped
 public class SelfResourceImpl implements SelfResource {
 
-  @Inject
-  UserResource userResource;
+  private final UserResource userResource;
+
+  private final Instance<SelfIdResolver> selfIdResolver;
+
+  private final RequestContext requestContext;
 
   @Inject
-  Instance<SelfIdResolver> selfIdResolver;
+  public SelfResourceImpl(UserResource userResource, Instance<SelfIdResolver> selfIdResolver, RequestContext requestContext) {
+    this.userResource = userResource;
+    this.selfIdResolver = selfIdResolver;
+    this.requestContext = requestContext;
+  }
 
-  @Context
-  SecurityContext securityContext;
+  SelfResourceImpl() {
+    this(null, null, null);
+  }
 
   @Override
   public Response getSelf(AttributeReferenceListWrapper attributes, AttributeReferenceListWrapper excludedAttributes) {
@@ -122,7 +128,7 @@
   }
 
   private String getInternalId() throws UnableToResolveIdResourceException {
-    Principal callerPrincipal = securityContext.getUserPrincipal();
+    Principal callerPrincipal = requestContext.getSecurityContext().getUserPrincipal();
 
     if (callerPrincipal != null) {
       log.debug("Resolved SelfResource principal to : {}", callerPrincipal.getName());
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/ServiceProviderConfigResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/ServiceProviderConfigResourceImpl.java
index e39d6cd..26fe41f 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/ServiceProviderConfigResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/ServiceProviderConfigResourceImpl.java
@@ -47,20 +47,20 @@
 @ApplicationScoped
 public class ServiceProviderConfigResourceImpl implements ServiceProviderConfigResource {
 
-  @Inject
-  ServerConfiguration serverConfiguration;
+  private final ServerConfiguration serverConfiguration;
+
+  private final EtagGenerator etagGenerator;
 
   @Inject
-  EtagGenerator etagGenerator;
-  
-  public ServiceProviderConfigResourceImpl() {
-    serverConfiguration = new ServerConfiguration();  
+  public ServiceProviderConfigResourceImpl(ServerConfiguration serverConfiguration, EtagGenerator etagGenerator) {
+    this.serverConfiguration = serverConfiguration;
+    this.etagGenerator = etagGenerator;
   }
-  
-  public void registerServerConfiguration(ServerConfiguration configuration) {
-    serverConfiguration = configuration;  
+
+  ServiceProviderConfigResourceImpl() {
+    this(null, null);
   }
-  
+
   @Override
   public Response getServiceProviderConfiguration(UriInfo uriInfo) {
     ServiceProviderConfiguration serviceProviderConfiguration = new ServiceProviderConfiguration();
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/UserResourceImpl.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/UserResourceImpl.java
index 4aa2580..d77ff62 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/UserResourceImpl.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/UserResourceImpl.java
@@ -23,7 +23,12 @@
 package org.apache.directory.scim.server.rest;
 
 import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.directory.scim.server.provider.ProviderRegistry;
+import org.apache.directory.scim.server.schema.Registry;
+import org.apache.directory.scim.server.utility.AttributeUtil;
+import org.apache.directory.scim.server.utility.EtagGenerator;
 import org.apache.directory.scim.spec.protocol.UserResource;
 import org.apache.directory.scim.spec.resources.ScimUser;
 
@@ -34,7 +39,13 @@
 @Slf4j
 @ApplicationScoped
 public class UserResourceImpl extends BaseResourceTypeResourceImpl<ScimUser> implements UserResource {
-  public UserResourceImpl() {
-    super(ScimUser.class);
+
+  @Inject
+  public UserResourceImpl(Registry registry, ProviderRegistry providerRegistry, AttributeUtil attributeUtil, RequestContext requestContext, EtagGenerator etagGenerator) {
+    super(registry, providerRegistry, attributeUtil, requestContext, etagGenerator, ScimUser.class);
+  }
+
+  UserResourceImpl() {
+    this(null, null, null, null, null);
   }
 }
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/WebApplicationExceptionMapper.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/WebApplicationExceptionMapper.java
index f8d0051..2289944 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/WebApplicationExceptionMapper.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/WebApplicationExceptionMapper.java
@@ -19,7 +19,6 @@
 
 package org.apache.directory.scim.server.rest;
 
-import jakarta.enterprise.inject.Specializes;
 import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.WebApplicationException;
 import jakarta.ws.rs.core.HttpHeaders;
@@ -32,7 +31,6 @@
 import org.apache.directory.scim.spec.protocol.Constants;
 import org.apache.directory.scim.spec.protocol.data.ErrorResponse;
 
-
 @Provider
 @Produces({Constants.SCIM_CONTENT_TYPE, MediaType.APPLICATION_JSON})
 public class WebApplicationExceptionMapper implements ExceptionMapper<WebApplicationException> {
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/utility/AttributeUtil.java b/scim-server/src/main/java/org/apache/directory/scim/server/utility/AttributeUtil.java
index 7305a1e..e872737 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/utility/AttributeUtil.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/utility/AttributeUtil.java
@@ -41,7 +41,6 @@
 import org.apache.directory.scim.spec.schema.Schema.Attribute.Returned;
 import org.apache.directory.scim.spec.schema.Schema.Attribute.Type;
 
-import jakarta.annotation.PostConstruct;
 import jakarta.inject.Inject;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -61,13 +60,15 @@
 @ApplicationScoped
 public class AttributeUtil {
 
-  @Inject
   Registry registry;
 
   ObjectMapper objectMapper;
 
-  @PostConstruct
-  public void init() { // TODO move this to a CDI producer
+  @Inject
+  public AttributeUtil(Registry registry) {
+    this.registry = registry;
+
+    // TODO move this to a CDI producer
     objectMapper = ObjectMapperFactory.getObjectMapper();
     objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
     objectMapper.setSerializationInclusion(Include.NON_NULL);
@@ -77,6 +78,8 @@
     objectMapper.registerModule(module);
   }
 
+  AttributeUtil() {}
+
   public <T extends ScimResource> T keepAlwaysAttributesForDisplay(T resource) throws IllegalArgumentException, IllegalAccessException, AttributeDoesNotExistException, IOException {
     return setAttributesForDisplayInternal(resource, Returned.DEFAULT, Returned.REQUEST, Returned.NEVER);
   }
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/utility/EndpointUtil.java b/scim-server/src/main/java/org/apache/directory/scim/server/utility/EndpointUtil.java
deleted file mode 100644
index 28b794d..0000000
--- a/scim-server/src/main/java/org/apache/directory/scim/server/utility/EndpointUtil.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.directory.scim.server.utility;
-
-import java.net.URI;
-
-import jakarta.enterprise.context.RequestScoped;
-import jakarta.ws.rs.core.UriBuilder;
-import jakarta.ws.rs.core.UriInfo;
-
-import org.apache.directory.scim.spec.annotation.ScimResourceType;
-import org.apache.directory.scim.spec.exception.ScimResourceInvalidException;
-import org.apache.directory.scim.spec.resources.ScimResource;
-
-@RequestScoped
-public class EndpointUtil {
-  private URI baseUri;
-  
-  public UriBuilder getBaseUriBuilder() {
-    return UriBuilder.fromUri(baseUri);
-  }
-  
-  public UriBuilder getEndpointUriBuilder(Class<? extends ScimResource> resource) {
-    ScimResourceType[] sr = resource.getAnnotationsByType(ScimResourceType.class);
-    
-    if (baseUri == null) {
-      throw new IllegalStateException("BaseUri for Resource "+resource+" was null");
-    }
-
-    if (sr.length == 0 || sr.length > 1) {
-      throw new ScimResourceInvalidException("ScimResource class must have a ScimResourceType annotation");
-    }
-
-    // yuck! TODO where to get REST endpoint from?
-    String resourceName = sr[0].name() + "s";  
-    
-    return UriBuilder.fromUri(baseUri).path(resourceName);
-  }
-  
-  public void process(UriInfo uriInfo) {
-    baseUri = uriInfo.getBaseUri();
-  }
-}
diff --git a/scim-server/src/test/java/org/apache/directory/scim/server/provider/ProviderRegistryTest.java b/scim-server/src/test/java/org/apache/directory/scim/server/provider/ProviderRegistryTest.java
index 43a0c68..6c30f5b 100644
--- a/scim-server/src/test/java/org/apache/directory/scim/server/provider/ProviderRegistryTest.java
+++ b/scim-server/src/test/java/org/apache/directory/scim/server/provider/ProviderRegistryTest.java
@@ -21,16 +21,12 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-import jakarta.enterprise.inject.Instance;
-
 import org.apache.directory.scim.server.schema.Registry;
 import org.apache.directory.scim.spec.resources.ScimUser;
 import org.apache.directory.scim.spec.schema.Schema;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 @ExtendWith(MockitoExtension.class)
@@ -44,9 +40,8 @@
   ProviderRegistry providerRegistry;
   
   public ProviderRegistryTest() {
-    providerRegistry = new ProviderRegistry();
     registry = new Registry();
-    providerRegistry.registry = registry;
+    providerRegistry = new ProviderRegistry(registry, null, null);
   }
 
   @Test
diff --git a/scim-server/src/test/java/org/apache/directory/scim/server/provider/UpdateRequestTest.java b/scim-server/src/test/java/org/apache/directory/scim/server/provider/UpdateRequestTest.java
index 9e31751..b094af5 100644
--- a/scim-server/src/test/java/org/apache/directory/scim/server/provider/UpdateRequestTest.java
+++ b/scim-server/src/test/java/org/apache/directory/scim/server/provider/UpdateRequestTest.java
@@ -31,8 +31,6 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import jakarta.enterprise.inject.Instance;
-
 import org.apache.directory.scim.server.rest.ObjectMapperFactory;
 import org.apache.directory.scim.server.schema.Registry;
 import org.apache.directory.scim.server.utility.ExampleObjectExtension;
@@ -89,18 +87,12 @@
   @Mock
   Provider<ScimUser> provider;
 
-  @Mock
-  Instance<Provider<ScimUser>> providerInstance;
-
   ProviderRegistry providerRegistry;
 
   @BeforeEach
   public void initialize() throws Exception {
-    providerRegistry = new ProviderRegistry();
     registry = new Registry();
-
-    providerRegistry.registry = registry;
-    providerRegistry.scimExtensionRegistry = ScimExtensionRegistry.getInstance();
+    providerRegistry = new ProviderRegistry(registry, ScimExtensionRegistry.getInstance(), null);
 
     Mockito.when(provider.getExtensionList())
            .thenReturn(Stream.of(EnterpriseExtension.class,ExampleObjectExtension.class).collect(Collectors.toList()));
@@ -110,8 +102,7 @@
 
   @Test
   public void testResourcePassthrough() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-    updateRequest.initWithResource("1234", createUser1(), createUser1());
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", createUser1(), createUser1(), registry);
     ScimUser result = updateRequest.getResource();
     log.info("testResourcePassthrough: " + result);
     Assertions.assertThat(result)
@@ -120,8 +111,7 @@
 
   @Test
   public void testPatchPassthrough() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-    updateRequest.initWithPatch("1234", createUser1(), createUser1PatchOps());
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", createUser1(), createUser1PatchOps(), registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
     log.info("testPatchPassthrough: " + result);
     Assertions.assertThat(result)
@@ -130,21 +120,16 @@
 
   @Test
   public void testPatchToUpdate() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-    updateRequest.initWithPatch("1234", createUser1(), createUser1PatchOps());
-        
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", createUser1(), createUser1PatchOps(), registry);
     assertThrows(UnsupportedOperationException.class, () -> updateRequest.getResource());
   }
 
   @Test
   public void testAddSingleAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.setNickName("Jon");
-
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -154,14 +139,12 @@
   
   @Test
   public void testAddSingleExtension() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     EnterpriseExtension ext = user1.removeExtension(EnterpriseExtension.class);
     ScimUser user2 = copy(user1);
     user2.addExtension(ext);
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -171,14 +154,12 @@
 
   @Test
   public void testAddComplexAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.getName()
          .setHonorificPrefix("Dr.");
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -188,8 +169,6 @@
 
   @Test
   public void testAddMultiValuedAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     PhoneNumber mobilePhone = new GlobalPhoneNumberBuilder().globalNumber("+1(814)867-5306").build();
@@ -197,7 +176,7 @@
     mobilePhone.setPrimary(false);
     user2.getPhoneNumbers().add(mobilePhone);
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -213,18 +192,16 @@
    */
   @Test
   public void testAddObjectToEmptyCollection() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
-    user1.setPhoneNumbers(new ArrayList<PhoneNumber>());
+    user1.setPhoneNumbers(new ArrayList<>());
     ScimUser user2 = copy(user1);
     
     PhoneNumber mobilePhone = new GlobalPhoneNumberBuilder().globalNumber("+1(814)867-5306").build();
     mobilePhone.setType("mobile");
     mobilePhone.setPrimary(true);
     user2.getPhoneNumbers().add(mobilePhone);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     assertNotNull(operations);
     assertEquals(1, operations.size());
@@ -236,10 +213,8 @@
   
   @Test
   public void testAddObjectsToEmptyCollection() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
-    user1.setPhoneNumbers(new ArrayList<PhoneNumber>());
+    user1.setPhoneNumbers(new ArrayList<>());
     ScimUser user2 = copy(user1);
     
     PhoneNumber mobilePhone = new GlobalPhoneNumberBuilder().globalNumber("+1(814)867-5306").build();
@@ -252,8 +227,9 @@
     
     user2.getPhoneNumbers().add(mobilePhone);
     user2.getPhoneNumbers().add(homePhone);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     assertNotNull(operations);
     assertEquals(2, operations.size());
@@ -271,13 +247,11 @@
 
   @Test
   public void testReplaceSingleAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.setActive(false);
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -287,13 +261,11 @@
   
   @Test
   public void testReplaceExtensionSingleAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.getExtension(EnterpriseExtension.class).setDepartment("Dept XYZ.");
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -303,14 +275,12 @@
 
   @Test
   public void testReplaceComplexAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.getName()
          .setFamilyName("Nobody");
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -320,8 +290,6 @@
 
   @Test
   public void testReplaceMultiValuedAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.getEmails()
@@ -330,7 +298,7 @@
                        .equals("work"))
          .forEach(e -> e.setValue("nobody@example.com"));
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -340,13 +308,11 @@
 
   @Test
   public void testRemoveSingleAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.setUserName(null);
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -356,13 +322,11 @@
   
   @Test
   public void testRemoveSingleExtension() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.removeExtension(EnterpriseExtension.class);
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -372,14 +336,13 @@
 
   @Test
   public void testRemoveComplexAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.getName()
          .setMiddleName(null);
 
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -389,13 +352,11 @@
 
   @Test
   public void testRemoveFullComplexAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     user2.setName(null);
 
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -405,8 +366,6 @@
 
   @Test
   public void testRemoveMultiValuedAttribute() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     List<Email> newEmails = user2.getEmails()
@@ -415,8 +374,8 @@
                                                .equals("work"))
                                  .collect(Collectors.toList());
     user2.setEmails(newEmails);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -426,8 +385,6 @@
   
   @Test
   public void testRemoveMultiValuedAttributeWithSorting() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -439,8 +396,8 @@
     localAddress.setType("local");
     
     user1.getAddresses().add(localAddress);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     PatchOperation actual = assertSingleResult(result);
@@ -450,8 +407,6 @@
   
   @Test
   public void testAddMultiValuedAttributeWithSorting() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -464,8 +419,8 @@
     
     user2.getAddresses().add(localAddress);
     user1.getAddresses().get(0).setKey("asdf");
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> result = updateRequest.getPatchOperations();
 
     assertEquals(2, result.size());
@@ -475,8 +430,6 @@
   
   @Test
   public void verifyEmptyArraysDoNotCauseMove() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -487,39 +440,35 @@
     ExampleObjectExtension ext2 = new ExampleObjectExtension();
     ext2.setList(new ArrayList<>());
     user2.addExtension(ext2);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     assertTrue(operations.isEmpty(), "Empty Arrays caused a diff");
   }
   
   @Test
   public void verifyEmptyArraysAreNulled() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
     //Set empty list on root object and verify no differences
     user1.setPhotos(new ArrayList<>());
-    updateRequest.initWithResource("1234", user1, user2);
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     assertTrue(operations.isEmpty(), "Empty Arrays are not being nulled out");
     
     //Reset user 1 and empty list on Extension and verify no differences
     user1 = createUser1();
     ExampleObjectExtension ext = new ExampleObjectExtension();
-    ext.setList(new ArrayList<String>());
-    updateRequest.initWithResource("1234", user1, user2);
+    ext.setList(new ArrayList<>());
     operations = updateRequest.getPatchOperations();
     assertTrue(operations.isEmpty(), "Empty Arrays are not being nulled out");
     
     //Reset extension and set empty list on element of extension then verify no differences
     Subobject subobject = new Subobject();
-    subobject.setList1(new ArrayList<String>());
+    subobject.setList1(new ArrayList<>());
     ext = new ExampleObjectExtension();
     ext.setSubobject(subobject);
-    updateRequest.initWithResource("1234", user1, user2);
     operations = updateRequest.getPatchOperations();
     assertTrue(operations.isEmpty(), "Empty Arrays are not being nulled out");
   }
@@ -529,8 +478,6 @@
    */
   @Test
   public void testAddArray() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -547,8 +494,8 @@
     ExampleObjectExtension ext2 = new ExampleObjectExtension();
     ext2.setList(Stream.of(FIRST,SECOND).collect(Collectors.toList()));
     user2.addExtension(ext2);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
 
     Assertions.assertThat(operations)
@@ -562,8 +509,6 @@
   
   @Test
   public void testRemoveArray() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -580,8 +525,8 @@
     ExampleObjectExtension ext2 = new ExampleObjectExtension();
     ext2.setList(null);
     user2.addExtension(ext2);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     assertNotNull(operations);
     assertEquals(2, operations.size());
@@ -594,8 +539,6 @@
   @Disabled
   //TODO: do asserts
   public void testNonTypedAttributeListGetUseablePath() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -606,8 +549,8 @@
     ExampleObjectExtension ext2 = new ExampleObjectExtension();
     ext2.setList(Stream.of(FIRST,SECOND,FOURTH).collect(Collectors.toList()));
     user2.addExtension(ext2);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     System.out.println("Number of operations: "+operations.size());
     operations.stream().forEach(op -> System.out.println(op));
@@ -619,8 +562,6 @@
   @Disabled
   //TODO: do asserts
   public void testMoveFormatNameToNicknamePart1() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -628,8 +569,8 @@
     user1.setNickName(nickname);
     
     user2.getName().setFormatted(nickname);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     System.out.println("Number of operations: "+operations.size());
     operations.stream().forEach(op -> System.out.println(op));
@@ -639,8 +580,6 @@
   @Disabled
   //TODO: do asserts
   public void testMoveFormatNameToNicknamePart2() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -650,8 +589,8 @@
     
     user2.getName().setFormatted(nickname);
     user1.getName().setFormatted("");
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     System.out.println("Number of operations: "+operations.size());
     operations.stream().forEach(op -> System.out.println(op));
@@ -661,8 +600,6 @@
   @Disabled
   //TODO: do asserts
   public void testMoveFormatNameToNicknamePart3() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -672,8 +609,8 @@
     
     user2.getName().setFormatted(nickname);
     user1.getName().setFormatted("");
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     System.out.println("Number of operations: "+operations.size());
     operations.stream().forEach(op -> System.out.println(op));
@@ -683,7 +620,6 @@
   @Disabled
   //TODO: do asserts
   public void testMoveFormatNameToNicknamePart4() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
 
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
@@ -694,8 +630,8 @@
     
     user2.getName().setFormatted(nickname);
     user1.getName().setFormatted(null);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     System.out.println("Number of operations: "+operations.size());
     operations.stream().forEach(op -> System.out.println(op));
@@ -705,8 +641,6 @@
   @Disabled
   //TODO: do asserts
   public void testMoveFormatNameToNicknamePart5() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -716,8 +650,8 @@
     
     user2.getName().setFormatted(null);
     user1.getName().setFormatted(nickname);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     System.out.println("Number of operations: "+operations.size());
     operations.stream().forEach(op -> System.out.println(op));
@@ -726,8 +660,6 @@
   @ParameterizedTest
   @MethodSource("testListOfStringsParameters")
   public void testListOfStringsParameterized(List<String> list1, List<String> list2, List<ExpectedPatchOperation> ops) throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -738,8 +670,8 @@
     ExampleObjectExtension ext2 = new ExampleObjectExtension();
     ext2.setList(list2);
     user2.addExtension(ext2);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     assertEquals(ops.size(), operations.size());
     for(int i = 0; i < operations.size(); i++) {
@@ -798,8 +730,6 @@
   @Test
   //TODO: do parameterized test
   public void offsetTest1() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
-
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
     
@@ -811,8 +741,8 @@
     //ext2.setList(Stream.of("A","A","B","B","D","F","N","Q","Z").collect(Collectors.toList()));
     ext2.setList(Stream.of("A","Z").collect(Collectors.toList()));
     user2.addExtension(ext2);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     System.out.println("Number of operations: "+operations.size());
     operations.stream().forEach(op -> System.out.println(op));
@@ -821,7 +751,6 @@
   
   @Test
   public void testMoveFormatNameToNicknamePart6() throws Exception {
-    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
 
     ScimUser user1 = createUser1();
     ScimUser user2 = copy(user1);
@@ -832,8 +761,8 @@
     
     user2.getName().setFormatted("");
     user1.getName().setFormatted(nickname);
-    
-    updateRequest.initWithResource("1234", user1, user2);
+
+    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
     List<PatchOperation> operations = updateRequest.getPatchOperations();
     System.out.println("Number of operations: "+operations.size());
     operations.stream().forEach(op -> System.out.println(op));
@@ -850,8 +779,7 @@
   public void testShowBugWhereDeleteIsTreatedAsMultipleReplace() throws Exception {
 //    final int expectedNumberOfOperationsWithoutBug = 1;
 //    final int expectedNumberOfOperationsWithBug = 4;
-//    
-//    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>(registry);
+//
 //    ScimUser user1 = createUser1();
 //    ScimUser user2 = copy(user1);
 //    user2.getPhoneNumbers().removeIf(p -> p.getType().equals("home"));
@@ -860,7 +788,7 @@
 //    workNumber.setType("home");
 //    assertNotNull(workNumber);
 //    
-//    updateRequest.initWithResource("1234", user1, user2);
+//    UpdateRequest<ScimUser> updateRequest = new UpdateRequest<>("1234", user1, user2, registry);
 //    List<PatchOperation> operations = updateRequest.getPatchOperations();
 //    assertNotNull(operations);
 //    assertEquals(expectedNumberOfOperationsWithBug, operations.size());
diff --git a/scim-server/src/test/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImplTest.java b/scim-server/src/test/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImplTest.java
index 027a297..63b5244 100644
--- a/scim-server/src/test/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImplTest.java
+++ b/scim-server/src/test/java/org/apache/directory/scim/server/rest/BaseResourceTypeResourceImplTest.java
@@ -86,7 +86,7 @@
     BaseResourceTypeResourceImpl baseResourceImpl = Mockito.mock(BaseResourceTypeResourceImpl.class);
     UriInfo uriInfo = mock(UriInfo.class);
     MultivaluedMap queryParams = mock(MultivaluedMap.class);
-    baseResourceImpl.uriInfo = uriInfo;
+    baseResourceImpl.requestContext = new RequestContext().setUriInfo(uriInfo);
 
     when(uriInfo.getQueryParameters()).thenReturn(queryParams);
     when(queryParams.getFirst("filter")).thenReturn("not null");
diff --git a/scim-server/src/test/java/org/apache/directory/scim/server/rest/SelfResourceImplTest.java b/scim-server/src/test/java/org/apache/directory/scim/server/rest/SelfResourceImplTest.java
index b5e8143..607e4ad 100644
--- a/scim-server/src/test/java/org/apache/directory/scim/server/rest/SelfResourceImplTest.java
+++ b/scim-server/src/test/java/org/apache/directory/scim/server/rest/SelfResourceImplTest.java
@@ -54,9 +54,7 @@
     when(principal.getName()).thenReturn("test-user");
     when(selfIdResolverInstance.isUnsatisfied()).thenReturn(true);
 
-    SelfResourceImpl selfResource = new SelfResourceImpl();
-    selfResource.selfIdResolver = selfIdResolverInstance;
-    selfResource.securityContext = securityContext;
+    SelfResourceImpl selfResource = new SelfResourceImpl(null, selfIdResolverInstance, new RequestContext().setSecurityContext(securityContext));
 
     Response response = selfResource.getSelf(null, null);
     assertThat(response.getEntity(), instanceOf(ErrorResponse.class));
@@ -84,10 +82,7 @@
     when(selfIdResolver.resolveToInternalId(principal)).thenReturn(internalId);
     when(userResource.getById(internalId, null, null)).thenReturn(mockResponse);
 
-    SelfResourceImpl selfResource = new SelfResourceImpl();
-    selfResource.selfIdResolver = selfIdResolverInstance;
-    selfResource.securityContext = securityContext;
-    selfResource.userResource = userResource;
+    SelfResourceImpl selfResource = new SelfResourceImpl(userResource, selfIdResolverInstance, new RequestContext().setSecurityContext(securityContext));
 
     // the response is just a passed along from the UserResource, so just validate it is the same instance.
     assertThat(selfResource.getSelf(null, null), sameInstance(mockResponse));
diff --git a/scim-server/src/test/java/org/apache/directory/scim/server/utility/AttributeUtilTest.java b/scim-server/src/test/java/org/apache/directory/scim/server/utility/AttributeUtilTest.java
index 22b1e4d..e2dd37b 100644
--- a/scim-server/src/test/java/org/apache/directory/scim/server/utility/AttributeUtilTest.java
+++ b/scim-server/src/test/java/org/apache/directory/scim/server/utility/AttributeUtilTest.java
@@ -67,8 +67,7 @@
   @BeforeEach
   public void setup() throws Exception {
     registry = Mockito.mock(Registry.class);
-    attributeUtil = new AttributeUtil();
-    attributeUtil.registry = registry;
+    attributeUtil = new AttributeUtil(registry);
     Schema scimUserSchema = ProviderRegistry.generateSchema(ScimUser.class, ReflectionUtils.getFieldsUpTo(ScimUser.class, BaseResource.class));
     Schema scimEnterpriseUserSchema = ProviderRegistry.generateSchema(EnterpriseExtension.class, ReflectionUtils.getFieldsUpTo(EnterpriseExtension.class, Object.class));
     Schema scimExampleSchema = ProviderRegistry.generateSchema(ExampleObjectExtension.class, ReflectionUtils.getFieldsUpTo(ExampleObjectExtension.class, Object.class));
@@ -81,8 +80,6 @@
     Mockito.when(registry.getAllSchemas()).thenReturn(Arrays.asList(scimUserSchema, scimEnterpriseUserSchema, scimExampleSchema));
     Mockito.when(registry.getAllSchemaUrns()).thenReturn(new HashSet<String>(Arrays.asList(ScimUser.SCHEMA_URI, EnterpriseExtension.URN, ExampleObjectExtension.URN)));
 
-    attributeUtil.init();
-
     objectMapper = ObjectMapperFactory.getObjectMapper();
     objectMapper.setSerializationInclusion(Include.NON_NULL);
     objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
diff --git a/scim-spec/scim-spec-protocol/src/main/java/org/apache/directory/scim/spec/protocol/SchemaResource.java b/scim-spec/scim-spec-protocol/src/main/java/org/apache/directory/scim/spec/protocol/SchemaResource.java
index 35c36ef..2b704f9 100644
--- a/scim-spec/scim-spec-protocol/src/main/java/org/apache/directory/scim/spec/protocol/SchemaResource.java
+++ b/scim-spec/scim-spec-protocol/src/main/java/org/apache/directory/scim/spec/protocol/SchemaResource.java
@@ -30,9 +30,11 @@
 import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.Response.Status;
+import jakarta.ws.rs.core.UriInfo;
 
 import static org.apache.directory.scim.spec.protocol.Constants.SCIM_CONTENT_TYPE;
 
@@ -76,7 +78,7 @@
   @Operation(description="Get All Schemas")
   @ApiResponse(content = @Content(mediaType = SCIM_CONTENT_TYPE,
     array = @ArraySchema(schema = @Schema(implementation = org.apache.directory.scim.spec.schema.Schema.class))))
-  default Response getAllSchemas(@QueryParam("filter") String filter) {
+  default Response getAllSchemas(@QueryParam("filter") String filter, @Context UriInfo uriInfo) {
 
     if (filter != null) {
       return Response.status(Status.FORBIDDEN).build();
@@ -91,7 +93,7 @@
   @Operation(description="Get Schemas by URN")
   @ApiResponse(content = @Content(mediaType = SCIM_CONTENT_TYPE,
     schema = @Schema(implementation = org.apache.directory.scim.spec.schema.Schema.class)))
-  default Response getSchema(@PathParam("uri") String uri) {
+  default Response getSchema(@PathParam("uri") String uri, @Context UriInfo uriInfo) {
     return Response.status(Status.NOT_IMPLEMENTED).build();
   }
 }