You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/12/11 16:58:20 UTC

[syncope] 02/02: [SYNCOPE-1410] More robust Builders

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

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 56d67c50509174eb114eb49e53b73aef60fefe8f
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Tue Dec 11 17:58:02 2018 +0100

    [SYNCOPE-1410] More robust Builders
---
 .../client/console/status/ChangePasswordModal.java |  2 +-
 .../syncope/client/console/wizards/any/Groups.java |  4 +-
 .../enduser/resources/UserSelfCreateResource.java  | 18 +++--
 .../enduser/resources/UserSelfUpdateResource.java  | 16 ++---
 .../client/enduser/util/ValidationTest.java        |  4 +-
 .../apache/syncope/common/lib/AnyOperations.java   | 80 +++++++++-------------
 .../apache/syncope/common/lib/request/AnyCR.java   | 12 ++--
 .../syncope/common/lib/request/AnyObjectCR.java    |  7 +-
 .../syncope/common/lib/request/AnyObjectUR.java    |  4 ++
 .../apache/syncope/common/lib/request/AnyUR.java   | 12 ++--
 .../syncope/common/lib/request/AttrPatch.java      | 11 ++-
 .../apache/syncope/common/lib/request/GroupCR.java | 10 +--
 .../apache/syncope/common/lib/request/GroupUR.java |  4 ++
 .../syncope/common/lib/request/MembershipUR.java   | 10 +--
 .../syncope/common/lib/request/RelationshipUR.java | 10 +--
 .../apache/syncope/common/lib/request/UserCR.java  | 10 +--
 .../apache/syncope/common/lib/request/UserUR.java  |  4 ++
 .../org/apache/syncope/common/lib/to/AttrTO.java   |  3 +-
 .../apache/syncope/common/lib/to/MembershipTO.java | 38 ++++++++--
 .../syncope/common/lib/AnyOperationsTest.java      |  8 +--
 .../org/apache/syncope/common/lib/JAXBTest.java    |  2 +-
 .../org/apache/syncope/common/lib/JSONTest.java    |  5 +-
 .../syncope/core/logic/ReconciliationLogic.java    |  8 +--
 .../java/DefaultGroupProvisioningManager.java      |  2 +-
 .../core/provisioning/java/MappingManagerImpl.java |  6 +-
 .../java/data/AbstractAnyDataBinder.java           | 20 +++---
 .../java/data/AnyObjectDataBinderImpl.java         | 10 ++-
 .../java/data/ConfigurationDataBinderImpl.java     |  3 +-
 .../provisioning/java/data/UserDataBinderImpl.java | 10 ++-
 .../provisioning/java/job/SetUMembershipsJob.java  | 16 ++---
 .../core/provisioning/java/MailTemplateTest.java   |  8 +--
 .../core/rest/cxf/service/AbstractAnyService.java  |  4 +-
 .../rest/cxf/service/AnyObjectServiceImpl.java     |  2 +-
 .../core/rest/cxf/service/GroupServiceImpl.java    |  2 +-
 .../core/rest/cxf/service/UserServiceImpl.java     |  2 +-
 .../camel/producer/SuspendProducer.java            |  6 +-
 .../syncope/core/flowable/task/PasswordReset.java  |  2 +-
 .../syncope/core/logic/UserWorkflowTaskLogic.java  |  2 +-
 .../syncope/ext/oidcclient/agent/CodeConsumer.java |  3 +-
 .../syncope/core/logic/oidc/OIDCUserManager.java   |  2 +-
 .../ext/saml2lsp/agent/AssertionConsumer.java      |  3 +-
 .../syncope/core/logic/saml2/SAML2UserManager.java |  2 +-
 .../apache/syncope/core/logic/SCIMDataBinder.java  | 22 +++---
 .../syncope/core/logic/scim/SCIMConfManager.java   |  3 +-
 .../ext/scimv2/cxf/service/GroupServiceImpl.java   | 21 +++---
 .../reference/flowable/AssignDirectorGroup.java    |  3 +-
 .../reference/flowable/CreateARelationship.java    |  5 +-
 .../fit/core/reference/TestPullActions.java        |  3 +-
 .../org/apache/syncope/fit/AbstractITCase.java     |  7 +-
 .../apache/syncope/fit/core/AnyObjectITCase.java   |  7 +-
 .../syncope/fit/core/AuthenticationITCase.java     |  3 +-
 .../syncope/fit/core/ConfigurationITCase.java      |  4 +-
 .../apache/syncope/fit/core/DynRealmITCase.java    |  2 +-
 .../org/apache/syncope/fit/core/GroupITCase.java   | 46 ++++++-------
 .../apache/syncope/fit/core/MembershipITCase.java  | 34 ++++-----
 .../apache/syncope/fit/core/PlainSchemaITCase.java | 36 +++++-----
 .../syncope/fit/core/PropagationTaskITCase.java    |  9 ++-
 .../apache/syncope/fit/core/PullTaskITCase.java    | 16 ++---
 .../org/apache/syncope/fit/core/SearchITCase.java  | 20 +++---
 .../org/apache/syncope/fit/core/UserITCase.java    | 77 +++++++++------------
 .../apache/syncope/fit/core/UserIssuesITCase.java  | 53 +++++++-------
 .../apache/syncope/fit/core/UserSelfITCase.java    | 16 ++---
 .../org/apache/syncope/fit/core/VirAttrITCase.java |  7 +-
 63 files changed, 366 insertions(+), 415 deletions(-)

diff --git a/client/console/src/main/java/org/apache/syncope/client/console/status/ChangePasswordModal.java b/client/console/src/main/java/org/apache/syncope/client/console/status/ChangePasswordModal.java
index 247f8c4..254fb89 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/status/ChangePasswordModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/status/ChangePasswordModal.java
@@ -86,7 +86,7 @@ public class ChangePasswordModal extends AbstractModalPanel<AnyWrapper<UserTO>>
                     }
                 }
 
-                UserUR req = new UserUR.Builder().key(inner.getKey()).
+                UserUR req = new UserUR.Builder(inner.getKey()).
                         password(new PasswordPatch.Builder().
                                 value(inner.getPassword()).onSyncope(isOnSyncope).resources(resources).build()).
                         build();
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
index 67d7d12..8333782 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
@@ -159,9 +159,7 @@ public class Groups extends WizardStep implements ICondition {
                                     new SortParam<>("name", true),
                                     null)).stream().map(input -> {
 
-                                return new MembershipTO.Builder().
-                                        group(input.getKey(), input.getName()).
-                                        build();
+                                return new MembershipTO.Builder(input.getKey()).groupName(input.getName()).build();
                             }).collect(Collectors.toList());
                 }
             }).hideLabel().setOutputMarkupId(true));
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
index 41be448..5fdb0b6 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java
@@ -90,14 +90,14 @@ public class UserSelfCreateResource extends BaseUserSelfResource {
                     userTO.getPlainAttrs().stream().
                             filter(attr -> (attr.getSchema().
                             contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR))).
