docs: @Override
      public void swapAttributes(
              ExternalContext externalContext, AttributeSwapRequest attributeSwapRequest) {
          // Collate the swap request into a single overrides map
          final Map<String, Object> attributes = new HashMap<String, Object>();
  
          final Map<String, Attribute> currentAttributes =
                  attributeSwapRequest.getCurrentAttributes();
          this.copyAttributes(attributes, currentAttributes);
  
          final Map<String, Attribute> attributesToCopy = attributeSwapRequest.getAttributesToCopy();
          this.copyAttributes(attributes, attributesToCopy);
  
          final Principal currentUser = externalContext.getCurrentUser();
          final String uid = currentUser.getName();
          final IPersonAttributes originalUserAttributes = this.getOriginalUserAttributes(uid);
  
          // Filter out unchanged attributes
          for (final Iterator<Map.Entry<String, Object>> overrideAttrEntryItr =
                          attributes.entrySet().iterator();
                  overrideAttrEntryItr.hasNext(); ) {
              final Entry<String, Object> overrideAttrEntry = overrideAttrEntryItr.next();
              final String attribute = overrideAttrEntry.getKey();
  
              final Object originalValue = originalUserAttributes.getAttributeValue(attribute);
              final Object overrideValue = overrideAttrEntry.getValue();
              if (originalValue == overrideValue
                      || (originalValue != null && originalValue.equals(overrideValue))) {
                  overrideAttrEntryItr.remove();
              }
          }
  
          final PortletRequest portletRequest = (PortletRequest) externalContext.getNativeRequest();
          final PortletPreferences preferences = portletRequest.getPreferences();
  
          final String[] configuredAttributes =
                  preferences.getValues(ATTRIBUTE_SWAPPER_ATTRIBUTES_FORM_SWAPPABLE_ATTRIBUTES, null);
          final String[] excludedAttributes =
                  preferences.getValues(
                          ATTRIBUTE_SWAPPER_ATTRIBUTES_FORM_SWAPPABLE_ATTRIBUTES_EXCLUDES, null);
  
          // Calculate the Set of attributes that are OK to be swapped
          final Set<String> allowedAttributes = new LinkedHashSet<String>();
          if (configuredAttributes != null) {
              allowedAttributes.addAll(Arrays.asList(configuredAttributes));
          } else {
              allowedAttributes.addAll(attributes.keySet());
          }
          if (excludedAttributes != null) {
              allowedAttributes.removeAll(Arrays.asList(excludedAttributes));
          }
  
          // Filter the attributes map
          for (final Iterator<String> attributeItr = attributes.keySet().iterator();
                  attributeItr.hasNext(); ) {
              final String attribute = attributeItr.next();
              if (!allowedAttributes.contains(attribute)) {
                  attributeItr.remove();
                  this.logger.warn(
                          "User '"
                                  + uid
                                  + "' attempted overriding attribute '"
                                  + attribute
                                  + "' which is not allowed in the current configuration. The attribute will be ignored.");
              }
          }
  
          this.logger.warn("User '" + uid + "' setting attribute overrides: " + attributes);
  
          // Override attributes retrieved the person directory
          this.portalRootPersonAttributeDao.setUserAttributeOverride(uid, attributes);
  
          // Update the IPerson, setting the overridden attributes
          final HttpServletRequest portalRequest =
                  this.portalRequestUtils.getPortletHttpRequest(portletRequest);
  
          final IPerson person = this.personManager.getPerson(portalRequest);
          final Map<String, List<Object>> multivaluedAttributes =
                  MultivaluedPersonAttributeUtils.toMultivaluedMap(attributes);
          person.setAttributes(multivaluedAttributes);
          person.setAttribute(OVERRIDDEN_ATTRIBUTES, multivaluedAttributes.keySet());
      }