Reduce exceptions thrown by AttributeUtil to new AttributeException
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/exception/AttributeDoesNotExistException.java b/scim-server/src/main/java/org/apache/directory/scim/server/exception/AttributeDoesNotExistException.java
index e01ad71..92d524e 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/exception/AttributeDoesNotExistException.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/exception/AttributeDoesNotExistException.java
@@ -19,7 +19,7 @@
 
 package org.apache.directory.scim.server.exception;
 
-public class AttributeDoesNotExistException extends Exception {
+public class AttributeDoesNotExistException extends AttributeException {
 
   private static final long serialVersionUID = 547510233114396694L;
 
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/exception/AttributeException.java b/scim-server/src/main/java/org/apache/directory/scim/server/exception/AttributeException.java
new file mode 100644
index 0000000..3d09887
--- /dev/null
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/exception/AttributeException.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.exception;
+
+public class AttributeException extends Exception {
+
+  private static final long serialVersionUID = 547510233114396694L;
+
+  public AttributeException() {
+  }
+
+  public AttributeException(String message) {
+    super(message);
+  }
+
+  public AttributeException(Throwable cause) {
+    super(cause);
+  }
+
+  public AttributeException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  public AttributeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+    super(message, cause, enableSuppression, writableStackTrace);
+  }
+
+}
diff --git a/scim-server/src/main/java/org/apache/directory/scim/server/rest/AttributeUtil.java b/scim-server/src/main/java/org/apache/directory/scim/server/rest/AttributeUtil.java
index 812f4e4..d5b0042 100644
--- a/scim-server/src/main/java/org/apache/directory/scim/server/rest/AttributeUtil.java
+++ b/scim-server/src/main/java/org/apache/directory/scim/server/rest/AttributeUtil.java
@@ -26,6 +26,7 @@
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.directory.scim.server.exception.AttributeDoesNotExistException;
+import org.apache.directory.scim.server.exception.AttributeException;
 import org.apache.directory.scim.server.schema.SchemaRegistry;
 import org.apache.directory.scim.spec.json.ObjectMapperFactory;
 import org.apache.directory.scim.spec.protocol.attribute.AttributeReference;
@@ -74,15 +75,15 @@
 
   AttributeUtil() {}
 
-  public <T extends ScimResource> T keepAlwaysAttributesForDisplay(T resource) throws IllegalArgumentException, IllegalAccessException, AttributeDoesNotExistException, IOException {
+  public <T extends ScimResource> T keepAlwaysAttributesForDisplay(T resource) throws AttributeException {
     return setAttributesForDisplayInternal(resource, Returned.DEFAULT, Returned.REQUEST, Returned.NEVER);
   }
   
-  public <T extends ScimResource> T setAttributesForDisplay(T resource) throws IllegalArgumentException, IllegalAccessException, AttributeDoesNotExistException, IOException {
+  public <T extends ScimResource> T setAttributesForDisplay(T resource) throws AttributeException {
     return setAttributesForDisplayInternal(resource, Returned.REQUEST, Returned.NEVER);
   }
   
-  private <T extends ScimResource> T setAttributesForDisplayInternal(T resource, Returned ... removeAttributesOfTypes) throws IllegalArgumentException, IllegalAccessException, AttributeDoesNotExistException, IOException {
+  private <T extends ScimResource> T setAttributesForDisplayInternal(T resource, Returned ... removeAttributesOfTypes) throws AttributeException {
     T copy = cloneScimResource(resource);
     String resourceType = copy.getResourceType();
     Schema schema = schemaRegistry.getBaseSchemaOfResourceType(resourceType);
@@ -105,7 +106,7 @@
     return copy;
   }
 
-  public <T extends ScimResource> T setAttributesForDisplay(T resource, Set<AttributeReference> attributes) throws IllegalArgumentException, IllegalAccessException, AttributeDoesNotExistException, IOException {
+  public <T extends ScimResource> T setAttributesForDisplay(T resource, Set<AttributeReference> attributes) throws AttributeException {
     if (attributes.isEmpty()) {
       return setAttributesForDisplay(resource);
     } else {
@@ -151,7 +152,7 @@
     }
   }
 
-  public <T extends ScimResource> T setExcludedAttributesForDisplay(T resource, Set<AttributeReference> excludedAttributes) throws IllegalArgumentException, IllegalAccessException, AttributeDoesNotExistException, IOException {
+  public <T extends ScimResource> T setExcludedAttributesForDisplay(T resource, Set<AttributeReference> excludedAttributes) throws AttributeException {
 
     if (excludedAttributes.isEmpty()) {
       return setAttributesForDisplay(resource);
@@ -182,92 +183,95 @@
   }
 
   @SuppressWarnings("unchecked")
-  private <T extends ScimResource> T cloneScimResource(T original) throws IOException {
+  private <T extends ScimResource> T cloneScimResource(T original) throws AttributeException {
+    try {
     ByteArrayOutputStream boas = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(boas);
     oos.writeObject(original);
 
     ByteArrayInputStream bais = new ByteArrayInputStream(boas.toByteArray());
     ObjectInputStream ois = new ObjectInputStream(bais);
-    T copy = null;
-    try {
-      copy = (T) ois.readObject();
+    return (T) ois.readObject();
     } catch (ClassNotFoundException e) {
-      // Should never happen
-      log.error("", e);
+      throw new IllegalStateException(e);
+    } catch (IOException e) {
+      throw new AttributeException(e);
     }
-    return copy;
   }
 
-  private void removeAttributesOfType(Object object, AttributeContainer attributeContainer, Returned returned) throws IllegalArgumentException {
+  private void removeAttributesOfType(Object object, AttributeContainer attributeContainer, Returned returned) throws AttributeException {
     Function<Attribute, Boolean> function = (attribute) -> returned == attribute.getReturned();
     processAttributes(object, attributeContainer, function);
   }
 
-  private void removeAttributesOfType(Object object, AttributeContainer attributeContainer, Returned returned, Set<Attribute> attributesToKeep) throws IllegalArgumentException, IllegalAccessException {
+  private void removeAttributesOfType(Object object, AttributeContainer attributeContainer, Returned returned, Set<Attribute> attributesToKeep) throws AttributeException {
     Function<Attribute, Boolean> function = (attribute) -> !attributesToKeep.contains(attribute) && returned == attribute.getReturned();
     processAttributes(object, attributeContainer, function);
   }
 
-  private void removeAttributes(Object object, AttributeContainer attributeContainer, Set<Attribute> attributesToRemove) throws IllegalArgumentException, IllegalAccessException {
+  private void removeAttributes(Object object, AttributeContainer attributeContainer, Set<Attribute> attributesToRemove) throws AttributeException {
     Function<Attribute, Boolean> function = (attribute) -> attributesToRemove.contains(attribute);
     processAttributes(object, attributeContainer, function);
   }
 
-  private void processAttributes(Object object, AttributeContainer attributeContainer, Function<Attribute, Boolean> function) throws IllegalArgumentException {
-    if (attributeContainer != null && object != null) {
-      for (Attribute attribute : attributeContainer.getAttributes()) {
+  private void processAttributes(Object object, AttributeContainer attributeContainer, Function<Attribute, Boolean> function) throws AttributeException {
+    try {
+      if (attributeContainer != null && object != null) {
+        for (Attribute attribute : attributeContainer.getAttributes()) {
 
-        Schema.AttributeAccessor accessor = attribute.getAccessor();
+          Schema.AttributeAccessor accessor = attribute.getAccessor();
 
-        if (function.apply(attribute)) {
-          if (!accessor.getType().isPrimitive()) {
-            Object obj = accessor.get(object);
-            if (obj == null) {
+          if (function.apply(attribute)) {
+            if (!accessor.getType().isPrimitive()) {
+              Object obj = accessor.get(object);
+              if (obj == null) {
+                continue;
+              }
+
+              log.info("field to be set to null = " + accessor.getType().getName());
+              accessor.set(object, null);
+            }
+          } else if (!attribute.isMultiValued() && attribute.getType() == Type.COMPLEX) {
+            log.debug("### Processing single value complex field " + attribute.getName());
+            Object subObject = accessor.get(object);
+
+            if (subObject == null) {
               continue;
             }
 
-            log.info("field to be set to null = " + accessor.getType().getName());
-            accessor.set(object, null);
-          }
-        } else if (!attribute.isMultiValued() && attribute.getType() == Type.COMPLEX) {
-          log.debug("### Processing single value complex field " + attribute.getName());
-          Object subObject = accessor.get(object);
-
-          if (subObject == null) {
-            continue;
-          }
-          
-          Attribute subAttribute = attributeContainer.getAttribute(attribute.getName());
-          log.debug("### container type = " + attributeContainer.getClass().getName());
-          if (subAttribute == null) {
-            log.debug("#### subattribute == null");
-          }
-          processAttributes(subObject, subAttribute, function);
-        } else if (attribute.isMultiValued() && attribute.getType() == Type.COMPLEX) {
-          log.debug("### Processing multi-valued complex field " + attribute.getName());
-          Object subObject = accessor.get(object);
-
-          if (subObject == null) {
-            continue;
-          }
-
-          if (Collection.class.isAssignableFrom(subObject.getClass())) {
-            Collection<?> collection = (Collection<?>) subObject;
-            for (Object o : collection) {
-              Attribute subAttribute = attributeContainer.getAttribute(attribute.getName());
-              processAttributes(o, subAttribute, function);
+            Attribute subAttribute = attributeContainer.getAttribute(attribute.getName());
+            log.debug("### container type = " + attributeContainer.getClass().getName());
+            if (subAttribute == null) {
+              log.debug("#### subattribute == null");
             }
-          } else if (accessor.getType().isArray()) {
-            Object[] array = (Object[]) subObject;
+            processAttributes(subObject, subAttribute, function);
+          } else if (attribute.isMultiValued() && attribute.getType() == Type.COMPLEX) {
+            log.debug("### Processing multi-valued complex field " + attribute.getName());
+            Object subObject = accessor.get(object);
 
-            for (Object o : array) {
-              Attribute subAttribute = attributeContainer.getAttribute(attribute.getName());
-              processAttributes(o, subAttribute, function);
+            if (subObject == null) {
+              continue;
+            }
+
+            if (Collection.class.isAssignableFrom(subObject.getClass())) {
+              Collection<?> collection = (Collection<?>) subObject;
+              for (Object o : collection) {
+                Attribute subAttribute = attributeContainer.getAttribute(attribute.getName());
+                processAttributes(o, subAttribute, function);
+              }
+            } else if (accessor.getType().isArray()) {
+              Object[] array = (Object[]) subObject;
+
+              for (Object o : array) {
+                Attribute subAttribute = attributeContainer.getAttribute(attribute.getName());
+                processAttributes(o, subAttribute, function);
+              }
             }
           }
         }
       }
+    } catch (IllegalArgumentException e) {
+      throw new AttributeException(e);
     }
   }
 
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 148113e..4c46acc 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
@@ -36,6 +36,7 @@
 import jakarta.ws.rs.core.Response.Status;
 import jakarta.ws.rs.core.Response.Status.Family;
 
+import org.apache.directory.scim.server.exception.*;
 import org.apache.directory.scim.server.repository.RepositoryRegistry;
 import org.apache.directory.scim.server.repository.Repository;
 import org.apache.directory.scim.server.schema.SchemaRegistry;
@@ -44,12 +45,6 @@
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 
-import org.apache.directory.scim.server.exception.AttributeDoesNotExistException;
-import org.apache.directory.scim.server.exception.ScimServerException;
-import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
-import org.apache.directory.scim.server.exception.UnableToDeleteResourceException;
-import org.apache.directory.scim.server.exception.UnableToRetrieveResourceException;
-import org.apache.directory.scim.server.exception.UnableToUpdateResourceException;
 import org.apache.directory.scim.server.repository.UpdateRequest;
 import org.apache.directory.scim.server.repository.annotations.ScimProcessingExtension;
 import org.apache.directory.scim.server.repository.extensions.AttributeFilterExtension;
@@ -195,8 +190,7 @@
                        .location(buildLocationTag(resource))
                        .tag(etag)
                        .build();
-      } catch (IllegalArgumentException | IllegalAccessException | AttributeDoesNotExistException | IOException e) {
-        e.printStackTrace();
+      } catch (AttributeException e) {
         return createAttributeProcessingErrorResponse(e);
       }
     } catch (ScimServerException sse) {
@@ -296,7 +290,7 @@
         } else {
           created = attributeUtil.setAttributesForDisplay(created, attributeReferences);
         }
-      } catch (IllegalArgumentException | IllegalAccessException | AttributeDoesNotExistException | IOException e) {
+      } catch (AttributeException e) {
         if (etag == null) {
           return Response.status(Status.CREATED)
                          .location(buildLocationTag(created))
@@ -404,7 +398,7 @@
             }
 
             results.add(resource);
-          } catch (IllegalArgumentException | IllegalAccessException | AttributeDoesNotExistException | IOException e) {
+          } catch (AttributeException e) {
             return createAttributeProcessingErrorResponse(e);
           }
         }
@@ -493,7 +487,7 @@
         } else {
           updated = attributeUtil.setAttributesForDisplay(updated, attributeReferences);
         }
-      } catch (IllegalArgumentException | IllegalAccessException | AttributeDoesNotExistException | IOException e) {
+      } catch (AttributeException e) {
         log.error("Failed to handle attribute processing in update " + e.getMessage());
       }
 
@@ -595,7 +589,7 @@
         } else {
           updated = attributeUtil.setAttributesForDisplay(updated, attributeReferences);
         }
-      } catch (IllegalArgumentException | IllegalAccessException | AttributeDoesNotExistException | IOException e) {
+      } catch (AttributeException e) {
         log.error("Failed to handle attribute processing in update " + e.getMessage());
       }