-                            forEachOrdered(attr -> {
+                            forEach(attr -> {
                                 String[] simpleAttrs = attr.getSchema().split(
                                         SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
                                 MembershipTO membership = userTO.getMemberships().stream().
                                         filter(memb -> simpleAttrs[0].equals(memb.getGroupName())).
                                         findFirst().orElse(null);
                                 if (membership == null) {
-                                    membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+                                    membership = new MembershipTO.Builder(null).groupName(simpleAttrs[0]).build();
                                     userTO.getMemberships().add(membership);
                                 }
 
@@ -112,7 +112,7 @@ public class UserSelfCreateResource extends BaseUserSelfResource {
                     SyncopeEnduserSession.get().getDatePlainSchemas().stream().map(plainSchema -> {
                         millisToDate(userTO.getPlainAttrs(), plainSchema);
                         return plainSchema;
-                    }).forEachOrdered(plainSchema -> {
+                    }).forEach(plainSchema -> {
                         userTO.getMemberships().forEach(membership -> {
                             millisToDate(membership.getPlainAttrs(), plainSchema);
                         });
@@ -122,14 +122,14 @@ public class UserSelfCreateResource extends BaseUserSelfResource {
                     userTO.getDerAttrs().stream().
                             filter(attr -> (attr.getSchema().
                             contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR))).
-                            forEachOrdered(attr -> {
+                            forEach(attr -> {
                                 String[] simpleAttrs = attr.getSchema().split(
                                         SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
                                 MembershipTO membership = userTO.getMemberships().stream().
                                         filter(memb -> simpleAttrs[0].equals(memb.getGroupName())).
                                         findFirst().orElse(null);
                                 if (membership == null) {
-                                    membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+                                    membership = new MembershipTO.Builder(null).groupName(simpleAttrs[0]).build();
                                     userTO.getMemberships().add(membership);
                                 }
 
@@ -144,14 +144,14 @@ public class UserSelfCreateResource extends BaseUserSelfResource {
                     userTO.getVirAttrs().stream().
                             filter(attr -> (attr.getSchema().
                             contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR))).
-                            forEachOrdered(attr -> {
+                            forEach(attr -> {
                                 String[] simpleAttrs = attr.getSchema().split(
                                         SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
                                 MembershipTO membership = userTO.getMemberships().stream().
                                         filter(memb -> simpleAttrs[0].equals(memb.getGroupName())).
                                         findFirst().orElse(null);
                                 if (membership == null) {
-                                    membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+                                    membership = new MembershipTO.Builder(null).groupName(simpleAttrs[0]).build();
                                     userTO.getMemberships().add(membership);
                                 }
 
@@ -166,9 +166,7 @@ public class UserSelfCreateResource extends BaseUserSelfResource {
                     LOG.trace("Received user self registration request is: [{}]", userTO);
 
                     // adapt request and create user
-                    UserCR req = new UserCR.Builder().
-                            realm(userTO.getRealm()).
-                            username(userTO.getUsername()).
+                    UserCR req = new UserCR.Builder(userTO.getRealm(), userTO.getUsername()).
                             password(userTO.getPassword()).
                             mustChangePassword(userTO.isMustChangePassword()).
                             securityQuestion(userTO.getSecurityQuestion()).
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
index 98bb010..1adbdf5 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java
@@ -75,14 +75,14 @@ public class UserSelfUpdateResource extends BaseUserSelfResource {
                 Set<AttrTO> membAttrs = new HashSet<>();
                 userTO.getPlainAttrs().stream().
                         filter(attr -> (attr.getSchema().contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR))).
-                        forEachOrdered((attr) -> {
+                        forEach(attr -> {
                             String[] simpleAttrs = attr.getSchema().split(
                                     SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
                             MembershipTO membership = userTO.getMemberships().stream().
                                     filter(item -> simpleAttrs[0].equals(item.getGroupName())).
                                     findFirst().orElse(null);
                             if (membership == null) {
-                                membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+                                membership = new MembershipTO.Builder(null).groupName(simpleAttrs[0]).build();
                                 userTO.getMemberships().add(membership);
                             }
                             AttrTO clone = SerializationUtils.clone(attr);
@@ -97,7 +97,7 @@ public class UserSelfUpdateResource extends BaseUserSelfResource {
                         map(plainSchema -> {
                             millisToDate(userTO.getPlainAttrs(), plainSchema);
                             return plainSchema;
-                        }).forEachOrdered(plainSchema -> {
+                        }).forEach(plainSchema -> {
                     userTO.getMemberships().forEach(membership -> {
                         millisToDate(membership.getPlainAttrs(), plainSchema);
                     });
@@ -106,14 +106,14 @@ public class UserSelfUpdateResource extends BaseUserSelfResource {
                 membAttrs.clear();
                 userTO.getDerAttrs().stream().
                         filter(attr -> (attr.getSchema().contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR))).
-                        forEachOrdered(attr -> {
+                        forEach(attr -> {
                             String[] simpleAttrs = attr.getSchema().split(
                                     SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
                             MembershipTO membership = userTO.getMemberships().stream().
                                     filter(item -> simpleAttrs[0].equals(item.getGroupName())).
                                     findFirst().orElse(null);
                             if (membership == null) {
-                                membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+                                membership = new MembershipTO.Builder(null).groupName(simpleAttrs[0]).build();
                                 userTO.getMemberships().add(membership);
                             }
                             AttrTO clone = SerializationUtils.clone(attr);
@@ -126,14 +126,14 @@ public class UserSelfUpdateResource extends BaseUserSelfResource {
                 membAttrs.clear();
                 userTO.getVirAttrs().stream().
                         filter(attr -> (attr.getSchema().contains(SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR))).
-                        forEachOrdered((attr) -> {
+                        forEach((attr) -> {
                             String[] simpleAttrs = attr.getSchema().split(
                                     SyncopeEnduserConstants.MEMBERSHIP_ATTR_SEPARATOR);
                             MembershipTO membership = userTO.getMemberships().stream().
                                     filter(item -> simpleAttrs[0].equals(item.getGroupName())).
                                     findFirst().orElse(null);
                             if (membership == null) {
-                                membership = new MembershipTO.Builder().group(null, simpleAttrs[0]).build();
+                                membership = new MembershipTO.Builder(null).groupName(simpleAttrs[0]).build();
                                 userTO.getMemberships().add(membership);
 
                             }
@@ -212,7 +212,7 @@ public class UserSelfUpdateResource extends BaseUserSelfResource {
                 EntityTOUtils.buildAttrMap(userTOAttrs);
         selfTOAttrs.stream().
                 filter(selfTOAttr -> (!userTOAttrsMap.containsKey(selfTOAttr.getSchema()))).
-                forEachOrdered(selfTOAttr -> {
+                forEach(selfTOAttr -> {
                     userTOAttrs.add(selfTOAttr);
                 });
     }
diff --git a/client/enduser/src/test/java/org/apache/syncope/client/enduser/util/ValidationTest.java b/client/enduser/src/test/java/org/apache/syncope/client/enduser/util/ValidationTest.java
index 1fdd91e..7790af7 100644
--- a/client/enduser/src/test/java/org/apache/syncope/client/enduser/util/ValidationTest.java
+++ b/client/enduser/src/test/java/org/apache/syncope/client/enduser/util/ValidationTest.java
@@ -36,8 +36,8 @@ import org.springframework.core.io.ClassPathResource;
 
 public class ValidationTest {
 
-    private AttrTO attrTO(String schemaKey, String... values) {
-        return new AttrTO.Builder().schema(schemaKey).values(values).build();
+    private AttrTO attrTO(final String schemaKey, final String... values) {
+        return new AttrTO.Builder(schemaKey).values(values).build();
     }
 
     @Test
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
index 0f9cb00..fc9e834 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
@@ -114,9 +114,8 @@ public final class AnyOperations {
         if (!incremental) {
             originalAttrs.keySet().stream().filter(attr -> !updatedAttrs.containsKey(attr)).
                     forEach(schema -> {
-                        result.getPlainAttrs().add(new AttrPatch.Builder().
+                        result.getPlainAttrs().add(new AttrPatch.Builder(new AttrTO.Builder(schema).build()).
                                 operation(PatchOperation.DELETE).
-                                attrTO(new AttrTO.Builder().schema(schema).build()).
                                 build());
                     });
         }
@@ -124,16 +123,14 @@ public final class AnyOperations {
         updatedAttrs.values().forEach(attrTO -> {
             if (isEmpty(attrTO)) {
                 if (!incremental) {
-                    result.getPlainAttrs().add(new AttrPatch.Builder().
+                    result.getPlainAttrs().add(new AttrPatch.Builder(new AttrTO.Builder(attrTO.getSchema()).build()).
                             operation(PatchOperation.DELETE).
-                            attrTO(new AttrTO.Builder().schema(attrTO.getSchema()).build()).
                             build());
                 }
             } else if (!originalAttrs.containsKey(attrTO.getSchema())
                     || !originalAttrs.get(attrTO.getSchema()).getValues().equals(attrTO.getValues())) {
 
-                AttrPatch patch = new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).attrTO(attrTO).
-                        build();
+                AttrPatch patch = new AttrPatch.Builder(attrTO).operation(PatchOperation.ADD_REPLACE).build();
                 if (!patch.isEmpty()) {
                     result.getPlainAttrs().add(patch);
                 }
@@ -188,18 +185,16 @@ public final class AnyOperations {
 
         updatedRels.entrySet().stream().
                 filter(entry -> (!originalRels.containsKey(entry.getKey()))).
-                forEachOrdered(entry -> {
-                    result.getRelationships().add(new RelationshipUR.Builder().
-                            operation(PatchOperation.ADD_REPLACE).
-                            relationshipTO(entry.getValue()).build());
+                forEach(entry -> {
+                    result.getRelationships().add(new RelationshipUR.Builder(entry.getValue()).
+                            operation(PatchOperation.ADD_REPLACE).build());
                 });
 
         if (!incremental) {
             originalRels.keySet().stream().filter(relationship -> !updatedRels.containsKey(relationship)).
                     forEach(key -> {
-                        result.getRelationships().add(new RelationshipUR.Builder().
-                                operation(PatchOperation.DELETE).
-                                relationshipTO(originalRels.get(key)).build());
+                        result.getRelationships().add(new RelationshipUR.Builder(originalRels.get(key)).
+                                operation(PatchOperation.DELETE).build());
                     });
         }
 
@@ -208,8 +203,8 @@ public final class AnyOperations {
         Map<String, MembershipTO> originalMembs = EntityTOUtils.buildMembershipMap(original.getMemberships());
 
         updatedMembs.forEach((key, value) -> {
-            MembershipUR membershipPatch = new MembershipUR.Builder().
-                    operation(PatchOperation.ADD_REPLACE).group(value.getGroupKey()).build();
+            MembershipUR membershipPatch = new MembershipUR.Builder(value.getGroupKey()).
+                    operation(PatchOperation.ADD_REPLACE).build();
 
             diff(value, membershipPatch);
 
@@ -223,8 +218,8 @@ public final class AnyOperations {
         if (!incremental) {
             originalMembs.keySet().stream().filter(membership -> !updatedMembs.containsKey(membership)).
                     forEach(key -> {
-                        result.getMemberships().add(new MembershipUR.Builder().
-                                operation(PatchOperation.DELETE).group(originalMembs.get(key).getGroupKey()).build());
+                        result.getMemberships().add(new MembershipUR.Builder(originalMembs.get(key).getGroupKey()).
+                                operation(PatchOperation.DELETE).build());
                     });
         }
 
@@ -310,18 +305,16 @@ public final class AnyOperations {
 
         updatedRels.entrySet().stream().
                 filter(entry -> (!originalRels.containsKey(entry.getKey()))).
-                forEachOrdered(entry -> {
-                    result.getRelationships().add(new RelationshipUR.Builder().
-                            operation(PatchOperation.ADD_REPLACE).
-                            relationshipTO(entry.getValue()).build());
+                forEach(entry -> {
+                    result.getRelationships().add(new RelationshipUR.Builder(entry.getValue()).
+                            operation(PatchOperation.ADD_REPLACE).build());
                 });
 
         if (!incremental) {
             originalRels.keySet().stream().filter(relationship -> !updatedRels.containsKey(relationship)).
                     forEach(key -> {
-                        result.getRelationships().add(new RelationshipUR.Builder().
-                                operation(PatchOperation.DELETE).
-                                relationshipTO(originalRels.get(key)).build());
+                        result.getRelationships().add(new RelationshipUR.Builder(originalRels.get(key)).
+                                operation(PatchOperation.DELETE).build());
                     });
         }
 
@@ -330,8 +323,8 @@ public final class AnyOperations {
         Map<String, MembershipTO> originalMembs = EntityTOUtils.buildMembershipMap(original.getMemberships());
 
         updatedMembs.forEach((key, value) -> {
-            MembershipUR membershipPatch = new MembershipUR.Builder().
-                    operation(PatchOperation.ADD_REPLACE).group(value.getGroupKey()).build();
+            MembershipUR membershipPatch = new MembershipUR.Builder(value.getGroupKey()).
+                    operation(PatchOperation.ADD_REPLACE).build();
 
             diff(value, membershipPatch);
 
@@ -345,8 +338,8 @@ public final class AnyOperations {
         if (!incremental) {
             originalMembs.keySet().stream().filter(membership -> !updatedMembs.containsKey(membership)).
                     forEach(key -> {
-                        result.getMemberships().add(new MembershipUR.Builder().
-                                operation(PatchOperation.DELETE).group(originalMembs.get(key).getGroupKey()).build());
+                        result.getMemberships().add(new MembershipUR.Builder(originalMembs.get(key).getGroupKey()).
+                                operation(PatchOperation.DELETE).build());
                     });
         }
 
@@ -531,14 +524,12 @@ public final class AnyOperations {
                                 findFirst().ifPresent(memb -> result.getMemberships().remove(memb));
 
                         if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
-                            MembershipTO newMembershipTO =
-                                    new MembershipTO.Builder().group(membPatch.getGroup()).build();
-
-                            // 3. plain attributes
-                            newMembershipTO.getPlainAttrs().addAll(membPatch.getPlainAttrs());
-
-                            // 4. virtual attributes
-                            newMembershipTO.getVirAttrs().addAll(membPatch.getVirAttrs());
+                            MembershipTO newMembershipTO = new MembershipTO.Builder(membPatch.getGroup()).
+                                    // 3. plain attributes
+                                    plainAttrs(membPatch.getPlainAttrs()).
+                                    // 4. virtual attributes
+                                    virAttrs(membPatch.getVirAttrs()).
+                                    build();
 
                             result.getMemberships().add(newMembershipTO);
                         }
@@ -586,14 +577,12 @@ public final class AnyOperations {
                                 findFirst().ifPresent(memb -> result.getMemberships().remove(memb));
 
                         if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
-                            MembershipTO newMembershipTO =
-                                    new MembershipTO.Builder().group(membPatch.getGroup()).build();
-
-                            // 3. plain attributes
-                            newMembershipTO.getPlainAttrs().addAll(membPatch.getPlainAttrs());
-
-                            // 4. virtual attributes
-                            newMembershipTO.getVirAttrs().addAll(membPatch.getVirAttrs());
+                            MembershipTO newMembershipTO = new MembershipTO.Builder(membPatch.getGroup()).
+                                    // 3. plain attributes
+                                    plainAttrs(membPatch.getPlainAttrs()).
+                                    // 4. virtual attributes
+                                    virAttrs(membPatch.getVirAttrs()).
+                                    build();
 
                             result.getMemberships().add(newMembershipTO);
                         }
@@ -625,9 +614,8 @@ public final class AnyOperations {
     public static void cleanEmptyAttrs(final AnyTO anyTO, final AnyUR anyUR) {
         anyUR.getPlainAttrs().addAll(anyTO.getPlainAttrs().stream().
                 filter(plainAttrTO -> isEmpty(plainAttrTO)).
-                map(plainAttrTO -> new AttrPatch.Builder().
+                map(plainAttrTO -> new AttrPatch.Builder(new AttrTO.Builder(plainAttrTO.getSchema()).build()).
                 operation(PatchOperation.DELETE).
-                attrTO(new AttrTO.Builder().schema(plainAttrTO.getSchema()).build()).
                 build()).collect(Collectors.toSet()));
     }
 
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyCR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyCR.java
index 49efeb1..9141e2a 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyCR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyCR.java
@@ -53,9 +53,13 @@ public abstract class AnyCR implements Serializable, AttributableReqEntity {
 
         protected R instance;
 
+        Builder(final String realm) {
+            getInstance().setRealm(realm);
+        }
+
         protected abstract R newInstance();
 
-        protected R getInstance() {
+        protected final R getInstance() {
             if (instance == null) {
                 instance = newInstance();
             }
@@ -63,12 +67,6 @@ public abstract class AnyCR implements Serializable, AttributableReqEntity {
         }
 
         @SuppressWarnings("unchecked")
-        public B realm(final String realm) {
-            getInstance().setRealm(realm);
-            return (B) this;
-        }
-
-        @SuppressWarnings("unchecked")
         public B auxClass(final String auxClass) {
             getInstance().getAuxClasses().add(auxClass);
             return (B) this;
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyObjectCR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyObjectCR.java
index a833034..ad8363e 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyObjectCR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyObjectCR.java
@@ -53,13 +53,10 @@ public class AnyObjectCR extends AnyCR implements GroupableRelatableTO {
             return new AnyObjectCR();
         }
 
-        public Builder(final String type) {
+        public Builder(final String realm, final String type, final String name) {
+            super(realm);
             getInstance().setType(type);
-        }
-
-        public Builder name(final String name) {
             getInstance().setName(name);
-            return this;
         }
 
         public Builder relationship(final RelationshipTO relationship) {
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyObjectUR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyObjectUR.java
index 1f7cdbf..577a870 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyObjectUR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyObjectUR.java
@@ -40,6 +40,10 @@ public class AnyObjectUR extends AnyUR {
 
     public static class Builder extends AnyUR.Builder<AnyObjectUR, Builder> {
 
+        public Builder(final String key) {
+            super(key);
+        }
+
         @Override
         protected AnyObjectUR newInstance() {
             return new AnyObjectUR();
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyUR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyUR.java
index 52a6b3f..fd42151 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyUR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AnyUR.java
@@ -51,9 +51,13 @@ public abstract class AnyUR implements Serializable {
 
         protected R instance;
 
+        Builder(final String key) {
+            getInstance().setKey(key);
+        }
+
         protected abstract R newInstance();
 
-        protected R getInstance() {
+        protected final R getInstance() {
             if (instance == null) {
                 instance = newInstance();
             }
@@ -61,12 +65,6 @@ public abstract class AnyUR implements Serializable {
         }
 
         @SuppressWarnings("unchecked")
-        public B key(final String key) {
-            getInstance().setKey(key);
-            return (B) this;
-        }
-
-        @SuppressWarnings("unchecked")
         public B realm(final StringReplacePatchItem realm) {
             getInstance().setRealm(realm);
             return (B) this;
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AttrPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AttrPatch.java
index 033ad87..bc874ce 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/AttrPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/AttrPatch.java
@@ -33,16 +33,15 @@ public class AttrPatch extends AbstractPatch {
 
     public static class Builder extends AbstractPatch.Builder<AttrPatch, Builder> {
 
+        public Builder(final AttrTO attrTO) {
+            super();
+            getInstance().setAttrTO(attrTO);
+        }
+
         @Override
         protected AttrPatch newInstance() {
             return new AttrPatch();
         }
-
-        public Builder attrTO(final AttrTO attrTO) {
-            getInstance().setAttrTO(attrTO);
-            return this;
-        }
-
     }
 
     private AttrTO attrTO;
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/GroupCR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/GroupCR.java
index 8830e1c..911d5e5 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/GroupCR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/GroupCR.java
@@ -47,16 +47,16 @@ public class GroupCR extends AnyCR {
 
     public static class Builder extends AnyCR.Builder<GroupCR, Builder> {
 
+        public Builder(final String realm, final String name) {
+            super(realm);
+            getInstance().setName(name);
+        }
+
         @Override
         protected GroupCR newInstance() {
             return new GroupCR();
         }
 
-        public Builder name(final String name) {
-            getInstance().setName(name);
-            return this;
-        }
-
         public Builder userOwner(final String userOwner) {
             getInstance().setUserOwner(userOwner);
             return this;
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/GroupUR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/GroupUR.java
index a3b3b65..c24318c 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/GroupUR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/GroupUR.java
@@ -47,6 +47,10 @@ public class GroupUR extends AnyUR {
 
     public static class Builder extends AnyUR.Builder<GroupUR, Builder> {
 
+        public Builder(final String key) {
+            super(key);
+        }
+
         @Override
         protected GroupUR newInstance() {
             return new GroupUR();
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/MembershipUR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/MembershipUR.java
index dde21be..bfb0503 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/MembershipUR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/MembershipUR.java
@@ -39,16 +39,16 @@ public class MembershipUR extends AbstractPatch {
 
     public static class Builder extends AbstractPatch.Builder<MembershipUR, Builder> {
 
+        public Builder(final String group) {
+            super();
+            getInstance().setGroup(group);
+        }
+
         @Override
         protected MembershipUR newInstance() {
             return new MembershipUR();
         }
 
-        public Builder group(final String group) {
-            getInstance().setGroup(group);
-            return this;
-        }
-
         public Builder plainAttr(final AttrTO plainAttr) {
             getInstance().getPlainAttrs().add(plainAttr);
             return this;
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/RelationshipUR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/RelationshipUR.java
index d193fe8..4e14d3b 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/RelationshipUR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/RelationshipUR.java
@@ -32,15 +32,15 @@ public class RelationshipUR extends AbstractPatch {
 
     public static class Builder extends AbstractPatch.Builder<RelationshipUR, Builder> {
 
+        public Builder(final RelationshipTO relationshipTO) {
+            super();
+            getInstance().setRelationshipTO(relationshipTO);
+        }
+
         @Override
         protected RelationshipUR newInstance() {
             return new RelationshipUR();
         }
-
-        public Builder relationshipTO(final RelationshipTO relationshipTO) {
-            getInstance().setRelationshipTO(relationshipTO);
-            return this;
-        }
     }
 
     private RelationshipTO relationshipTO;
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/UserCR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/UserCR.java
index 38929fa..0e76d67 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/UserCR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/UserCR.java
@@ -50,16 +50,16 @@ public class UserCR extends AnyCR implements GroupableRelatableTO {
 
     public static class Builder extends AnyCR.Builder<UserCR, Builder> {
 
+        public Builder(final String realm, final String username) {
+            super(realm);
+            getInstance().setUsername(username);
+        }
+
         @Override
         protected UserCR newInstance() {
             return new UserCR();
         }
 
-        public Builder username(final String username) {
-            getInstance().setUsername(username);
-            return this;
-        }
-
         public Builder password(final String password) {
             getInstance().setPassword(password);
             return this;
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/request/UserUR.java b/common/lib/src/main/java/org/apache/syncope/common/lib/request/UserUR.java
index bc5f854..5a42f8c 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/request/UserUR.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/request/UserUR.java
@@ -40,6 +40,10 @@ public class UserUR extends AnyUR {
 
     public static class Builder extends AnyUR.Builder<UserUR, Builder> {
 
+        public Builder(final String key) {
+            super(key);
+        }
+
         @Override
         protected UserUR newInstance() {
             return new UserUR();
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttrTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttrTO.java
index 570d91f..5348e7e 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttrTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttrTO.java
@@ -42,9 +42,8 @@ public class AttrTO implements Serializable {
 
         private final AttrTO instance = new AttrTO();
 
-        public Builder schema(final String schema) {
+        public Builder(final String schema) {
             instance.setSchema(schema);
-            return this;
         }
 
         public Builder value(final String value) {
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
index 7696c08..1946964 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
@@ -21,6 +21,8 @@ package org.apache.syncope.common.lib.to;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Optional;
 import java.util.Set;
@@ -41,17 +43,45 @@ public class MembershipTO implements Serializable, AttributableTO {
 
         private final MembershipTO instance = new MembershipTO();
 
-        public Builder group(final String groupKey) {
+        public Builder(final String groupKey) {
             instance.setGroupKey(groupKey);
-            return this;
         }
 
-        public Builder group(final String groupKey, final String groupName) {
-            instance.setGroupKey(groupKey);
+        public Builder groupName(final String groupName) {
             instance.setGroupName(groupName);
             return this;
         }
 
+        public Builder plainAttr(final AttrTO plainAttr) {
+            instance.getPlainAttrs().add(plainAttr);
+            return this;
+        }
+
+        public Builder plainAttrs(final AttrTO... plainAttrs) {
+            instance.getPlainAttrs().addAll(Arrays.asList(plainAttrs));
+            return this;
+        }
+
+        public Builder plainAttrs(final Collection<AttrTO> plainAttrs) {
+            instance.getPlainAttrs().addAll(plainAttrs);
+            return this;
+        }
+
+        public Builder virAttr(final AttrTO virAttr) {
+            instance.getVirAttrs().add(virAttr);
+            return this;
+        }
+
+        public Builder virAttrs(final Collection<AttrTO> virAttrs) {
+            instance.getVirAttrs().addAll(virAttrs);
+            return this;
+        }
+
+        public Builder virAttrs(final AttrTO... virAttrs) {
+            instance.getVirAttrs().addAll(Arrays.asList(virAttrs));
+            return this;
+        }
+
         public MembershipTO build() {
             return instance;
         }
diff --git a/common/lib/src/test/java/org/apache/syncope/common/lib/AnyOperationsTest.java b/common/lib/src/test/java/org/apache/syncope/common/lib/AnyOperationsTest.java
index 41393d4..c69d179 100644
--- a/common/lib/src/test/java/org/apache/syncope/common/lib/AnyOperationsTest.java
+++ b/common/lib/src/test/java/org/apache/syncope/common/lib/AnyOperationsTest.java
@@ -33,13 +33,13 @@ public class AnyOperationsTest {
     public void mindiff() {
         AnyObjectTO oldOne = new AnyObjectTO();
         oldOne.setName("name");
-        oldOne.getPlainAttrs().add(new AttrTO.Builder().schema("plain").value("oldValue").build());
-        oldOne.getPlainAttrs().add(new AttrTO.Builder().schema("encrypted").value("oldValue").build());
+        oldOne.getPlainAttrs().add(new AttrTO.Builder("plain").value("oldValue").build());
+        oldOne.getPlainAttrs().add(new AttrTO.Builder("encrypted").value("oldValue").build());
 
         AnyObjectTO newOne = new AnyObjectTO();
         newOne.setName("name");
-        newOne.getPlainAttrs().add(new AttrTO.Builder().schema("plain").value("newValue").build());
-        newOne.getPlainAttrs().add(new AttrTO.Builder().schema("encrypted").value("oldValue").build());
+        newOne.getPlainAttrs().add(new AttrTO.Builder("plain").value("newValue").build());
+        newOne.getPlainAttrs().add(new AttrTO.Builder("encrypted").value("oldValue").build());
 
         AnyObjectUR diff = AnyOperations.diff(newOne, oldOne, true);
         assertEquals(1, diff.getPlainAttrs().size());
diff --git a/common/lib/src/test/java/org/apache/syncope/common/lib/JAXBTest.java b/common/lib/src/test/java/org/apache/syncope/common/lib/JAXBTest.java
index a63d558..4e6109c 100644
--- a/common/lib/src/test/java/org/apache/syncope/common/lib/JAXBTest.java
+++ b/common/lib/src/test/java/org/apache/syncope/common/lib/JAXBTest.java
@@ -63,7 +63,7 @@ public class JAXBTest {
         GroupTO group = new GroupTO();
         group.setName(UUID.randomUUID().toString());
         group.setRealm(SyncopeConstants.ROOT_REALM);
-        group.getVirAttrs().add(new AttrTO.Builder().schema("rvirtualdata").value("rvirtualvalue").build());
+        group.getVirAttrs().add(new AttrTO.Builder("rvirtualdata").value("rvirtualvalue").build());
         group.getADynMembershipConds().put("USER", "username==a*");
 
         ProvisioningResult<GroupTO> original = new ProvisioningResult<>();
diff --git a/common/lib/src/test/java/org/apache/syncope/common/lib/JSONTest.java b/common/lib/src/test/java/org/apache/syncope/common/lib/JSONTest.java
index 780fc30..fb9ac17 100644
--- a/common/lib/src/test/java/org/apache/syncope/common/lib/JSONTest.java
+++ b/common/lib/src/test/java/org/apache/syncope/common/lib/JSONTest.java
@@ -84,7 +84,7 @@ public class JSONTest {
         GroupTO group = new GroupTO();
         group.setName(UUID.randomUUID().toString());
         group.setRealm(SyncopeConstants.ROOT_REALM);
-        group.getVirAttrs().add(new AttrTO.Builder().schema("rvirtualdata").value("rvirtualvalue").build());
+        group.getVirAttrs().add(new AttrTO.Builder("rvirtualdata").value("rvirtualvalue").build());
         group.getADynMembershipConds().put("USER", "username==a*");
 
         ProvisioningResult<GroupTO> original = new ProvisioningResult<>();
@@ -100,7 +100,8 @@ public class JSONTest {
         StringWriter writer = new StringWriter();
         mapper.writeValue(writer, original);
 
-        ProvisioningResult<GroupTO> actual = mapper.readValue(writer.toString(), new TypeReference<ProvisioningResult<GroupTO>>() {
+        ProvisioningResult<GroupTO> actual = mapper.readValue(writer.toString(),
+                new TypeReference<ProvisioningResult<GroupTO>>() {
         });
         assertEquals(original, actual);
     }
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
index 36c594b..ab36bdc 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
@@ -117,10 +117,10 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
 
         ConnObjectTO connObjectTO = ConnObjectUtils.getConnObjectTO(attrs.getRight());
         if (attrs.getLeft() != null) {
-            connObjectTO.getAttrs().add(new AttrTO.Builder().
-                    schema(connObjectKey.getExtAttrName()).value(attrs.getLeft()).build());
-            connObjectTO.getAttrs().add(new AttrTO.Builder().
-                    schema(Uid.NAME).value(attrs.getLeft()).build());
+            connObjectTO.getAttrs().add(new AttrTO.Builder(connObjectKey.getExtAttrName()).
+                    value(attrs.getLeft()).build());
+            connObjectTO.getAttrs().add(new AttrTO.Builder(Uid.NAME).
+                    value(attrs.getLeft()).build());
         }
 
         return connObjectTO;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
index 6b14f25..febaffe 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
@@ -94,7 +94,7 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
         WorkflowResult<String> created = gwfAdapter.create(groupCR);
 
         // see ConnObjectUtils#getAnyTOFromConnObject for GroupOwnerSchema
-        groupCR.getPlainAttrs().stream().filter(attr -> StringUtils.EMPTY.equals(attr.getSchema())).findFirst().
+        groupCR.getPlainAttr(StringUtils.EMPTY).
                 ifPresent(groupOwner -> groupOwnerMap.put(created.getResult(), groupOwner.getValues().get(0)));
 
         List<PropagationTaskInfo> tasks = propagationManager.getCreateTasks(
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index 33077fe..b246830 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -802,7 +802,7 @@ public class MappingManagerImpl implements MappingManager {
                         anyTO.getPlainAttrs().add(attrTO);
                     } else {
                         MembershipTO membership = groupableTO.getMembership(group.getKey()).orElseGet(() -> {
-                            MembershipTO newMemb = new MembershipTO.Builder().group(group.getKey()).build();
+                            MembershipTO newMemb = new MembershipTO.Builder(group.getKey()).build();
                             groupableTO.getMemberships().add(newMemb);
                             return newMemb;
                         });
@@ -818,7 +818,7 @@ public class MappingManagerImpl implements MappingManager {
                         anyTO.getDerAttrs().add(attrTO);
                     } else {
                         MembershipTO membership = groupableTO.getMembership(group.getKey()).orElseGet(() -> {
-                            MembershipTO newMemb = new MembershipTO.Builder().group(group.getKey()).build();
+                            MembershipTO newMemb = new MembershipTO.Builder(group.getKey()).build();
                             groupableTO.getMemberships().add(newMemb);
                             return newMemb;
                         });
@@ -841,7 +841,7 @@ public class MappingManagerImpl implements MappingManager {
                         anyTO.getVirAttrs().add(attrTO);
                     } else {
                         MembershipTO membership = groupableTO.getMembership(group.getKey()).orElseGet(() -> {
-                            MembershipTO newMemb = new MembershipTO.Builder().group(group.getKey()).build();
+                            MembershipTO newMemb = new MembershipTO.Builder(group.getKey()).build();
                             groupableTO.getMemberships().add(newMemb);
                             return newMemb;
                         });
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index c33e9db..5612a49 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -553,17 +553,16 @@ abstract class AbstractAnyDataBinder {
         anyTO.getAuxClasses().addAll(auxClasses.stream().map(Entity::getKey).collect(Collectors.toList()));
 
         plainAttrs.forEach(plainAttr -> {
-            anyTO.getPlainAttrs().add(new AttrTO.Builder().
-                    schema(plainAttr.getSchema().getKey()).
+            anyTO.getPlainAttrs().add(new AttrTO.Builder(plainAttr.getSchema().getKey()).
                     values(plainAttr.getValuesAsStrings()).build());
         });
 
         derAttrs.forEach((schema, value) -> {
-            anyTO.getDerAttrs().add(new AttrTO.Builder().schema(schema.getKey()).value(value).build());
+            anyTO.getDerAttrs().add(new AttrTO.Builder(schema.getKey()).value(value).build());
         });
 
         virAttrs.forEach((schema, values) -> {
-            anyTO.getVirAttrs().add(new AttrTO.Builder().schema(schema.getKey()).values(values).build());
+            anyTO.getVirAttrs().add(new AttrTO.Builder(schema.getKey()).values(values).build());
         });
 
         anyTO.getResources().addAll(resources.stream().map(Entity::getKey).collect(Collectors.toSet()));
@@ -581,27 +580,24 @@ abstract class AbstractAnyDataBinder {
             final Map<VirSchema, List<String>> virAttrs,
             final Membership<? extends Any<?>> membership) {
 
-        MembershipTO membershipTO = new MembershipTO.Builder().
-                group(membership.getRightEnd().getKey(), membership.getRightEnd().getName()).
+        MembershipTO membershipTO = new MembershipTO.Builder(membership.getRightEnd().getKey()).
+                groupName(membership.getRightEnd().getName()).
                 build();
 
         plainAttrs.forEach(plainAttr -> {
-            membershipTO.getPlainAttrs().add(new AttrTO.Builder().
-                    schema(plainAttr.getSchema().getKey()).
+            membershipTO.getPlainAttrs().add(new AttrTO.Builder(plainAttr.getSchema().getKey()).
                     values(plainAttr.getValuesAsStrings()).
                     build());
         });
 
         derAttrs.forEach((schema, value) -> {
-            membershipTO.getDerAttrs().add(new AttrTO.Builder().
-                    schema(schema.getKey()).
+            membershipTO.getDerAttrs().add(new AttrTO.Builder(schema.getKey()).
                     value(value).
                     build());
         });
 
         virAttrs.forEach((schema, values) -> {
-            membershipTO.getVirAttrs().add(new AttrTO.Builder().
-                    schema(schema.getKey()).
+            membershipTO.getVirAttrs().add(new AttrTO.Builder(schema.getKey()).
                     values(values).
                     build());
         });
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
index 02325d6..9c5634f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -121,11 +121,9 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
             // dynamic memberships
             anyObjectTO.getDynMemberships().addAll(
-                    anyObjectDAO.findDynGroups(anyObject.getKey()).stream().map(group -> {
-                        return new MembershipTO.Builder().
-                                group(group.getKey(), group.getName()).
-                                build();
-                    }).collect(Collectors.toList()));
+                    anyObjectDAO.findDynGroups(anyObject.getKey()).stream().
+                            map(group -> new MembershipTO.Builder(group.getKey()).groupName(group.getName()).build()).
+                            collect(Collectors.toList()));
         }
 
         return anyObjectTO;
@@ -387,7 +385,7 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
                                 newAttr.setSchema(schema);
                                 anyObject.add(newAttr);
 
-                                AttrPatch patch = new AttrPatch.Builder().attrTO(attrTO).build();
+                                AttrPatch patch = new AttrPatch.Builder(attrTO).build();
                                 processAttrPatch(
                                         anyObject, patch, schema, newAttr, anyUtils,
                                         resources, propByRes, invalidValues);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
index fbe700d..c0db08f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
@@ -53,8 +53,7 @@ public class ConfigurationDataBinderImpl extends AbstractAnyDataBinder implement
 
     @Override
     public AttrTO getAttrTO(final CPlainAttr attr) {
-        return new AttrTO.Builder().
-                schema(attr.getSchema().getKey()).
+        return new AttrTO.Builder(attr.getSchema().getKey()).
                 values(attr.getValuesAsStrings()).
                 build();
     }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index 79e7e03..1bc5265 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -460,7 +460,7 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
                                 attr.setSchema(schema);
                                 user.add(attr);
 
-                                AttrPatch patch = new AttrPatch.Builder().attrTO(attrTO).build();
+                                AttrPatch patch = new AttrPatch.Builder(attrTO).build();
                                 processAttrPatch(
                                         user, patch, schema, attr, anyUtils,
                                         resources, propByRes, invalidValues);
@@ -630,11 +630,9 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
 
             // dynamic memberships
             userTO.getDynMemberships().addAll(
-                    userDAO.findDynGroups(user.getKey()).stream().map(group -> {
-                        return new MembershipTO.Builder().
-                                group(group.getKey(), group.getName()).
-                                build();
-                    }).collect(Collectors.toList()));
+                    userDAO.findDynGroups(user.getKey()).stream().
+                            map(group -> new MembershipTO.Builder(group.getKey()).groupName(group.getName()).build()).
+                            collect(Collectors.toList()));
         }
 
         return userTO;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
index 4fca9f2..7e044de 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
@@ -74,10 +74,9 @@ public class SetUMembershipsJob extends AbstractInterruptableJob {
                     groups.forEach(group -> {
                         Set<String> before = membershipsBefore.get(user);
                         if (before == null || !before.contains(group)) {
-                            userUR.getMemberships().add(new MembershipUR.Builder().
-                                            operation(PatchOperation.ADD_REPLACE).
-                                            group(group).
-                                            build());
+                            userUR.getMemberships().add(new MembershipUR.Builder(group).
+                                    operation(PatchOperation.ADD_REPLACE).
+                                    build());
                         }
                     });
                 });
@@ -86,7 +85,7 @@ public class SetUMembershipsJob extends AbstractInterruptableJob {
                     UserUR userUR = updateReqs.stream().
                             filter(req -> user.equals(req.getKey())).findFirst().
                             orElseGet(() -> {
-                                UserUR req = new UserUR.Builder().key(user).build();
+                                UserUR req = new UserUR.Builder(user).build();
                                 updateReqs.add(req);
                                 return req;
                             });
@@ -94,10 +93,9 @@ public class SetUMembershipsJob extends AbstractInterruptableJob {
                     groups.forEach(group -> {
                         Set<String> after = membershipsAfter.get(user);
                         if (after == null || !after.contains(group)) {
-                            userUR.getMemberships().add(new MembershipUR.Builder().
-                                            operation(PatchOperation.DELETE).
-                                            group(group).
-                                            build());
+                            userUR.getMemberships().add(new MembershipUR.Builder(group).
+                                    operation(PatchOperation.DELETE).
+                                    build());
                         }
                     });
                 });
diff --git a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/MailTemplateTest.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/MailTemplateTest.java
index ea1f551..494d824 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/MailTemplateTest.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/MailTemplateTest.java
@@ -99,10 +99,10 @@ public class MailTemplateTest extends AbstractTest {
         String username = "test" + UUID.randomUUID().toString();
         UserTO user = new UserTO();
         user.setUsername(username);
-        user.getPlainAttrs().add(new AttrTO.Builder().schema("firstname").value("John").build());
-        user.getPlainAttrs().add(new AttrTO.Builder().schema("surname").value("Doe").build());
-        user.getPlainAttrs().add(new AttrTO.Builder().schema("email").value("john.doe@syncope.apache.org").build());
-        user.getMemberships().add(new MembershipTO.Builder().group(UUID.randomUUID().toString(), "a group").build());
+        user.getPlainAttrs().add(new AttrTO.Builder("firstname").value("John").build());
+        user.getPlainAttrs().add(new AttrTO.Builder("surname").value("Doe").build());
+        user.getPlainAttrs().add(new AttrTO.Builder("email").value("john.doe@syncope.apache.org").build());
+        user.getMemberships().add(new MembershipTO.Builder(UUID.randomUUID().toString()).groupName("a group").build());
         ctx.put("user", user);
 
         String token = "token " + UUID.randomUUID().toString();
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
index 3277109..19a4862 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
@@ -174,7 +174,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, CR extends AnyCR, UR
                 break;
 
             case PLAIN:
-                updateReq.getPlainAttrs().add(new AttrPatch.Builder().operation(operation).attrTO(attrTO).build());
+                updateReq.getPlainAttrs().add(new AttrPatch.Builder(attrTO).operation(operation).build());
                 break;
 
             case DERIVED:
@@ -196,7 +196,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, CR extends AnyCR, UR
         addUpdateOrReplaceAttr(
                 getActualKey(getAnyDAO(), key),
                 schemaType,
-                new AttrTO.Builder().schema(schema).build(),
+                new AttrTO.Builder(schema).build(),
                 PatchOperation.DELETE);
     }
 
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
index 7660562..2b1f4cf 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AnyObjectServiceImpl.java
@@ -59,7 +59,7 @@ public class AnyObjectServiceImpl extends AbstractAnyService<AnyObjectTO, AnyObj
 
     @Override
     protected AnyObjectUR newUpdateReq(final String key) {
-        return new AnyObjectUR.Builder().key(key).build();
+        return new AnyObjectUR.Builder(key).build();
     }
 
     @Override
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
index 855dd87..eedafba 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
@@ -55,7 +55,7 @@ public class GroupServiceImpl extends AbstractAnyService<GroupTO, GroupCR, Group
 
     @Override
     protected GroupUR newUpdateReq(final String key) {
-        return new GroupUR.Builder().key(key).build();
+        return new GroupUR.Builder(key).build();
     }
 
     @Override
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
index 79d4023..6daf501 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
@@ -54,7 +54,7 @@ public class UserServiceImpl extends AbstractAnyService<UserTO, UserCR, UserUR>
 
     @Override
     protected UserUR newUpdateReq(final String key) {
-        return new UserUR.Builder().key(key).build();
+        return new UserUR.Builder(key).build();
     }
 
     @Override
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/producer/SuspendProducer.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/producer/SuspendProducer.java
index 646fe36..74b11f7 100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/producer/SuspendProducer.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/producer/SuspendProducer.java
@@ -42,13 +42,13 @@ public class SuspendProducer extends AbstractProducer {
                     (Pair<WorkflowResult<String>, Boolean>) exchange.getIn().getBody();
 
             // propagate suspension if and only if it is required by policy
-            if (updated != null && updated.getValue()) {
-                UserUR userUR = new UserUR.Builder().key(updated.getKey().getResult()).build();
+            if (updated != null && updated.getRight()) {
+                UserUR userUR = new UserUR.Builder(updated.getLeft().getResult()).build();
 
                 List<PropagationTaskInfo> taskInfos = getPropagationManager().getUserUpdateTasks(
                         new WorkflowResult<>(
                                 Pair.of(userUR, Boolean.FALSE),
-                                updated.getKey().getPropByRes(), updated.getKey().getPerformedTasks()));
+                                updated.getLeft().getPropByRes(), updated.getLeft().getPerformedTasks()));
                 getPropagationTaskExecutor().execute(taskInfos, false);
             }
         }
diff --git a/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/task/PasswordReset.java b/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/task/PasswordReset.java
index 2d431f2..55ded95 100644
--- a/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/task/PasswordReset.java
+++ b/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/task/PasswordReset.java
@@ -51,7 +51,7 @@ public class PasswordReset extends FlowableServiceTask {
 
         user.removeToken();
 
-        UserUR req = new UserUR.Builder().key(user.getKey()).
+        UserUR req = new UserUR.Builder(user.getKey()).
                 password(new PasswordPatch.Builder().
                         onSyncope(true).
                         resources(userDAO.findAllResourceKeys(user.getKey())).
diff --git a/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowTaskLogic.java b/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowTaskLogic.java
index 5e5fbcf..77decd6 100644
--- a/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowTaskLogic.java
+++ b/ext/flowable/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowTaskLogic.java
@@ -69,7 +69,7 @@ public class UserWorkflowTaskLogic extends AbstractTransactionalLogic<EntityTO>
     public UserTO executeNextTask(final WorkflowTaskExecInput workflowTaskExecInput) {
         WorkflowResult<String> updated = wfTaskManager.executeNextTask(workflowTaskExecInput);
 
-        UserUR userUR = new UserUR.Builder().key(updated.getResult()).build();
+        UserUR userUR = new UserUR.Builder(updated.getResult()).build();
 
         List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(new WorkflowResult<>(
                 Pair.<UserUR, Boolean>of(userUR, null),
diff --git a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
index 7bb26c1..d793582 100644
--- a/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
+++ b/ext/oidcclient/agent/src/main/java/org/apache/syncope/ext/oidcclient/agent/CodeConsumer.java
@@ -66,8 +66,7 @@ public class CodeConsumer extends HttpServlet {
                         authorizationCode,
                         request.getSession().getAttribute(OIDCConstants.OP).toString());
                 if (responseTO.isSelfReg()) {
-                    responseTO.getAttrs().add(
-                            new AttrTO.Builder().schema("username").values(responseTO.getUsername()).build());
+                    responseTO.getAttrs().add(new AttrTO.Builder("username").values(responseTO.getUsername()).build());
                     request.getSession(true).
                             setAttribute(Constants.OIDCCLIENT_USER_ATTRS, MAPPER.writeValueAsString(responseTO.
                                     getAttrs()));
diff --git a/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/oidc/OIDCUserManager.java b/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/oidc/OIDCUserManager.java
index 2df0dfd..f30fb80 100644
--- a/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/oidc/OIDCUserManager.java
+++ b/ext/oidcclient/logic/src/main/java/org/apache/syncope/core/logic/oidc/OIDCUserManager.java
@@ -225,7 +225,7 @@ public class OIDCUserManager {
                         if (attr.isPresent()) {
                             attr.get().getValues().clear();
                         } else {
-                            attr = Optional.of(new AttrTO.Builder().schema(intAttrName.getSchemaName()).build());
+                            attr = Optional.of(new AttrTO.Builder(intAttrName.getSchemaName()).build());
                             userTO.getPlainAttrs().add(attr.get());
                         }
                         attr.get().getValues().addAll(values);
diff --git a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
index aae650b..78d071c 100644
--- a/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
+++ b/ext/saml2sp/agent/src/main/java/org/apache/syncope/ext/saml2lsp/agent/AssertionConsumer.java
@@ -56,8 +56,7 @@ public class AssertionConsumer extends AbstractSAML2SPServlet {
                             request.getInputStream()));
 
             if (responseTO.isSelfReg()) {
-                responseTO.getAttrs().add(
-                        new AttrTO.Builder().schema("username").values(responseTO.getUsername()).build());
+                responseTO.getAttrs().add(new AttrTO.Builder("username").values(responseTO.getUsername()).build());
                 request.getSession(true).
                         setAttribute(Constants.SAML2SP_USER_ATTRS, MAPPER.writeValueAsString(responseTO.getAttrs()));
 
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2UserManager.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2UserManager.java
index 7cc36e2..ff27083 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2UserManager.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2UserManager.java
@@ -239,7 +239,7 @@ public class SAML2UserManager {
                         if (attr.isPresent()) {
                             attr.get().getValues().clear();
                         } else {
-                            attr = Optional.of(new AttrTO.Builder().schema(intAttrName.getSchemaName()).build());
+                            attr = Optional.of(new AttrTO.Builder(intAttrName.getSchemaName()).build());
                             userTO.getPlainAttrs().add(attr.get());
                         }
                         attr.get().getValues().addAll(values);
diff --git a/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMDataBinder.java b/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMDataBinder.java
index bf122d5..cc67e72 100644
--- a/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMDataBinder.java
+++ b/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/SCIMDataBinder.java
@@ -162,7 +162,7 @@ public class SCIMDataBinder {
         attrs.putAll(EntityTOUtils.buildAttrMap(userTO.getPlainAttrs()));
         attrs.putAll(EntityTOUtils.buildAttrMap(userTO.getDerAttrs()));
         attrs.putAll(EntityTOUtils.buildAttrMap(userTO.getVirAttrs()));
-        attrs.put("username", new AttrTO.Builder().schema("username").value(userTO.getUsername()).build());
+        attrs.put("username", new AttrTO.Builder("username").value(userTO.getUsername()).build());
 
         if (conf.getUserConf() != null) {
             if (output(attributes, excludedAttributes, "name") && conf.getUserConf().getName() != null) {
@@ -433,7 +433,7 @@ public class SCIMDataBinder {
                 confs.stream().
                         filter(object -> value.getType().equals(object.getType().name())).findFirst().
                         ifPresent(conf -> attrs.add(
-                        new AttrTO.Builder().schema(conf.getValue()).value(value.getValue()).build()));
+                        new AttrTO.Builder(conf.getValue()).value(value.getValue()).build()));
             }
         });
     }
@@ -597,7 +597,7 @@ public class SCIMDataBinder {
         }
 
         userTO.getMemberships().addAll(user.getGroups().stream().
-                map(group -> new MembershipTO.Builder().group(group.getValue()).build()).
+                map(group -> new MembershipTO.Builder(group.getValue()).build()).
                 collect(Collectors.toList()));
 
         userTO.getRoles().addAll(user.getRoles().stream().
@@ -609,15 +609,9 @@ public class SCIMDataBinder {
 
     public UserCR toUserCR(final SCIMUser user) {
         UserTO userTO = toUserTO(user);
-
-        return new UserCR.Builder().
-                username(userTO.getUsername()).
-                password(userTO.getPassword()).
-                realm(userTO.getRealm()).
-                plainAttrs(userTO.getPlainAttrs()).
-                memberships(userTO.getMemberships()).
-                roles(userTO.getRoles()).
-                build();
+        UserCR userCR = new UserCR();
+        EntityTOUtils.toAnyCR(userTO, userCR);
+        return userCR;
     }
 
     private void setAttribute(final UserTO userTO, final String schema, final String value) {
@@ -627,7 +621,7 @@ public class SCIMDataBinder {
                 break;
 
             default:
-                userTO.getPlainAttrs().add(new AttrTO.Builder().schema(schema).value(value).build());
+                userTO.getPlainAttrs().add(new AttrTO.Builder(schema).value(value).build());
         }
     }
 
@@ -695,6 +689,6 @@ public class SCIMDataBinder {
             throw new BadRequestException(ErrorType.invalidValue);
         }
 
-        return new GroupCR.Builder().realm(SyncopeConstants.ROOT_REALM).name(group.getDisplayName()).build();
+        return new GroupCR.Builder(SyncopeConstants.ROOT_REALM, group.getDisplayName()).build();
     }
 }
diff --git a/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/scim/SCIMConfManager.java b/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/scim/SCIMConfManager.java
index 02ba142..08ddf21 100644
--- a/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/scim/SCIMConfManager.java
+++ b/ext/scimv2/logic/src/main/java/org/apache/syncope/core/logic/scim/SCIMConfManager.java
@@ -89,8 +89,7 @@ public class SCIMConfManager {
         conf.setGeneralConf(new SCIMGeneralConf());
         conf.getGeneralConf().setLastChangeDate(new Date());
 
-        configurationLogic.set(new AttrTO.Builder().
-                schema(SCIMConf.KEY).
+        configurationLogic.set(new AttrTO.Builder(SCIMConf.KEY).
                 value(Base64.getEncoder().encodeToString(POJOHelper.serialize(conf).getBytes())).
                 build());
     }
diff --git a/ext/scimv2/scim-rest-cxf/src/main/java/org/apache/syncope/ext/scimv2/cxf/service/GroupServiceImpl.java b/ext/scimv2/scim-rest-cxf/src/main/java/org/apache/syncope/ext/scimv2/cxf/service/GroupServiceImpl.java
index 0a7a747..cd7ceb3 100644
--- a/ext/scimv2/scim-rest-cxf/src/main/java/org/apache/syncope/ext/scimv2/cxf/service/GroupServiceImpl.java
+++ b/ext/scimv2/scim-rest-cxf/src/main/java/org/apache/syncope/ext/scimv2/cxf/service/GroupServiceImpl.java
@@ -57,10 +57,9 @@ public class GroupServiceImpl extends AbstractService<SCIMGroup> implements Grou
 
         // then assign members
         group.getMembers().forEach(member -> {
-            UserUR req = new UserUR.Builder().
-                    key(member.getValue()).
-                    membership(new MembershipUR.Builder().
-                            operation(PatchOperation.ADD_REPLACE).group(result.getEntity().getKey()).build()).
+            UserUR req = new UserUR.Builder(member.getValue()).
+                    membership(new MembershipUR.Builder(result.getEntity().getKey()).
+                            operation(PatchOperation.ADD_REPLACE).build()).
                     build();
             try {
                 userLogic().update(req, false);
@@ -136,10 +135,9 @@ public class GroupServiceImpl extends AbstractService<SCIMGroup> implements Grou
             afterMembers.add(member.getValue());
 
             if (!beforeMembers.contains(member.getValue())) {
-                UserUR req = new UserUR.Builder().
-                        key(member.getValue()).
-                        membership(new MembershipUR.Builder().
-                                operation(PatchOperation.ADD_REPLACE).group(result.getEntity().getKey()).build()).
+                UserUR req = new UserUR.Builder(member.getValue()).
+                        membership(new MembershipUR.Builder(result.getEntity().getKey()).
+                                operation(PatchOperation.ADD_REPLACE).build()).
                         build();
                 try {
                     userLogic().update(req, false);
@@ -151,10 +149,9 @@ public class GroupServiceImpl extends AbstractService<SCIMGroup> implements Grou
         });
         // remove unconfirmed members
         beforeMembers.stream().filter(member -> !afterMembers.contains(member)).forEach(user -> {
-            UserUR req = new UserUR.Builder().
-                    key(user).
-                    membership(new MembershipUR.Builder().
-                            operation(PatchOperation.DELETE).group(result.getEntity().getKey()).build()).
+            UserUR req = new UserUR.Builder(user).
+                    membership(new MembershipUR.Builder(result.getEntity().getKey()).
+                            operation(PatchOperation.DELETE).build()).
                     build();
             try {
                 userLogic().update(req, false);
diff --git a/fit/core-reference/src/main/java-all/org/apache/syncope/fit/core/reference/flowable/AssignDirectorGroup.java b/fit/core-reference/src/main/java-all/org/apache/syncope/fit/core/reference/flowable/AssignDirectorGroup.java
index a2fb529..f7dc233 100644
--- a/fit/core-reference/src/main/java-all/org/apache/syncope/fit/core/reference/flowable/AssignDirectorGroup.java
+++ b/fit/core-reference/src/main/java-all/org/apache/syncope/fit/core/reference/flowable/AssignDirectorGroup.java
@@ -50,8 +50,7 @@ public class AssignDirectorGroup extends FlowableServiceTask {
 
             UserUR userUR = new UserUR();
             userUR.setKey(user.getKey());
-            userUR.getMemberships().add(new MembershipUR.Builder().
-                    group("ebf97068-aa4b-4a85-9f01-680e8c4cf227").build());
+            userUR.getMemberships().add(new MembershipUR.Builder("ebf97068-aa4b-4a85-9f01-680e8c4cf227").build());
 
             PropagationByResource propByRes = dataBinder.update(user, userUR);
 
diff --git a/fit/core-reference/src/main/java-all/org/apache/syncope/fit/core/reference/flowable/CreateARelationship.java b/fit/core-reference/src/main/java-all/org/apache/syncope/fit/core/reference/flowable/CreateARelationship.java
index 1944255..20bfe19 100644
--- a/fit/core-reference/src/main/java-all/org/apache/syncope/fit/core/reference/flowable/CreateARelationship.java
+++ b/fit/core-reference/src/main/java-all/org/apache/syncope/fit/core/reference/flowable/CreateARelationship.java
@@ -53,9 +53,8 @@ public class CreateARelationship extends FlowableServiceTask {
 
             UserUR userUR = new UserUR();
             userUR.setKey(user.getKey());
-            userUR.getRelationships().add(new RelationshipUR.Builder().
-                    relationshipTO(new RelationshipTO.Builder().
-                            otherEnd("PRINTER", printer).type("neighborhood").build()).
+            userUR.getRelationships().add(new RelationshipUR.Builder(new RelationshipTO.Builder().
+                    otherEnd("PRINTER", printer).type("neighborhood").build()).
                     build());
 
             PropagationByResource propByRes = dataBinder.update(user, userUR);
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestPullActions.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestPullActions.java
index ab33943..f96f59c 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestPullActions.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/TestPullActions.java
@@ -79,9 +79,8 @@ public class TestPullActions implements PullActions {
             }
         }
         if (fullnamePatch == null) {
-            fullnamePatch = new AttrPatch.Builder().
+            fullnamePatch = new AttrPatch.Builder(new AttrTO.Builder("fullname").build()).
                     operation(PatchOperation.ADD_REPLACE).
-                    attrTO(new AttrTO.Builder().schema("fullname").build()).
                     build();
         }
 
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index 2d61758..bd8a027 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -354,11 +354,11 @@ public abstract class AbstractITCase {
     }
 
     protected static AttrTO attrTO(final String schema, final String value) {
-        return new AttrTO.Builder().schema(schema).value(value).build();
+        return new AttrTO.Builder(schema).value(value).build();
     }
 
     protected static AttrPatch attrAddReplacePatch(final String schema, final String value) {
-        return new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).attrTO(attrTO(schema, value)).build();
+        return new AttrPatch.Builder(attrTO(schema, value)).operation(PatchOperation.ADD_REPLACE).build();
     }
 
     public static <T> T getObject(final URI location, final Class<?> serviceClass, final Class<T> resultClass) {
@@ -439,8 +439,7 @@ public abstract class AbstractITCase {
 
         // 2. create user
         UserCR req = UserITCase.getUniqueSample("notificationtest@syncope.apache.org");
-        req.getMemberships().add(
-                new MembershipTO.Builder().group("bf825fe1-7320-4a54-bd64-143b5c18ab97").build());
+        req.getMemberships().add(new MembershipTO.Builder("bf825fe1-7320-4a54-bd64-143b5c18ab97").build());
 
         UserTO userTO = createUser(req).getEntity();
         assertNotNull(userTO);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
index 38fcc3d..472a3bd 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
@@ -48,9 +48,7 @@ import org.junit.jupiter.api.Test;
 public class AnyObjectITCase extends AbstractITCase {
 
     public static AnyObjectCR getSample(final String location) {
-        return new AnyObjectCR.Builder("PRINTER").
-                name(location + getUUIDString()).
-                realm(SyncopeConstants.ROOT_REALM).
+        return new AnyObjectCR.Builder(SyncopeConstants.ROOT_REALM, "PRINTER", location + getUUIDString()).
                 plainAttr(attrTO("location", location + getUUIDString())).
                 resource(RESOURCE_NAME_DBSCRIPTED).
                 build();
@@ -77,8 +75,7 @@ public class AnyObjectITCase extends AbstractITCase {
         // 1. create anyObject in realm /odd and attempt to assign group 15, from realm /even => exception
         AnyObjectCR anyObjectCR = getSample("createInvalidMembership");
         anyObjectCR.setRealm("/odd");
-        anyObjectCR.getMemberships().add(
-                new MembershipTO.Builder().group("034740a9-fa10-453b-af37-dc7897e98fb1").build());
+        anyObjectCR.getMemberships().add(new MembershipTO.Builder("034740a9-fa10-453b-af37-dc7897e98fb1").build());
 
         try {
             createAnyObject(anyObjectCR);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
index 3a167f5..749f453 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
@@ -481,8 +481,7 @@ public class AuthenticationITCase extends AbstractITCase {
         // 1. create user with group 'groupForWorkflowApproval' 
         // (users with group groupForWorkflowApproval are defined in workflow as subject to approval)
         UserCR userCR = UserITCase.getUniqueSample("createWithReject@syncope.apache.org");
-        userCR.getMemberships().add(
-                new MembershipTO.Builder().group("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
 
         UserTO userTO = createUser(userCR).getEntity();
         assertNotNull(userTO);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConfigurationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConfigurationITCase.java
index c6a3438..77f6df0 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConfigurationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ConfigurationITCase.java
@@ -53,7 +53,7 @@ public class ConfigurationITCase extends AbstractITCase {
         testKey.setType(AttrSchemaType.String);
         createSchema(SchemaType.PLAIN, testKey);
 
-        AttrTO conf = new AttrTO.Builder().schema(testKey.getKey()).value("testValue").build();
+        AttrTO conf = new AttrTO.Builder(testKey.getKey()).value("testValue").build();
 
         configurationService.set(conf);
 
@@ -69,7 +69,7 @@ public class ConfigurationITCase extends AbstractITCase {
         testKey.setMandatoryCondition("true");
         createSchema(SchemaType.PLAIN, testKey);
 
-        AttrTO conf = new AttrTO.Builder().schema(testKey.getKey()).build();
+        AttrTO conf = new AttrTO.Builder(testKey.getKey()).build();
         try {
             configurationService.set(conf);
             fail("This should not happen");
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
index a8bf513..2c0cc5e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/DynRealmITCase.java
@@ -197,7 +197,7 @@ public class DynRealmITCase extends AbstractITCase {
             // GROUP_UPDATE
             GroupUR groupUR = new GroupUR();
             groupUR.setKey(groupKey);
-            groupUR.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO("icon", "modified")).build());
+            groupUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("icon", "modified")).build());
             group = delegatedGroupService.update(groupUR).readEntity(new GenericType<ProvisioningResult<GroupTO>>() {
             }).getEntity();
             assertNotNull(group);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java
index c5221ed..58a55f8 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java
@@ -99,10 +99,7 @@ import org.junit.jupiter.api.Test;
 public class GroupITCase extends AbstractITCase {
 
     public static GroupCR getBasicSample(final String name) {
-        return new GroupCR.Builder().
-                realm(SyncopeConstants.ROOT_REALM).
-                name(name + getUUIDString()).
-                build();
+        return new GroupCR.Builder(SyncopeConstants.ROOT_REALM, name + getUUIDString()).build();
     }
 
     public static GroupCR getSample(final String name) {
@@ -238,9 +235,9 @@ public class GroupITCase extends AbstractITCase {
 
         groupTO.getPlainAttr("show").get().getValues().clear();
 
-        groupUR = new GroupUR.Builder().key(groupTO.getKey()).
-                plainAttr(new AttrPatch.Builder().operation(PatchOperation.DELETE).
-                        attrTO(new AttrTO.Builder().schema("show").build()).build()).build();
+        groupUR = new GroupUR.Builder(groupTO.getKey()).
+                plainAttr(new AttrPatch.Builder(new AttrTO.Builder("show").build()).
+                        operation(PatchOperation.DELETE).build()).build();
 
         groupTO = updateGroup(groupUR).getEntity();
 
@@ -257,11 +254,11 @@ public class GroupITCase extends AbstractITCase {
 
         GroupTO created = createGroup(createReq).getEntity();
 
-        created.getPlainAttrs().add(new AttrTO.Builder().schema("icon").build());
-        created.getPlainAttrs().add(new AttrTO.Builder().schema("show").build());
-        created.getPlainAttrs().add(new AttrTO.Builder().schema("rderived_sx").value("sx").build());
-        created.getPlainAttrs().add(new AttrTO.Builder().schema("rderived_dx").value("dx").build());
-        created.getPlainAttrs().add(new AttrTO.Builder().schema("title").value("mr").build());
+        created.getPlainAttrs().add(new AttrTO.Builder("icon").build());
+        created.getPlainAttrs().add(new AttrTO.Builder("show").build());
+        created.getPlainAttrs().add(new AttrTO.Builder("rderived_sx").value("sx").build());
+        created.getPlainAttrs().add(new AttrTO.Builder("rderived_dx").value("dx").build());
+        created.getPlainAttrs().add(new AttrTO.Builder("title").value("mr").build());
 
         GroupTO original = groupService.read(created.getKey());
 
@@ -696,9 +693,8 @@ public class GroupITCase extends AbstractITCase {
         // verify that the condition is dynamically applied
         AnyObjectUR anyObjectUR = new AnyObjectUR();
         anyObjectUR.setKey(newAny.getKey());
-        anyObjectUR.getPlainAttrs().add(new AttrPatch.Builder().
+        anyObjectUR.getPlainAttrs().add(new AttrPatch.Builder(new AttrTO.Builder("location").build()).
                 operation(PatchOperation.DELETE).
-                attrTO(new AttrTO.Builder().schema("location").build()).
                 build());
         newAny = updateAnyObject(anyObjectUR).getEntity();
         assertFalse(newAny.getPlainAttr("location").isPresent());
@@ -725,7 +721,7 @@ public class GroupITCase extends AbstractITCase {
         printerCR.setRealm(SyncopeConstants.ROOT_REALM);
         printerCR.setName("Printer_" + getUUIDString());
         printerCR.setType("PRINTER");
-        printerCR.getPlainAttrs().add(new AttrTO.Builder().schema("location").value("home").build());
+        printerCR.getPlainAttrs().add(new AttrTO.Builder("location").value("home").build());
         AnyObjectTO printer = createAnyObject(printerCR).getEntity();
 
         group = groupService.read(group.getKey());
@@ -746,7 +742,7 @@ public class GroupITCase extends AbstractITCase {
         printerCR.setRealm(SyncopeConstants.ROOT_REALM);
         printerCR.setName("Printer_" + getUUIDString());
         printerCR.setType("PRINTER");
-        printerCR.getMemberships().add(new MembershipTO.Builder().group(group.getKey()).build());
+        printerCR.getMemberships().add(new MembershipTO.Builder(group.getKey()).build());
         AnyObjectTO printer = createAnyObject(printerCR).getEntity();
 
         group = groupService.read(group.getKey());
@@ -787,8 +783,8 @@ public class GroupITCase extends AbstractITCase {
             // 2. update succeeds
             GroupUR groupUR = new GroupUR();
             groupUR.setKey(group.getKey());
-            groupUR.getPlainAttrs().add(new AttrPatch.Builder().
-                    operation(PatchOperation.ADD_REPLACE).attrTO(attrTO("title", "second")).build());
+            groupUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("title", "second")).
+                    operation(PatchOperation.ADD_REPLACE).build());
 
             result = updateGroup(groupUR);
             assertNotNull(result);
@@ -809,8 +805,8 @@ public class GroupITCase extends AbstractITCase {
             // 4. update succeeds again
             groupUR = new GroupUR();
             groupUR.setKey(group.getKey());
-            groupUR.getPlainAttrs().add(new AttrPatch.Builder().
-                    operation(PatchOperation.ADD_REPLACE).attrTO(attrTO("title", "third")).build());
+            groupUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("title", "third")).
+                    operation(PatchOperation.ADD_REPLACE).build());
 
             result = updateGroup(groupUR);
             assertNotNull(result);
@@ -831,8 +827,8 @@ public class GroupITCase extends AbstractITCase {
             // 6. update now fails
             groupUR = new GroupUR();
             groupUR.setKey(group.getKey());
-            groupUR.getPlainAttrs().add(new AttrPatch.Builder().
-                    operation(PatchOperation.ADD_REPLACE).attrTO(attrTO("title", "fourth")).build());
+            groupUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("title", "fourth")).
+                    operation(PatchOperation.ADD_REPLACE).build());
 
             result = updateGroup(groupUR);
             assertNotNull(result);
@@ -886,7 +882,7 @@ public class GroupITCase extends AbstractITCase {
 
         // 2. create user with such group assigned
         UserCR userCR = UserITCase.getUniqueSample("forProvision@syncope.apache.org");
-        userCR.getMemberships().add(new MembershipTO.Builder().group(groupTO.getKey()).build());
+        userCR.getMemberships().add(new MembershipTO.Builder(groupTO.getKey()).build());
         UserTO userTO = createUser(userCR).getEntity();
 
         // 3. modify the group by assiging the LDAP resource
@@ -1103,7 +1099,7 @@ public class GroupITCase extends AbstractITCase {
         // 5. modify group with new double value
         GroupUR groupUR = new GroupUR();
         groupUR.setKey(groupTO.getKey());
-        groupUR.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO(doubleSchemaName, "11.257")).build());
+        groupUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO(doubleSchemaName, "11.257")).build());
 
         groupTO = updateGroup(groupUR).getEntity();
         assertNotNull(groupTO);
@@ -1116,7 +1112,7 @@ public class GroupITCase extends AbstractITCase {
         // 7. modify group with new double value, verify that no pattern is applied
         groupUR = new GroupUR();
         groupUR.setKey(groupTO.getKey());
-        groupUR.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO(doubleSchemaName, "11.23")).build());
+        groupUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO(doubleSchemaName, "11.23")).build());
 
         groupTO = updateGroup(groupUR).getEntity();
         assertNotNull(groupTO);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
index 6a2bd53..faaa15c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
@@ -69,16 +69,16 @@ public class MembershipITCase extends AbstractITCase {
     public void misc() {
         UserCR userCR = UserITCase.getUniqueSample("memb@apache.org");
         userCR.setRealm("/even/two");
-        userCR.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1976").build());
+        userCR.getPlainAttrs().add(new AttrTO.Builder("aLong").value("1976").build());
         userCR.getPlainAttrs().removeIf(attr -> "ctype".equals(attr.getSchema()));
 
         // the group 034740a9-fa10-453b-af37-dc7897e98fb1 has USER type extensions for 'csv' and 'other' 
         // any type classes
-        MembershipTO membership = new MembershipTO.Builder().group("034740a9-fa10-453b-af37-dc7897e98fb1").build();
-        membership.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1977").build());
+        MembershipTO membership = new MembershipTO.Builder("034740a9-fa10-453b-af37-dc7897e98fb1").build();
+        membership.getPlainAttrs().add(new AttrTO.Builder("aLong").value("1977").build());
 
         // 'fullname' is in 'minimal user', so it is not allowed for this membership
-        membership.getPlainAttrs().add(new AttrTO.Builder().schema("fullname").value("discarded").build());
+        membership.getPlainAttrs().add(new AttrTO.Builder("fullname").value("discarded").build());
 
         userCR.getMemberships().add(membership);
 
@@ -116,14 +116,14 @@ public class MembershipITCase extends AbstractITCase {
             UserUR userUR = new UserUR();
             userUR.setKey(userTO.getKey());
 
-            userUR.getPlainAttrs().add(new AttrPatch.Builder().
-                    attrTO(new AttrTO.Builder().schema("aLong").value("1977").build()).build());
+            userUR.getPlainAttrs().
+                    add(new AttrPatch.Builder(new AttrTO.Builder("aLong").value("1977").build()).build());
 
-            MembershipUR membershipPatch = new MembershipUR.Builder().group(membership.getGroupKey()).build();
+            MembershipUR membershipPatch = new MembershipUR.Builder(membership.getGroupKey()).build();
             membershipPatch.getPlainAttrs().add(
-                    new AttrTO.Builder().schema("aLong").value("1976").build());
+                    new AttrTO.Builder("aLong").value("1976").build());
             membershipPatch.getPlainAttrs().add(
-                    new AttrTO.Builder().schema("ctype").value("membership type").build());
+                    new AttrTO.Builder("ctype").value("membership type").build());
             userUR.getMemberships().add(membershipPatch);
 
             userTO = updateUser(userUR).getEntity();
@@ -147,7 +147,7 @@ public class MembershipITCase extends AbstractITCase {
             userUR = new UserUR();
             userUR.setKey(userTO.getKey());
 
-            membershipPatch = new MembershipUR.Builder().group(membership.getGroupKey()).
+            membershipPatch = new MembershipUR.Builder(membership.getGroupKey()).
                     operation(PatchOperation.DELETE).build();
             userUR.getMemberships().add(membershipPatch);
 
@@ -165,10 +165,10 @@ public class MembershipITCase extends AbstractITCase {
     public void deleteUserWithMembership() {
         UserCR userCR = UserITCase.getUniqueSample("memb@apache.org");
         userCR.setRealm("/even/two");
-        userCR.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1976").build());
+        userCR.getPlainAttrs().add(new AttrTO.Builder("aLong").value("1976").build());
 
-        MembershipTO membership = new MembershipTO.Builder().group("034740a9-fa10-453b-af37-dc7897e98fb1").build();
-        membership.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1977").build());
+        MembershipTO membership = new MembershipTO.Builder("034740a9-fa10-453b-af37-dc7897e98fb1").build();
+        membership.getPlainAttrs().add(new AttrTO.Builder("aLong").value("1977").build());
         userCR.getMemberships().add(membership);
 
         UserTO user = createUser(userCR).getEntity();
@@ -193,8 +193,8 @@ public class MembershipITCase extends AbstractITCase {
         // pre: create user with membership to such group
         UserCR userCR = UserITCase.getUniqueSample("typeExt@apache.org");
 
-        MembershipTO membership = new MembershipTO.Builder().group(groupTO.getKey()).build();
-        membership.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1454").build());
+        MembershipTO membership = new MembershipTO.Builder(groupTO.getKey()).build();
+        membership.getPlainAttrs().add(new AttrTO.Builder("aLong").value("1454").build());
         userCR.getMemberships().add(membership);
 
         UserTO user = createUser(userCR).getEntity();
@@ -248,8 +248,8 @@ public class MembershipITCase extends AbstractITCase {
             userCR.getResources().clear();
             userCR.getResources().add(newResource.getKey());
 
-            MembershipTO membership = new MembershipTO.Builder().group("034740a9-fa10-453b-af37-dc7897e98fb1").build();
-            membership.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("5432").build());
+            MembershipTO membership = new MembershipTO.Builder("034740a9-fa10-453b-af37-dc7897e98fb1").build();
+            membership.getPlainAttrs().add(new AttrTO.Builder("aLong").value("5432").build());
             userCR.getMemberships().add(membership);
 
             user = createUser(userCR).getEntity();
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PlainSchemaITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PlainSchemaITCase.java
index 2b2fb84..926730b 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PlainSchemaITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PlainSchemaITCase.java
@@ -187,10 +187,10 @@ public class PlainSchemaITCase extends AbstractITCase {
         UserUR userUR = new UserUR();
         userUR.setKey(userTO.getKey());
         // validation OK - application/pdf -> application/pdf
-        userUR.getPlainAttrs().add(new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                attrTO(attrTO("BinaryPDF",
-                        Base64.getEncoder().encodeToString(
-                                IOUtils.readBytesFromStream(getClass().getResourceAsStream("/test.pdf"))))).
+        userUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("BinaryPDF",
+                Base64.getEncoder().encodeToString(
+                        IOUtils.readBytesFromStream(getClass().getResourceAsStream("/test.pdf"))))).
+                operation(PatchOperation.ADD_REPLACE).
                 build());
 
         updateUser(userUR);
@@ -200,10 +200,10 @@ public class PlainSchemaITCase extends AbstractITCase {
         userUR.setKey(userTO.getKey());
         // validation KO - text/html -> application/pdf
         try {
-            userUR.getPlainAttrs().add(new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                    attrTO(attrTO("BinaryPDF",
-                            Base64.getEncoder().encodeToString(
-                                    IOUtils.readBytesFromStream(getClass().getResourceAsStream("/test.html"))))).
+            userUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("BinaryPDF",
+                    Base64.getEncoder().encodeToString(
+                            IOUtils.readBytesFromStream(getClass().getResourceAsStream("/test.html"))))).
+                    operation(PatchOperation.ADD_REPLACE).
                     build());
 
             updateUser(userUR);
@@ -215,10 +215,10 @@ public class PlainSchemaITCase extends AbstractITCase {
         userUR = new UserUR();
         userUR.setKey(userTO.getKey());
         // validation ok - application/json -> application/json
-        userUR.getPlainAttrs().add(new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                attrTO(attrTO("BinaryJSON",
-                        Base64.getEncoder().encodeToString(
-                                IOUtils.readBytesFromStream(getClass().getResourceAsStream("/test.json"))))).
+        userUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("BinaryJSON",
+                Base64.getEncoder().encodeToString(
+                        IOUtils.readBytesFromStream(getClass().getResourceAsStream("/test.json"))))).
+                operation(PatchOperation.ADD_REPLACE).
                 build());
 
         updateUser(userUR);
@@ -227,10 +227,10 @@ public class PlainSchemaITCase extends AbstractITCase {
         userUR = new UserUR();
         userUR.setKey(userTO.getKey());
         // no validation - application/xml -> application/json
-        userUR.getPlainAttrs().add(new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                attrTO(attrTO("BinaryJSON2",
-                        Base64.getEncoder().encodeToString(
-                                IOUtils.readBytesFromStream(getClass().getResourceAsStream("/test.xml"))))).
+        userUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("BinaryJSON2",
+                Base64.getEncoder().encodeToString(
+                        IOUtils.readBytesFromStream(getClass().getResourceAsStream("/test.xml"))))).
+                operation(PatchOperation.ADD_REPLACE).
                 build());
 
         updateUser(userUR);
@@ -351,8 +351,8 @@ public class PlainSchemaITCase extends AbstractITCase {
         UserTO userTO = createUser(userCR).getEntity();
         assertNotNull(userTO);
 
-        UserUR req = new UserUR.Builder().key(userTO.getKey()).
-                membership(new MembershipUR.Builder().group("b1f7c12d-ec83-441f-a50e-1691daaedf3b").build()).build();
+        UserUR req = new UserUR.Builder(userTO.getKey()).
+                membership(new MembershipUR.Builder("b1f7c12d-ec83-441f-a50e-1691daaedf3b").build()).build();
 
         UserTO newUserTO = updateUser(req).getEntity();
         assertNotNull(newUserTO);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
index f07a546..5ab0e85 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
@@ -142,8 +142,7 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
 
             // 1. create printer on external resource
             AnyObjectCR anyObjectCR = AnyObjectITCase.getSample("propagationJEXLTransformer");
-            String originalLocation = anyObjectCR.getPlainAttrs().stream().
-                    filter(attr -> "location".equals(attr.getSchema())).findFirst().get().getValues().get(0);
+            String originalLocation = anyObjectCR.getPlainAttr("location").get().getValues().get(0);
             assertFalse(originalLocation.endsWith(suffix));
 
             AnyObjectTO anyObjectTO = createAnyObject(anyObjectCR).getEntity();
@@ -258,9 +257,9 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
         for (int i = 0; i < 9; i++) {
             UserUR userUR = new UserUR();
             userUR.setKey(userTO.getKey());
-            userUR.getPlainAttrs().add(new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                    attrTO(new AttrTO.Builder().schema("userId").value(
-                            "test" + getUUIDString() + i + "@test.com").build()).
+            userUR.getPlainAttrs().add(new AttrPatch.Builder(new AttrTO.Builder("userId").value(
+                    "test" + getUUIDString() + i + "@test.com").build()).
+                    operation(PatchOperation.ADD_REPLACE).
                     build());
 
             userService.update(userUR);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
index 1b850eb..57abc8e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
@@ -164,8 +164,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
         UserTO userTemplate = new UserTO();
         userTemplate.getResources().add(RESOURCE_NAME_WS2);
 
-        userTemplate.getMemberships().add(
-                new MembershipTO.Builder().group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
+        userTemplate.getMemberships().add(new MembershipTO.Builder("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
         task.getTemplates().put(AnyTypeKind.USER.name(), userTemplate);
 
         GroupTO groupTemplate = new GroupTO();
@@ -778,9 +777,8 @@ public class PullTaskITCase extends AbstractTaskITCase {
             AnyCR userCR = remediation.get().getAnyCRPayload();
             userCR.getResources().clear();
 
-            String email = userCR.getPlainAttrs().stream().
-                    filter(attr -> "email".equals(attr.getSchema())).findFirst().get().getValues().get(0);
-            userCR.getPlainAttrs().add(new AttrTO.Builder().schema("userId").value(email).build());
+            String email = userCR.getPlainAttr("email").get().getValues().get(0);
+            userCR.getPlainAttrs().add(new AttrTO.Builder("userId").value(email).build());
 
             remediationService.remedy(remediation.get().getKey(), userCR);
 
@@ -821,8 +819,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
         userCR.getResources().add(RESOURCE_NAME_NOPROPAGATION2);
         userCR.getResources().add(RESOURCE_NAME_NOPROPAGATION4);
 
-        userCR.getMemberships().add(
-                new MembershipTO.Builder().group("bf825fe1-7320-4a54-bd64-143b5c18ab97").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("bf825fe1-7320-4a54-bd64-143b5c18ab97").build());
 
         UserTO userTO = createUser(userCR).getEntity();
         assertNotNull(userTO);
@@ -837,8 +834,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
             //-----------------------------
             UserTO template = new UserTO();
 
-            template.getMemberships().add(
-                    new MembershipTO.Builder().group("b8d38784-57e7-4595-859a-076222644b55").build());
+            template.getMemberships().add(new MembershipTO.Builder("b8d38784-57e7-4595-859a-076222644b55").build());
 
             template.getResources().add(RESOURCE_NAME_NOPROPAGATION4);
             //-----------------------------
@@ -1233,7 +1229,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
 
             UserTO template = new UserTO();
             template.getAuxClasses().add("minimal group");
-            template.getMemberships().add(new MembershipTO.Builder().group(propagationGroup.getKey()).build());
+            template.getMemberships().add(new MembershipTO.Builder(propagationGroup.getKey()).build());
             template.getPlainAttrs().add(attrTO("firstname", "'fixed'"));
             pullTask.getTemplates().put(AnyTypeKind.USER.name(), template);
 
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
index 840da6e..42951d2 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
@@ -480,18 +480,14 @@ public class SearchITCase extends AbstractITCase {
 
         String serviceKey = null;
         try {
-            AnyObjectCR anyObjectCR = new AnyObjectCR();
-            anyObjectCR.setName("one");
-            anyObjectCR.setRealm(SyncopeConstants.ROOT_REALM);
-            anyObjectCR.setType(service.getKey());
-            anyObjectCR.getMemberships().add(
-                    new MembershipTO.Builder().group("29f96485-729e-4d31-88a1-6fc60e4677f3").build());
+            AnyObjectCR anyObjectCR = new AnyObjectCR.Builder(SyncopeConstants.ROOT_REALM, service.getKey(), "one").
+                    membership(new MembershipTO.Builder("29f96485-729e-4d31-88a1-6fc60e4677f3").build()).
+                    build();
             serviceKey = createAnyObject(anyObjectCR).getEntity().getKey();
 
-            AnyObjectUR anyObjectUR = new AnyObjectUR();
-            anyObjectUR.setKey("fc6dbc3a-6c07-4965-8781-921e7401a4a5");
-            anyObjectUR.getMemberships().add(new MembershipUR.Builder().group("29f96485-729e-4d31-88a1-6fc60e4677f3").
-                    build());
+            AnyObjectUR anyObjectUR = new AnyObjectUR.Builder("fc6dbc3a-6c07-4965-8781-921e7401a4a5").
+                    membership(new MembershipUR.Builder("29f96485-729e-4d31-88a1-6fc60e4677f3").build()).
+                    build();
             updateAnyObject(anyObjectUR);
 
             PagedResult<AnyObjectTO> matching = anyObjectService.search(new AnyQuery.Builder().fiql(
@@ -522,7 +518,7 @@ public class SearchITCase extends AbstractITCase {
     public void issueSYNCOPE1223() {
         UserUR req = new UserUR();
         req.setKey("vivaldi");
-        req.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO("ctype", "ou=sample,o=isp")).build());
+        req.getPlainAttrs().add(new AttrPatch.Builder(attrTO("ctype", "ou=sample,o=isp")).build());
         userService.update(req);
 
         try {
@@ -533,7 +529,7 @@ public class SearchITCase extends AbstractITCase {
             assertEquals("vivaldi", users.getResult().get(0).getUsername());
         } finally {
             req.getPlainAttrs().clear();
-            req.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO("ctype", "F")).build());
+            req.getPlainAttrs().add(new AttrPatch.Builder(attrTO("ctype", "F")).build());
             userService.update(req);
         }
     }
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
index e5d3d37..fa177d3 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
@@ -48,17 +48,17 @@ import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.client.lib.batch.BatchRequest;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.request.ResourceAR;
+import org.apache.syncope.common.lib.policy.AccountPolicyTO;
+import org.apache.syncope.common.lib.policy.HaveIBeenPwnedPasswordRuleConf;
+import org.apache.syncope.common.lib.policy.PasswordPolicyTO;
 import org.apache.syncope.common.lib.request.AttrPatch;
-import org.apache.syncope.common.lib.request.ResourceDR;
 import org.apache.syncope.common.lib.request.MembershipUR;
 import org.apache.syncope.common.lib.request.PasswordPatch;
+import org.apache.syncope.common.lib.request.ResourceAR;
+import org.apache.syncope.common.lib.request.ResourceDR;
 import org.apache.syncope.common.lib.request.StatusR;
 import org.apache.syncope.common.lib.request.StringReplacePatchItem;
 import org.apache.syncope.common.lib.request.UserUR;
-import org.apache.syncope.common.lib.policy.AccountPolicyTO;
-import org.apache.syncope.common.lib.policy.HaveIBeenPwnedPasswordRuleConf;
-import org.apache.syncope.common.lib.policy.PasswordPolicyTO;
 import org.apache.syncope.common.lib.request.UserCR;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
@@ -73,11 +73,11 @@ import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.PatchOperation;
+import org.apache.syncope.common.lib.types.ExecStatus;
 import org.apache.syncope.common.lib.types.ImplementationEngine;
 import org.apache.syncope.common.lib.types.ImplementationType;
-import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.common.lib.types.PolicyType;
-import org.apache.syncope.common.lib.types.ExecStatus;
 import org.apache.syncope.common.lib.types.ResourceAssociationAction;
 import org.apache.syncope.common.lib.types.ResourceDeassociationAction;
 import org.apache.syncope.common.lib.types.StatusRType;
@@ -90,10 +90,10 @@ import org.apache.syncope.common.rest.api.service.ResourceService;
 import org.apache.syncope.common.rest.api.service.UserSelfService;
 import org.apache.syncope.common.rest.api.service.UserService;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
-import org.apache.syncope.fit.core.reference.TestAccountRuleConf;
-import org.apache.syncope.fit.core.reference.TestPasswordRuleConf;
 import org.apache.syncope.fit.AbstractITCase;
 import org.apache.syncope.fit.FlowableDetector;
+import org.apache.syncope.fit.core.reference.TestAccountRuleConf;
+import org.apache.syncope.fit.core.reference.TestPasswordRuleConf;
 import org.identityconnectors.framework.common.objects.OperationalAttributes;
 import org.junit.jupiter.api.Test;
 
@@ -108,10 +108,8 @@ public class UserITCase extends AbstractITCase {
     }
 
     public static UserCR getSample(final String email) {
-        return new UserCR.Builder().
-                realm(SyncopeConstants.ROOT_REALM).
+        return new UserCR.Builder(SyncopeConstants.ROOT_REALM, email).
                 password("password123").
-                username(email).
                 plainAttr(attrTO("fullname", email)).
                 plainAttr(attrTO("firstname", email)).
                 plainAttr(attrTO("surname", "surname")).
@@ -260,8 +258,7 @@ public class UserITCase extends AbstractITCase {
             // configured to be minLength=16
             userCR.setPassword("password1");
 
-            userCR.getMemberships().add(new MembershipTO.Builder().
-                    group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
+            userCR.getMemberships().add(new MembershipTO.Builder("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
 
             createUser(userCR);
         });
@@ -293,8 +290,7 @@ public class UserITCase extends AbstractITCase {
         UserCR userCR = getUniqueSample("a.b@c.com");
 
         // add a membership
-        userCR.getMemberships().add(new MembershipTO.Builder().
-                group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
 
         // add an attribute with a non-existing schema: must be ignored
         AttrTO attrWithInvalidSchemaTO = attrTO("invalid schema", "a value");
@@ -372,12 +368,10 @@ public class UserITCase extends AbstractITCase {
     public void createWithRequiredValueMissing() {
         UserCR userCR = getUniqueSample("a.b@c.it");
 
-        AttrTO type = userCR.getPlainAttrs().stream().
-                filter(attr -> "ctype".equals(attr.getSchema())).findFirst().get();
+        AttrTO type = userCR.getPlainAttr("ctype").get();
         userCR.getPlainAttrs().remove(type);
 
-        userCR.getMemberships().add(new MembershipTO.Builder().
-                group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
 
         // 1. create user without type (mandatory by UserSchema)
         try {
@@ -389,8 +383,7 @@ public class UserITCase extends AbstractITCase {
 
         userCR.getPlainAttrs().add(attrTO("ctype", "F"));
 
-        AttrTO surname = userCR.getPlainAttrs().stream().
-                filter(attr -> "surname".equals(attr.getSchema())).findFirst().get();
+        AttrTO surname = userCR.getPlainAttr("surname").get();
         userCR.getPlainAttrs().remove(surname);
 
         // 2. create user without surname (mandatory when type == 'F')
@@ -506,9 +499,9 @@ public class UserITCase extends AbstractITCase {
         UserTO userTO = createUser(userCR).getEntity();
         assertNotNull(userTO);
 
-        UserUR userUR = new UserUR.Builder().key(userTO.getKey()).
-                plainAttr(new AttrPatch.Builder().operation(PatchOperation.DELETE).
-                        attrTO(new AttrTO.Builder().schema("ctype").build()).
+        UserUR userUR = new UserUR.Builder(userTO.getKey()).
+                plainAttr(new AttrPatch.Builder(new AttrTO.Builder("ctype").build()).
+                        operation(PatchOperation.DELETE).
                         build()).build();
 
         userTO = updateUser(userUR).getEntity();
@@ -554,8 +547,7 @@ public class UserITCase extends AbstractITCase {
     public void update() {
         UserCR userCR = getUniqueSample("g.h@t.com");
 
-        userCR.getMemberships().add(new MembershipTO.Builder().
-                group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
 
         UserTO userTO = createUser(userCR).getEntity();
 
@@ -572,10 +564,10 @@ public class UserITCase extends AbstractITCase {
         String newFullName = getUUIDString() + "g.h@t.com";
         userUR.getPlainAttrs().add(attrAddReplacePatch("fullname", newFullName));
 
-        userUR.getMemberships().add(new MembershipUR.Builder().operation(PatchOperation.ADD_REPLACE).
-                group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
-        userUR.getMemberships().add(new MembershipUR.Builder().operation(PatchOperation.ADD_REPLACE).
-                group(userTO.getMemberships().get(0).getGroupKey()).build());
+        userUR.getMemberships().add(new MembershipUR.Builder("f779c0d4-633b-4be5-8f57-32eb478a3ca5").
+                operation(PatchOperation.ADD_REPLACE).build());
+        userUR.getMemberships().add(new MembershipUR.Builder(userTO.getMemberships().get(0).getGroupKey()).
+                operation(PatchOperation.ADD_REPLACE).build());
 
         userTO = updateUser(userUR).getEntity();
         assertNotNull(userTO);
@@ -614,7 +606,7 @@ public class UserITCase extends AbstractITCase {
         assertFalse(beforeTasks <= 0);
 
         UserCR userCR = getUniqueSample("pwdonly@t.com");
-        userCR.getMemberships().add(new MembershipTO.Builder().group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
 
         UserTO userTO = createUser(userCR).getEntity();
 
@@ -651,8 +643,7 @@ public class UserITCase extends AbstractITCase {
         UserCR userCR = getUniqueSample("t@p.mode");
 
         // add a membership
-        userCR.getMemberships().add(new MembershipTO.Builder().
-                group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
 
         // 1. create user
         UserTO userTO = createUser(userCR).getEntity();
@@ -716,8 +707,7 @@ public class UserITCase extends AbstractITCase {
 
         UserCR userCR = getUniqueSample("createActivate@syncope.apache.org");
 
-        userCR.getMemberships().add(new MembershipTO.Builder().
-                group("268fed79-f440-4390-9435-b273768eb5d6").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("268fed79-f440-4390-9435-b273768eb5d6").build());
 
         UserTO userTO = createUser(userCR).getEntity();
 
@@ -743,8 +733,7 @@ public class UserITCase extends AbstractITCase {
     public void suspendReactivate() {
         UserCR userCR = getUniqueSample("suspendReactivate@syncope.apache.org");
 
-        userCR.getMemberships().add(new MembershipTO.Builder().
-                group("bf825fe1-7320-4a54-bd64-143b5c18ab97").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("bf825fe1-7320-4a54-bd64-143b5c18ab97").build());
 
         UserTO userTO = createUser(userCR).getEntity();
 
@@ -856,8 +845,8 @@ public class UserITCase extends AbstractITCase {
         userUR.setKey(userTO.getKey());
 
         loginDate.getValues().add("2000-01-01");
-        userUR.getPlainAttrs().add(new AttrPatch.Builder().
-                operation(PatchOperation.ADD_REPLACE).attrTO(loginDate).build());
+        userUR.getPlainAttrs().add(new AttrPatch.Builder(loginDate).
+                operation(PatchOperation.ADD_REPLACE).build());
 
         userTO = updateUser(userUR).getEntity();
         assertNotNull(userTO);
@@ -925,8 +914,7 @@ public class UserITCase extends AbstractITCase {
 
         userCR.getAuxClasses().add("csv");
 
-        userCR.getMemberships().add(new MembershipTO.Builder().
-                group("37d15e4c-cdc1-460b-a591-8505c8133806").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("37d15e4c-cdc1-460b-a591-8505c8133806").build());
 
         userCR.getResources().add(RESOURCE_NAME_CSV);
 
@@ -1339,9 +1327,8 @@ public class UserITCase extends AbstractITCase {
         assertNotNull(response.getEntity());
 
         // 2. update
-        UserUR userUR = new UserUR.Builder().key(result.getEntity().getKey()).
-                plainAttr(new AttrPatch.Builder().
-                        attrTO(new AttrTO.Builder().schema("surname").value("surname2").build()).build()).
+        UserUR userUR = new UserUR.Builder(result.getEntity().getKey()).
+                plainAttr(new AttrPatch.Builder(new AttrTO.Builder("surname").value("surname2").build()).build()).
                 build();
         result = userService.update(userUR).readEntity(
                 new GenericType<ProvisioningResult<UserTO>>() {
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
index 4ac01df..d6e416f 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserIssuesITCase.java
@@ -114,8 +114,7 @@ public class UserIssuesITCase extends AbstractITCase {
         assertTrue(userTO.getResources().isEmpty());
 
         // 2. update assigning a resource forcing mandatory constraints: must fail with RequiredValuesMissing
-        UserUR userUR = new UserUR.Builder().
-                key(userTO.getKey()).
+        UserUR userUR = new UserUR.Builder(userTO.getKey()).
                 password(new PasswordPatch.Builder().value("newPassword123").build()).
                 resource(new StringPatchItem.Builder().
                         operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_WS2).build()).
@@ -269,10 +268,8 @@ public class UserIssuesITCase extends AbstractITCase {
         userCR.getVirAttrs().clear();
         userCR.getAuxClasses().add("csv");
 
-        userCR.getMemberships().add(new MembershipTO.Builder().
-                group("0626100b-a4ba-4e00-9971-86fad52a6216").build());
-        userCR.getMemberships().add(new MembershipTO.Builder().
-                group("ba9ed509-b1f5-48ab-a334-c8530a6422dc").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("0626100b-a4ba-4e00-9971-86fad52a6216").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("ba9ed509-b1f5-48ab-a334-c8530a6422dc").build());
 
         userCR.getResources().add(RESOURCE_NAME_CSV);
 
@@ -288,11 +285,10 @@ public class UserIssuesITCase extends AbstractITCase {
         // -----------------------------------
         // Remove the first membership: de-provisioning shouldn't happen
         // -----------------------------------
-        UserUR userUR = new UserUR();
-        userUR.setKey(userTO.getKey());
-
-        userUR.getMemberships().add(new MembershipUR.Builder().
-                operation(PatchOperation.DELETE).group(userTO.getMemberships().get(0).getGroupKey()).build());
+        UserUR userUR = new UserUR.Builder(userTO.getKey()).
+                membership(new MembershipUR.Builder(userTO.getMemberships().get(0).getGroupKey()).
+                        operation(PatchOperation.DELETE).build()).
+                build();
 
         userTO = updateUser(userUR).getEntity();
         assertNotNull(userTO);
@@ -323,11 +319,10 @@ public class UserIssuesITCase extends AbstractITCase {
         // -----------------------------------
         // Remove the first membership: de-provisioning should happen
         // -----------------------------------
-        userUR = new UserUR();
-        userUR.setKey(userTO.getKey());
-
-        userUR.getMemberships().add(new MembershipUR.Builder().
-                operation(PatchOperation.DELETE).group(userTO.getMemberships().get(0).getGroupKey()).build());
+        userUR = new UserUR.Builder(userTO.getKey()).
+                membership(new MembershipUR.Builder(userTO.getMemberships().get(0).getGroupKey()).
+                        operation(PatchOperation.DELETE).build()).
+                build();
 
         userTO = updateUser(userUR).getEntity();
         assertNotNull(userTO);
@@ -641,7 +636,7 @@ public class UserIssuesITCase extends AbstractITCase {
         // 2. create user with LDAP resource and membership of the above group
         UserCR userCR = UserITCase.getUniqueSample("syncope354@syncope.apache.org");
         userCR.getResources().add(RESOURCE_NAME_LDAP);
-        userCR.getMemberships().add(new MembershipTO.Builder().group(groupTO.getKey()).build());
+        userCR.getMemberships().add(new MembershipTO.Builder(groupTO.getKey()).build());
 
         UserTO userTO = createUser(userCR).getEntity();
         assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP));
@@ -657,8 +652,8 @@ public class UserIssuesITCase extends AbstractITCase {
         // 4. remove membership
         UserUR userUR = new UserUR();
         userUR.setKey(userTO.getKey());
-        userUR.getMemberships().add(new MembershipUR.Builder().operation(PatchOperation.DELETE).
-                group(userTO.getMemberships().get(0).getGroupKey()).build());
+        userUR.getMemberships().add(new MembershipUR.Builder(userTO.getMemberships().get(0).getGroupKey()).
+                operation(PatchOperation.DELETE).build());
 
         userTO = updateUser(userUR).getEntity();
         assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP));
@@ -699,7 +694,7 @@ public class UserIssuesITCase extends AbstractITCase {
         userCR.getPlainAttrs().add(attrTO("obscure", "valueToBeObscured"));
         userCR.getPlainAttrs().add(attrTO("photo", Base64.getEncoder().encodeToString(
                 IOUtils.readBytesFromStream(getClass().getResourceAsStream("/favicon.jpg")))));
-        userCR.getMemberships().add(new MembershipTO.Builder().group(groupTO.getKey()).build());
+        userCR.getMemberships().add(new MembershipTO.Builder(groupTO.getKey()).build());
 
         UserTO userTO = createUser(userCR).getEntity();
         assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP));
@@ -1304,8 +1299,8 @@ public class UserIssuesITCase extends AbstractITCase {
             // 5. update user with the new group, and don't provide any password
             UserUR userUR = new UserUR();
             userUR.setKey(userTO.getKey());
-            userUR.getMemberships().add(new MembershipUR.Builder().operation(PatchOperation.ADD_REPLACE).
-                    group(group.getKey()).build());
+            userUR.getMemberships().add(new MembershipUR.Builder(group.getKey()).
+                    operation(PatchOperation.ADD_REPLACE).build());
 
             ProvisioningResult<UserTO> result = updateUser(userUR);
             assertNotNull(result);
@@ -1340,8 +1335,8 @@ public class UserIssuesITCase extends AbstractITCase {
         UserCR userCR = UserITCase.getUniqueSample("syncope710@syncope.apache.org");
         userCR.getResources().clear();
         userCR.getMemberships().clear();
-        userCR.getMemberships().add(new MembershipTO.Builder().group(ldapGroup.getKey()).build());
-        userCR.getMemberships().add(new MembershipTO.Builder().group(dbGroup.getKey()).build());
+        userCR.getMemberships().add(new MembershipTO.Builder(ldapGroup.getKey()).build());
+        userCR.getMemberships().add(new MembershipTO.Builder(dbGroup.getKey()).build());
 
         ProvisioningResult<UserTO> result = createUser(userCR);
         assertEquals(2, result.getPropagationStatuses().size());
@@ -1371,7 +1366,7 @@ public class UserIssuesITCase extends AbstractITCase {
         // 2. create user and assign such group
         UserCR userCR = UserITCase.getUniqueSample("syncope881U@apache.org");
         userCR.getMemberships().clear();
-        userCR.getMemberships().add(new MembershipTO.Builder().group(group.getKey()).build());
+        userCR.getMemberships().add(new MembershipTO.Builder(group.getKey()).build());
 
         UserTO user = createUser(userCR).getEntity();
         assertNotNull(user);
@@ -1405,9 +1400,7 @@ public class UserIssuesITCase extends AbstractITCase {
 
         // 2. create user matching the condition above
         UserCR userCR = UserITCase.getUniqueSample("syncope1099U@apache.org");
-        userCR.getPlainAttrs().stream().
-                filter(attr -> "firstname".equals(attr.getSchema())).findFirst().get().
-                getValues().set(0, "issueSYNCOPE1099");
+        userCR.getPlainAttr("firstname").get().getValues().set(0, "issueSYNCOPE1099");
 
         ProvisioningResult<UserTO> created = createUser(userCR);
         assertNotNull(created);
@@ -1471,7 +1464,7 @@ public class UserIssuesITCase extends AbstractITCase {
         // 3. update user to match the dynamic condition: expect propagation to LDAP
         UserUR userUR = new UserUR();
         userUR.setKey(result.getEntity().getKey());
-        userUR.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO("cool", "true")).build());
+        userUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("cool", "true")).build());
 
         result = updateUser(userUR);
         assertEquals(1, result.getPropagationStatuses().size());
@@ -1480,7 +1473,7 @@ public class UserIssuesITCase extends AbstractITCase {
         // 4. update again user to not match the dynamic condition any more: expect propagation to LDAP
         userUR = new UserUR();
         userUR.setKey(result.getEntity().getKey());
-        userUR.getPlainAttrs().add(new AttrPatch.Builder().attrTO(attrTO("cool", "false")).build());
+        userUR.getPlainAttrs().add(new AttrPatch.Builder(attrTO("cool", "false")).build());
 
         result = updateUser(userUR);
         assertEquals(1, result.getPropagationStatuses().size());
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
index 90ba42b..b56f9db 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
@@ -110,7 +110,7 @@ public class UserSelfITCase extends AbstractITCase {
         // 1. self-create user with membership: goes 'createApproval' with resources and membership but no propagation
         UserCR userCR = UserITCase.getUniqueSample("anonymous@syncope.apache.org");
         userCR.getMemberships().add(
-                new MembershipTO.Builder().group("29f96485-729e-4d31-88a1-6fc60e4677f3").build());
+                new MembershipTO.Builder("29f96485-729e-4d31-88a1-6fc60e4677f3").build());
         userCR.getResources().add(RESOURCE_NAME_TESTDB);
 
         SyncopeClient anonClient = clientFactory.create();
@@ -148,7 +148,7 @@ public class UserSelfITCase extends AbstractITCase {
         // 1. self-create user with membership: goes 'createApproval' with resources and membership but no propagation
         UserCR userCR = UserITCase.getUniqueSample("anonymous@syncope.apache.org");
         userCR.getMemberships().add(
-                new MembershipTO.Builder().group("29f96485-729e-4d31-88a1-6fc60e4677f3").build());
+                new MembershipTO.Builder("29f96485-729e-4d31-88a1-6fc60e4677f3").build());
         userCR.getResources().add(RESOURCE_NAME_TESTDB);
         SyncopeClient anonClient = clientFactory.create();
         UserTO userTO = anonClient.getService(UserSelfService.class).
@@ -252,9 +252,8 @@ public class UserSelfITCase extends AbstractITCase {
         UserUR userUR = new UserUR();
         userUR.setKey(created.getKey());
         userUR.setUsername(new StringReplacePatchItem.Builder().value(created.getUsername() + "XX").build());
-        userUR.getMemberships().add(new MembershipUR.Builder().
+        userUR.getMemberships().add(new MembershipUR.Builder("bf825fe1-7320-4a54-bd64-143b5c18ab97").
                 operation(PatchOperation.ADD_REPLACE).
-                group("bf825fe1-7320-4a54-bd64-143b5c18ab97").
                 build());
         userUR.getResources().add(new StringPatchItem.Builder().
                 operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_TESTDB).build());
@@ -463,7 +462,7 @@ public class UserSelfITCase extends AbstractITCase {
         userCR.getResources().add(RESOURCE_NAME_TESTDB);
 
         // User with group 0cbcabd2-4410-4b6b-8f05-a052b451d18f are defined in workflow as subject to approval
-        userCR.getMemberships().add(new MembershipTO.Builder().group("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
 
         // 1. create user with group 0cbcabd2-4410-4b6b-8f05-a052b451d18f
         UserTO userTO = createUser(userCR).getEntity();
@@ -542,7 +541,7 @@ public class UserSelfITCase extends AbstractITCase {
 
         // User with group 0cbcabd2-4410-4b6b-8f05-a052b451d18f are defined in workflow as subject to approval
         userCR.getMemberships().add(
-                new MembershipTO.Builder().group("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
+                new MembershipTO.Builder("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
 
         // 1. create user and verify that no propagation occurred)
         ProvisioningResult<UserTO> result = createUser(userCR);
@@ -632,7 +631,7 @@ public class UserSelfITCase extends AbstractITCase {
 
         UserUR req = new UserUR();
         req.setKey(created.getKey());
-        req.getMemberships().add(new MembershipUR.Builder().group("b1f7c12d-ec83-441f-a50e-1691daaedf3b").build());
+        req.getMemberships().add(new MembershipUR.Builder("b1f7c12d-ec83-441f-a50e-1691daaedf3b").build());
 
         SyncopeClient client = clientFactory.create(created.getUsername(), "password123");
         Response response = client.getService(UserSelfService.class).update(req);
@@ -707,8 +706,7 @@ public class UserSelfITCase extends AbstractITCase {
         userCR.getMemberships().clear();
 
         // Users with group 0cbcabd2-4410-4b6b-8f05-a052b451d18f are defined in workflow as subject to approval
-        userCR.getMemberships().add(
-                new MembershipTO.Builder().group("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("0cbcabd2-4410-4b6b-8f05-a052b451d18f").build());
 
         // 1. create user with group 9 (and verify that no propagation occurred)
         UserTO userTO = createUser(userCR).getEntity();
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/VirAttrITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/VirAttrITCase.java
index 7078432..356c070 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/VirAttrITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/VirAttrITCase.java
@@ -79,8 +79,7 @@ public class VirAttrITCase extends AbstractITCase {
         UserCR userCR = UserITCase.getUniqueSample("issue16@apache.org");
         userCR.getVirAttrs().add(attrTO("virtualdata", "virtualvalue"));
         userCR.getResources().add(RESOURCE_NAME_DBVIRATTR);
-        userCR.getMemberships().add(
-                new MembershipTO.Builder().group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
+        userCR.getMemberships().add(new MembershipTO.Builder("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
 
         // 1. create user
         UserTO userTO = createUser(userCR).getEntity();
@@ -542,7 +541,7 @@ public class VirAttrITCase extends AbstractITCase {
             userCR.getVirAttrs().clear();
             userCR.getMemberships().clear();
 
-            userCR.getMemberships().add(new MembershipTO.Builder().group(groupTO.getKey()).build());
+            userCR.getMemberships().add(new MembershipTO.Builder(groupTO.getKey()).build());
 
             ProvisioningResult<UserTO> result = createUser(userCR);
             assertEquals(2, result.getPropagationStatuses().size());
@@ -684,7 +683,7 @@ public class VirAttrITCase extends AbstractITCase {
             userUR.setKey(userTO.getKey());
             // modify virtual attribute
             userUR.getVirAttrs().add(
-                    new AttrTO.Builder().schema(virSchema.getKey()).
+                    new AttrTO.Builder(virSchema.getKey()).
                             value("test@issue691.dom3.org").
                             value("test@issue691.dom4.org").
                             build());