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

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


The following commit(s) were added to refs/heads/4_0_X by this push:
     new 71a332148b [SYNCOPE-1934] Multiple AnyTypeClass per Realm
71a332148b is described below

commit 71a332148b735bbf94811030285831a886c3853e
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Thu Nov 27 11:12:03 2025 +0100

    [SYNCOPE-1934] Multiple AnyTypeClass per Realm
---
 .../apache/syncope/client/console/pages/Types.java | 10 ++--
 .../client/console/panels/AnyTypeClassesPanel.java |  3 +-
 .../client/console/panels/AnyTypesPanel.java       |  3 +-
 .../client/console/panels/RealmDetails.java        | 35 ++++++-----
 .../client/console/panels/RealmWizardBuilder.java  | 47 ++++++++-------
 .../wizards/any/AbstractAttrsWizardStep.java       |  3 +-
 .../syncope/client/console/pages/Types.properties  |  4 ++
 .../client/console/pages/Types_fr_CA.properties    | 12 ++--
 .../client/console/pages/Types_it.properties       |  4 ++
 .../client/console/pages/Types_ja.properties       |  4 ++
 .../client/console/pages/Types_pt_BR.properties    |  4 ++
 .../client/console/pages/Types_ru.properties       | 12 ++--
 .../panels/AnyTypeClassesPanel_it.properties       |  8 +--
 .../panels/AnyTypeDetailsPanel_fr_CA.properties    |  6 +-
 .../panels/AnyTypeDetailsPanel_it.properties       |  2 +-
 .../panels/AnyTypeDetailsPanel_ja.properties       |  2 +-
 .../panels/AnyTypeDetailsPanel_ru.properties       |  8 +--
 .../console/panels/AnyTypesPanel_ru.properties     |  4 +-
 .../client/console/panels/RealmDetails.html        |  2 +-
 .../client/console/panels/RealmDetails.properties  |  2 +-
 .../console/panels/RealmDetails_fr_CA.properties   |  2 +-
 .../console/panels/RealmDetails_it.properties      |  2 +-
 .../console/panels/RealmDetails_ja.properties      |  2 +-
 .../console/panels/RealmDetails_pt_BR.properties   |  2 +-
 .../console/panels/RealmDetails_ru.properties      |  2 +-
 .../panels/RealmWizardBuilder$Placeholder.html     | 23 ++++++++
 ...s => RealmWizardBuilder$Placeholder.properties} |  5 +-
 ...ealmWizardBuilder$Placeholder_fr_CA.properties} |  5 +-
 ...> RealmWizardBuilder$Placeholder_it.properties} |  5 +-
 ...> RealmWizardBuilder$Placeholder_ja.properties} |  5 +-
 ...> RealmWizardBuilder$Placeholder_pt.properties} |  5 +-
 ...> RealmWizardBuilder$Placeholder_ru.properties} |  5 +-
 .../panels/RelationshipTypesPanel.properties       |  1 +
 .../panels/RelationshipTypesPanel_fr_CA.properties |  1 +
 .../panels/RelationshipTypesPanel_it.properties    |  1 +
 .../panels/RelationshipTypesPanel_ja.properties    |  1 +
 .../panels/RelationshipTypesPanel_pt_BR.properties |  1 +
 .../panels/RelationshipTypesPanel_ru.properties    |  1 +
 .../panels/TypesDirectoryPanel_it.properties       |  4 +-
 .../org/apache/syncope/common/lib/to/RealmTO.java  | 16 +++--
 .../syncope/core/persistence/api/entity/Realm.java |  5 +-
 .../common/validation/RealmValidator.java          | 26 ++++-----
 .../core/persistence/jpa/entity/JPARealm.java      | 20 ++++---
 .../core/persistence/jpa/outer/RealmTest.java      |  9 ++-
 .../core/persistence/neo4j/entity/Neo4jRealm.java  | 18 +++---
 .../core/persistence/neo4j/outer/RealmTest.java    |  9 ++-
 .../provisioning/java/DefaultDerAttrHandler.java   | 10 ++--
 .../java/data/AnyTypeDataBinderImpl.java           |  3 +-
 .../java/data/RealmDataBinderImpl.java             | 40 +++++++------
 .../java/data/ResourceDataBinderImpl.java          | 68 +++++++++-------------
 .../propagation/DefaultPropagationManager.java     |  7 +--
 .../org/apache/syncope/fit/core/RealmITCase.java   |  4 +-
 .../asciidoc/reference-guide/concepts/realms.adoc  |  2 +-
 53 files changed, 260 insertions(+), 225 deletions(-)

diff --git 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Types.java
 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Types.java
index 006737c003..1f13afb196 100644
--- 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Types.java
+++ 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Types.java
@@ -33,7 +33,7 @@ import 
org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
 import org.apache.wicket.extensions.markup.html.tabs.ITab;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.spring.injection.annot.SpringBean;
 
@@ -72,7 +72,7 @@ public class Types extends BasePage {
     private List<ITab> buildTabList() {
         final List<ITab> tabs = new ArrayList<>();
 
-        tabs.add(new AbstractTab(new Model<>("RelationshipTypes")) {
+        tabs.add(new AbstractTab(new ResourceModel("relationshipTypes")) {
 
             private static final long serialVersionUID = -6815067322125799251L;
 
@@ -82,7 +82,7 @@ public class Types extends BasePage {
             }
         });
 
-        tabs.add(new AbstractTab(new Model<>("AnyTypes")) {
+        tabs.add(new AbstractTab(new ResourceModel("anyTypes")) {
 
             private static final long serialVersionUID = -6815067322125799251L;
 
@@ -92,7 +92,7 @@ public class Types extends BasePage {
             }
         });
 
-        tabs.add(new AbstractTab(new Model<>("AnyTypeClasses")) {
+        tabs.add(new AbstractTab(new ResourceModel("anyTypeClasses")) {
 
             private static final long serialVersionUID = -6815067322125799251L;
 
@@ -102,7 +102,7 @@ public class Types extends BasePage {
             }
         });
 
-        tabs.add(new AbstractTab(new Model<>("Schemas")) {
+        tabs.add(new AbstractTab(new ResourceModel("schemas")) {
 
             private static final long serialVersionUID = -6815067322125799251L;
 
diff --git 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
index 7f3c3c0143..c946f873a2 100644
--- 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
+++ 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
@@ -125,8 +125,7 @@ public class AnyTypeClassesPanel extends 
TypesDirectoryPanel<
                         || Collection.class.isAssignableFrom(field.getType())
                         || Map.class.isAssignableFrom(field.getType())) {
 
-                    columns.add(new PropertyColumn<>(
-                            new ResourceModel(field.getName()), 
field.getName()));
+                    columns.add(new PropertyColumn<>(new 
ResourceModel(field.getName()), field.getName()));
                 } else if (field.getType().equals(boolean.class) || 
field.getType().equals(Boolean.class)) {
                     columns.add(new BooleanPropertyColumn<>(
                             new ResourceModel(field.getName()), 
field.getName(), field.getName()));
diff --git 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
index 1530540fc8..7ac1a451e4 100644
--- 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
+++ 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
@@ -124,8 +124,7 @@ public class AnyTypesPanel extends 
TypesDirectoryPanel<AnyTypeTO, AnyTypesPanel.
                         || Collection.class.isAssignableFrom(field.getType())
                         || Map.class.isAssignableFrom(field.getType())) {
 
-                    columns.add(new PropertyColumn<>(
-                            new ResourceModel(field.getName()), 
field.getName()));
+                    columns.add(new PropertyColumn<>(new 
ResourceModel(field.getName()), field.getName()));
                 } else if (field.getType().equals(boolean.class) || 
field.getType().equals(Boolean.class)) {
                     columns.add(new BooleanPropertyColumn<>(
                             new ResourceModel(field.getName()), 
field.getName(), field.getName()));
diff --git 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmDetails.java
 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmDetails.java
index 5f57098eb8..ef92135c97 100644
--- 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmDetails.java
+++ 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmDetails.java
@@ -21,7 +21,6 @@ package org.apache.syncope.client.console.panels;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.stream.Collectors;
 import org.apache.syncope.client.console.SyncopeWebApplication;
 import org.apache.syncope.client.console.commons.RealmPolicyProvider;
@@ -29,7 +28,6 @@ import 
org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
 import org.apache.syncope.client.console.rest.ImplementationRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
 import org.apache.syncope.client.ui.commons.Constants;
-import 
org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
 import 
org.apache.syncope.client.ui.commons.markup.html.form.AjaxGridFieldPanel;
 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel;
 import 
org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
@@ -60,7 +58,7 @@ public class RealmDetails extends Panel {
 
     protected static final Logger LOG = 
LoggerFactory.getLogger(RealmDetails.class);
 
-    protected final IModel<List<String>> anyTypeClasses = new 
LoadableDetachableModel<>() {
+    protected final IModel<List<String>> availableAnyTypeClasses = new 
LoadableDetachableModel<>() {
 
         private static final long serialVersionUID = 5275935387613157437L;
 
@@ -103,8 +101,6 @@ public class RealmDetails extends Panel {
 
     protected final WebMarkupContainer container;
 
-    protected final AjaxDropDownChoicePanel<String> anyTypeClass;
-
     public RealmDetails(final String id, final RealmTO realmTO) {
         this(id, realmTO, null, true);
     }
@@ -135,10 +131,16 @@ public class RealmDetails extends Panel {
         fullPath.setEnabled(false);
         generics.add(fullPath.setVisible(unwrapped));
 
-        anyTypeClass = new AjaxDropDownChoicePanel<>(
-                "anyTypeClass", "anyTypeClass", new PropertyModel<>(realmTO, 
"anyTypeClass"), true);
-        anyTypeClass.setChoices(anyTypeClasses.getObject());
-        generics.add(anyTypeClass);
+        if (unwrapped) {
+            generics.add(new AjaxPalettePanel.Builder<String>().
+                    setAllowOrder(true).build(
+                    "anyTypeClasses",
+                    new PropertyModel<>(realmTO, "anyTypeClasses"),
+                    new 
ListModel<>(availableAnyTypeClasses.getObject())).setOutputMarkupId(true));
+        } else {
+            generics.add(new AjaxTextFieldPanel(
+                    "anyTypeClasses", "anyTypeClasses", 
Model.of(realmTO.getAnyTypeClasses().toString())));
+        }
 
         Map<String, String> attrs = realmTO.getPlainAttrs().stream().
                 sorted(Comparator.comparing(Attr::getSchema)).
@@ -155,10 +157,10 @@ public class RealmDetails extends Panel {
 
         if (unwrapped) {
             container.add(new AjaxPalettePanel.Builder<String>().
-                    setAllowMoveAll(true).setAllowOrder(true).
-                    build("actions",
-                            new PropertyModel<>(realmTO, "actions"),
-                            new ListModel<>(logicActions.getObject())).
+                    setAllowMoveAll(true).setAllowOrder(true).build(
+                    "actions",
+                    new PropertyModel<>(realmTO, "actions"),
+                    new ListModel<>(logicActions.getObject())).
                     setOutputMarkupId(true));
         } else {
             container.add(new AjaxTextFieldPanel(
@@ -166,7 +168,8 @@ public class RealmDetails extends Panel {
         }
 
         if (unwrapped) {
-            container.add(new 
AjaxPalettePanel.Builder<String>().build("resources",
+            container.add(new AjaxPalettePanel.Builder<String>().build(
+                    "resources",
                     new PropertyModel<>(realmTO, "resources"),
                     new ListModel<>(resources.getObject())).
                     setOutputMarkupId(true).
@@ -190,8 +193,4 @@ public class RealmDetails extends Panel {
         container.setEnabled(enable);
         return this;
     }
-
-    public Optional<String> getAnyTypeClassValue() {
-        return Optional.ofNullable(anyTypeClass.getModelObject());
-    }
 }
diff --git 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java
 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java
index b087756d39..4639589d00 100644
--- 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java
+++ 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/RealmWizardBuilder.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.client.console.panels;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 import org.apache.syncope.client.console.rest.RealmRestClient;
@@ -31,7 +30,9 @@ import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.behavior.AttributeAppender;
 import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.extensions.wizard.WizardModel.ICondition;
 import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.model.ResourceModel;
 
 public class RealmWizardBuilder extends BaseAjaxWizardBuilder<RealmTO> {
 
@@ -68,7 +69,7 @@ public class RealmWizardBuilder extends 
BaseAjaxWizardBuilder<RealmTO> {
 
     @Override
     protected WizardModel buildModelSteps(final RealmTO modelObject, final 
WizardModel wizardModel) {
-        
Optional.ofNullable(parent).map(RealmTO::getAnyTypeClass).ifPresent(modelObject::setAnyTypeClass);
+        Optional.ofNullable(parent).ifPresent(p -> 
modelObject.getAnyTypeClasses().addAll(p.getAnyTypeClasses()));
 
         RealmDetails details = new RealmDetails("details", modelObject);
         details.add(new AttributeAppender("style", "overflow-x:hidden;"));
@@ -77,10 +78,7 @@ public class RealmWizardBuilder extends 
BaseAjaxWizardBuilder<RealmTO> {
 
         RealmWrapper wrapper = new RealmWrapper(modelObject);
 
-        List<String> anyTypeClasses = new ArrayList<>();
-        
Optional.ofNullable((modelObject.getAnyTypeClass())).ifPresent(anyTypeClasses::add);
-
-        wizardModel.add(new PlainAttrs(wrapper, mode, anyTypeClasses, 
List.of()) {
+        wizardModel.add(new PlainAttrs(wrapper, mode, 
modelObject.getAnyTypeClasses(), List.of()) {
 
             private static final long serialVersionUID = 8167894751609598306L;
 
@@ -88,17 +86,9 @@ public class RealmWizardBuilder extends 
BaseAjaxWizardBuilder<RealmTO> {
             public PageReference getPageReference() {
                 return pageRef;
             }
-
-            @Override
-            public boolean evaluate() {
-                anyTypeClasses.clear();
-                details.getAnyTypeClassValue().ifPresent(anyTypeClasses::add);
-                super.evaluate();
-                return true;
-            }
         });
 
-        wizardModel.add(new DerAttrs(wrapper, anyTypeClasses, List.of()) {
+        wizardModel.add(new DerAttrs(wrapper, modelObject.getAnyTypeClasses(), 
List.of()) {
 
             private static final long serialVersionUID = 4298394879912549771L;
 
@@ -106,15 +96,10 @@ public class RealmWizardBuilder extends 
BaseAjaxWizardBuilder<RealmTO> {
             public PageReference getPageReference() {
                 return pageRef;
             }
-
-            @Override
-            public boolean evaluate() {
-                anyTypeClasses.clear();
-                details.getAnyTypeClassValue().ifPresent(anyTypeClasses::add);
-                return super.evaluate();
-            }
         });
 
+        wizardModel.add(new Placeholder(wrapper));
+
         return wizardModel;
     }
 
@@ -126,4 +111,22 @@ public class RealmWizardBuilder extends 
BaseAjaxWizardBuilder<RealmTO> {
             add(details);
         }
     }
+
+    protected static class Placeholder extends WizardStep implements 
ICondition {
+
+        private static final long serialVersionUID = -1633642371208520029L;
+
+        protected final RealmWrapper wrapper;
+
+        protected Placeholder(final RealmWrapper wrapper) {
+            this.wrapper = wrapper;
+            setTitleModel(new ResourceModel("noAttributes"));
+        }
+
+        @Override
+        public boolean evaluate() {
+            // display this step only if no AnyTypeClasses are selected for 
this Realm
+            return wrapper.getInnerObject().getAnyTypeClasses().isEmpty();
+        }
+    }
 }
diff --git 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep.java
 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep.java
index 847340f0bf..005d911401 100644
--- 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep.java
+++ 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrsWizardStep.java
@@ -124,9 +124,8 @@ public abstract class AbstractAttrsWizardStep<S extends 
SchemaTO> extends Wizard
         if (attributable instanceof AnyTO anyTO) {
             
classes.addAll(anyTypeClassRestClient.list(anyTO.getAuxClasses()).stream().
                     map(AnyTypeClassTO::getKey).toList());
-        } else if (attributable instanceof RealmTO realmTO && 
realmTO.getAnyTypeClass() != null) {
-            classes.add(realmTO.getAnyTypeClass());
         }
+
         setSchemas(classes);
         setAttrs();
         return getAttrsFromTO();
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types.properties
index 0b0a53b240..44f056e1a9 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types.properties
@@ -18,3 +18,7 @@ createSchema=Create new schema
 createAnyTypeClass=Create new AnyTypeClass
 createAnyType=Create new AnyType
 createRelationshipType=Create new RelationshipType
+relationshipTypes=RelationshipTypes
+anyTypes=AnyTypes
+anyTypeClasses=AnyTypeClasses
+schemas=Schemas
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_fr_CA.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_fr_CA.properties
index 1b47c927d4..facfbe1452 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_fr_CA.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_fr_CA.properties
@@ -14,7 +14,11 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-createSchema=Cr�er nouveau sch�ma
-createAnyTypeClass=Cr�er nouvelle classe tout type
-createAnyType=Cr�er nouveau tout type
-createRelationshipType=Cr�er nouveau type de relation
+createSchema=Cr\u00e9er nouveau sch\u00e9ma
+createAnyTypeClass=Cr\u00e9er nouvelle classe tout type
+createAnyType=Cr\u00e9er nouveau tout type
+createRelationshipType=Cr\u00e9er nouveau type de relation
+relationshipTypes=RelationshipTypes
+anyTypes=AnyTypes
+anyTypeClasses=AnyTypeClasses
+schemas=Schemas
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_it.properties
index 0edc2f1f49..3307a3b058 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_it.properties
@@ -18,3 +18,7 @@ createSchema=Crea un nuovo Schema
 createAnyTypeClass=Crea un nuovo AnyTypeClass
 createAnyType=Crea un nuovo AnyType
 createRelationshipType=Crea un nuovo RelationshipType
+relationshipTypes=RelationshipType
+anyTypes=AnyType
+anyTypeClasses=AnyTypeClass
+schemas=Schema
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_ja.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_ja.properties
index 1f95b26efa..2d04f551a8 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_ja.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_ja.properties
@@ -18,3 +18,7 @@ 
createSchema=\u65b0\u3057\u3044\u30b9\u30ad\u30fc\u30de\u3092\u4f5c\u6210
 
createAnyTypeClass=\u65b0\u3057\u3044\u4efb\u610f\u30bf\u30a4\u30d7\u30af\u30e9\u30b9\u3092\u4f5c\u6210
 
createAnyType=\u65b0\u3057\u3044\u4efb\u610f\u30bf\u30a4\u30d7\u3092\u4f5c\u6210
 
createRelationshipType=\u65b0\u3057\u3044\u95a2\u4fc2\u30bf\u30a4\u30d7\u3092\u4f5c\u6210
+relationshipTypes=RelationshipTypes
+anyTypes=AnyTypes
+anyTypeClasses=AnyTypeClasses
+schemas=Schemas
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_pt_BR.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_pt_BR.properties
index 64762c2467..fdecb3e981 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_pt_BR.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_pt_BR.properties
@@ -18,3 +18,7 @@ createSchema=Cria um novo Schema
 createAnyTypeClass=Cria um novo AnyTypeClass
 createAnyType=Cria um novo AnyType
 createRelationshipType=Cria um novo RelationshipType
+relationshipTypes=RelationshipTypes
+anyTypes=AnyTypes
+anyTypeClasses=AnyTypeClasses
+schemas=Schemas
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_ru.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_ru.properties
index 3f0c258df9..df5e322ed3 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_ru.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Types_ru.properties
@@ -15,11 +15,15 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-# createSchema=Создать атрибут
+# 
createSchema=\u00d0\u00a1\u00d0\u00be\u00d0\u00b7\u00d0\u00b4\u00d0\u00b0\u00d1\u0082\u00d1\u008c
 
\u00d0\u00b0\u00d1\u0082\u00d1\u0080\u00d0\u00b8\u00d0\u00b1\u00d1\u0083\u00d1\u0082
 createSchema=\u0421\u043e\u0437\u0434\u0430\u0442\u044c 
\u0430\u0442\u0440\u0438\u0431\u0443\u0442
-# createAnyTypeClass=Создать класс для типа объекта
+# 
createAnyTypeClass=\u00d0\u00a1\u00d0\u00be\u00d0\u00b7\u00d0\u00b4\u00d0\u00b0\u00d1\u0082\u00d1\u008c
 \u00d0\u00ba\u00d0\u00bb\u00d0\u00b0\u00d1\u0081\u00d1\u0081 
\u00d0\u00b4\u00d0\u00bb\u00d1\u008f 
\u00d1\u0082\u00d0\u00b8\u00d0\u00bf\u00d0\u00b0 
\u00d0\u00be\u00d0\u00b1\u00d1\u008a\u00d0\u00b5\u00d0\u00ba\u00d1\u0082\u00d0\u00b0
 createAnyTypeClass=\u0421\u043e\u0437\u0434\u0430\u0442\u044c 
\u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0442\u0438\u043f\u0430 
\u043e\u0431\u044a\u0435\u043a\u0442\u0430
-# createAnyType=Создать тип объекта
+# 
createAnyType=\u00d0\u00a1\u00d0\u00be\u00d0\u00b7\u00d0\u00b4\u00d0\u00b0\u00d1\u0082\u00d1\u008c
 \u00d1\u0082\u00d0\u00b8\u00d0\u00bf 
\u00d0\u00be\u00d0\u00b1\u00d1\u008a\u00d0\u00b5\u00d0\u00ba\u00d1\u0082\u00d0\u00b0
 createAnyType=\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0438\u043f 
\u043e\u0431\u044a\u0435\u043a\u0442\u0430
-# createRelationshipType=Создать тип связи
+# 
createRelationshipType=\u00d0\u00a1\u00d0\u00be\u00d0\u00b7\u00d0\u00b4\u00d0\u00b0\u00d1\u0082\u00d1\u008c
 \u00d1\u0082\u00d0\u00b8\u00d0\u00bf 
\u00d1\u0081\u00d0\u00b2\u00d1\u008f\u00d0\u00b7\u00d0\u00b8
 createRelationshipType=\u0421\u043e\u0437\u0434\u0430\u0442\u044c 
\u0442\u0438\u043f \u043e\u0442\u0441\u0432\u044f\u0437\u0438
+relationshipTypes=RelationshipTypes
+anyTypes=AnyTypes
+anyTypeClasses=AnyTypeClasses
+schemas=Schemas
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeClassesPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeClassesPanel_it.properties
index 6b85715cf1..a7ed41112e 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeClassesPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeClassesPanel_it.properties
@@ -16,7 +16,7 @@
 # under the License.
 any.edit=Modifica AnyTypeClass ${key}
 any.new=Nuovo AnyTypeClass
-anyTypeClasses=AnyTypeClasses
-plainSchemas=Plain Schemas
-derSchemas=Derived Schemas
-inUseByTypes=AnyTypes
+anyTypeClasses=AnyTypeClass
+plainSchemas=Plain Schema
+derSchemas=Derived Schema
+inUseByTypes=AnyType
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_fr_CA.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_fr_CA.properties
index 1389abc849..92da46b271 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_fr_CA.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_fr_CA.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-key=Cl�
-Genre=Genre
-classes=Classes tous types
+key=Cl\u00e9
+classes=AnyTypeClasses
+kind=Genre
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_it.properties
index 0d7f7aa52b..d8fa4e3018 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_it.properties
@@ -16,4 +16,4 @@
 # under the License.
 key=Key
 kind=Tipo
-classes=AnyTypeClasses
+classes=AnyTypeClass
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_ja.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_ja.properties
index 1e368f0cca..d0488fe549 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_ja.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_ja.properties
@@ -16,4 +16,4 @@
 # under the License.
 key=\u30ad\u30fc
 kind=\u7a2e\u985e
-classes=\u4efb\u610f\u30bf\u30a4\u30d7\u30af\u30e9\u30b9
+classes=AnyTypeClasses
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_ru.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_ru.properties
index 4ea3f60b03..95331cd909 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_ru.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypeDetailsPanel_ru.properties
@@ -15,9 +15,9 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-# key=Идентификатор
+# 
key=\u00d0\u0098\u00d0\u00b4\u00d0\u00b5\u00d0\u00bd\u00d1\u0082\u00d0\u00b8\u00d1\u0084\u00d0\u00b8\u00d0\u00ba\u00d0\u00b0\u00d1\u0082\u00d0\u00be\u00d1\u0080
 
key=\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440
-# kind=Объект
+# kind=\u00d0\u009e\u00d0\u00b1\u00d1\u008a\u00d0\u00b5\u00d0\u00ba\u00d1\u0082
 kind=\u041e\u0431\u044a\u0435\u043a\u0442
-# classes=Классы для типов объектов
-classes=\u041a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f 
\u0442\u0438\u043f\u043e\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432
+# 
classes=\u00d0\u009a\u00d0\u00bb\u00d0\u00b0\u00d1\u0081\u00d1\u0081\u00d1\u008b
 \u00d0\u00b4\u00d0\u00bb\u00d1\u008f 
\u00d1\u0082\u00d0\u00b8\u00d0\u00bf\u00d0\u00be\u00d0\u00b2 
\u00d0\u00be\u00d0\u00b1\u00d1\u008a\u00d0\u00b5\u00d0\u00ba\u00d1\u0082\u00d0\u00be\u00d0\u00b2
+classes=AnyTypeClasses
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypesPanel_ru.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypesPanel_ru.properties
index 60c0cc50ba..5e17e75559 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypesPanel_ru.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/AnyTypesPanel_ru.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-# any.edit=Изменить тип объектов ${key}
+# 
any.edit=\u00d0\u0098\u00d0\u00b7\u00d0\u00bc\u00d0\u00b5\u00d0\u00bd\u00d0\u00b8\u00d1\u0082\u00d1\u008c
 \u00d1\u0082\u00d0\u00b8\u00d0\u00bf 
\u00d0\u00be\u00d0\u00b1\u00d1\u008a\u00d0\u00b5\u00d0\u00ba\u00d1\u0082\u00d0\u00be\u00d0\u00b2
 ${key}
 any.edit=\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0442\u0438\u043f 
\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 ${key}
-# any.new=Создать тип объектов
+# 
any.new=\u00d0\u00a1\u00d0\u00be\u00d0\u00b7\u00d0\u00b4\u00d0\u00b0\u00d1\u0082\u00d1\u008c
 \u00d1\u0082\u00d0\u00b8\u00d0\u00bf 
\u00d0\u00be\u00d0\u00b1\u00d1\u008a\u00d0\u00b5\u00d0\u00ba\u00d1\u0082\u00d0\u00be\u00d0\u00b2
 any.new=\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0438\u043f 
\u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails.html
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails.html
index dbcd850f91..6092926ae7 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails.html
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails.html
@@ -27,7 +27,7 @@ under the License.
           <span wicket:id="fullPath">[fullPath]</span>
         </div>
         <div class="form-group">
-          <span wicket:id="anyTypeClass">[anyTypeClass]</span>
+          <span wicket:id="anyTypeClasses">[anyTypeClasses]</span>
         </div>
       </div>
       <div class="form-group">
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails.properties
index 499b0dcb34..36833588e9 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails.properties
@@ -23,5 +23,5 @@ authPolicy=Authentication Policy
 accessPolicy=Access Policy
 attrReleasePolicy=Attribute Release Policy
 ticketExpirationPolicy=Ticket Expiration Policy
-anyTypeClass=AnyTypeClass
+anyTypeClasses=AnyTypeClasses
 plainAttrs=Attributes
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_fr_CA.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_fr_CA.properties
index ae1bc48bdd..1d536a4ef7 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_fr_CA.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_fr_CA.properties
@@ -23,5 +23,5 @@ authPolicy=Authentication Policy
 accessPolicy=Access Policy
 attrReleasePolicy=Attribute Release Policy
 ticketExpirationPolicy=Ticket Expiration Policy
-anyTypeClass=AnyTypeClass
+anyTypeClasses=AnyTypeClasses
 plainAttrs=Attributs
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_it.properties
index 2edd63e2f9..063c11ec47 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_it.properties
@@ -23,5 +23,5 @@ authPolicy=Politica Autenticazione
 accessPolicy=Politica Accesso
 attrReleasePolicy=Politica Rilascio Attributi
 ticketExpirationPolicy=Politica Ticket Expiration
-anyTypeClass=AnyTypeClass
+anyTypeClasses=AnyTypeClass
 plainAttrs=Attributi
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_ja.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_ja.properties
index 531b1b1685..08b5841bb9 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_ja.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_ja.properties
@@ -23,5 +23,5 @@ authPolicy=Authentication Policy
 accessPolicy=Access Policy
 attrReleasePolicy=Attribute Release Policy
 ticketExpirationPolicy=Ticket Expiration Policy
-anyTypeClass=AnyTypeClass
+anyTypeClasses=AnyTypeClasses
 plainAttrs=Attributes
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_pt_BR.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_pt_BR.properties
index 8cbaee2687..ba19e43198 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_pt_BR.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_pt_BR.properties
@@ -23,5 +23,5 @@ authPolicy=Authentication Policy
 accessPolicy=Access Policy
 attrReleasePolicy=Attribute Release Policy
 ticketExpirationPolicy=Ticket Expiration Policy
-anyTypeClass=AnyTypeClass
+anyTypeClasses=AnyTypeClasses
 plainAttrs=Attributes
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_ru.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_ru.properties
index 4b6f2b47dd..6d81099cc5 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_ru.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmDetails_ru.properties
@@ -24,5 +24,5 @@ authPolicy=Authentication Policy
 accessPolicy=Access Policy
 attrReleasePolicy=Attribute Release Policy
 ticketExpirationPolicy=Ticket Expiration Policy
-anyTypeClass=AnyTypeClass
+anyTypeClasses=AnyTypeClasses
 plainAttrs=Attributes
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder.html
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder.html
new file mode 100644
index 0000000000..3e2b98e600
--- /dev/null
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder.html
@@ -0,0 +1,23 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml"; 
xmlns:wicket="http://wicket.apache.org";>
+  <wicket:panel>
+    <i><wicket:message key="noAnyTypeClasses"/></i>
+  </wicket:panel>
+</html>
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder.properties
similarity index 91%
copy from 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
copy to 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder.properties
index 11e90660b3..7dd090d0ff 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder.properties
@@ -14,6 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-description=Description
-kind=Tipo
-classes=AnyTypeClasses
+noAttributes=No Attributes
+noAnyTypeClasses=No AnyTypeClasses were selected
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_fr_CA.properties
similarity index 91%
copy from 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
copy to 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_fr_CA.properties
index 11e90660b3..7dd090d0ff 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_fr_CA.properties
@@ -14,6 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-description=Description
-kind=Tipo
-classes=AnyTypeClasses
+noAttributes=No Attributes
+noAnyTypeClasses=No AnyTypeClasses were selected
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_it.properties
similarity index 90%
copy from 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
copy to 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_it.properties
index 11e90660b3..61fd000386 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_it.properties
@@ -14,6 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-description=Description
-kind=Tipo
-classes=AnyTypeClasses
+noAttributes=Nessun attributo
+noAnyTypeClasses=Nessuna AnyTypeClass selezionata
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_ja.properties
similarity index 91%
copy from 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
copy to 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_ja.properties
index 11e90660b3..7dd090d0ff 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_ja.properties
@@ -14,6 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-description=Description
-kind=Tipo
-classes=AnyTypeClasses
+noAttributes=No Attributes
+noAnyTypeClasses=No AnyTypeClasses were selected
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_pt.properties
similarity index 91%
copy from 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
copy to 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_pt.properties
index 11e90660b3..7dd090d0ff 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_pt.properties
@@ -14,6 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-description=Description
-kind=Tipo
-classes=AnyTypeClasses
+noAttributes=No Attributes
+noAnyTypeClasses=No AnyTypeClasses were selected
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_ru.properties
similarity index 91%
copy from 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
copy to 
client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_ru.properties
index 11e90660b3..7dd090d0ff 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RealmWizardBuilder$Placeholder_ru.properties
@@ -14,6 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-description=Description
-kind=Tipo
-classes=AnyTypeClasses
+noAttributes=No Attributes
+noAnyTypeClasses=No AnyTypeClasses were selected
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel.properties
index 67d76078bd..c41e4711bf 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel.properties
@@ -18,3 +18,4 @@ any.edit=Edit RelationshipType ${key}
 any.new=New RelationshipType
 leftEndAnyType=Left End AnyType
 rightEndAnyType=Right End AnyType
+description=Description
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_fr_CA.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_fr_CA.properties
index 6703efd930..89e67c8b23 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_fr_CA.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_fr_CA.properties
@@ -18,3 +18,4 @@ any.edit=Modifier le type de relation ${key}
 any.new=Nouveau type de relation
 leftEndAnyType=Left End AnyType
 rightEndAnyType=Right End AnyType
+description=Description
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_it.properties
index f4f94ea678..e9ec8689ef 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_it.properties
@@ -18,3 +18,4 @@ any.edit=Modifica RelationshipType ${key}
 any.new=Nuovo RelationshipType
 leftEndAnyType=AnyType lato sinistro
 rightEndAnyType=AnyType lato destro
+description=Descrizione
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_ja.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_ja.properties
index fd855a5326..376289e60f 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_ja.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_ja.properties
@@ -18,3 +18,4 @@ any.edit=\u95a2\u4fc2\u30bf\u30a4\u30d7 ${key} 
\u3092\u7de8\u96c6
 any.new=\u65b0\u3057\u3044\u95a2\u4fc2\u30bf\u30a4\u30d7
 leftEndAnyType=Left End AnyType
 rightEndAnyType=Right End AnyType
+description=Description
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_pt_BR.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_pt_BR.properties
index c095675fe0..bf5e41f963 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_pt_BR.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_pt_BR.properties
@@ -18,3 +18,4 @@ any.edit=Alterar RelationshipType ${key}
 any.new=Novo RelationshipType
 leftEndAnyType=Left End AnyType
 rightEndAnyType=Right End AnyType
+description=Description
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_ru.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_ru.properties
index e7a313d584..bf61f42a91 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_ru.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/RelationshipTypesPanel_ru.properties
@@ -21,3 +21,4 @@ any.edit=\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c 
\u0442\u0438\u043f \u0
 any.new=\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0438\u043f 
\u0441\u0432\u044f\u0437\u0438
 leftEndAnyType=Left End AnyType
 rightEndAnyType=Right End AnyType
+description=Description
diff --git 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
index 11e90660b3..411b0df545 100644
--- 
a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
+++ 
b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/panels/TypesDirectoryPanel_it.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-description=Description
+description=Descrizione
 kind=Tipo
-classes=AnyTypeClasses
+classes=AnyTypeClass
diff --git 
a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java 
b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
index 242d368dec..2e3efc0a07 100644
--- 
a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
+++ 
b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/to/RealmTO.java
@@ -45,7 +45,7 @@ public class RealmTO implements NamedEntityTO, TemplatableTO, 
AttributableTO {
 
     private String fullPath;
 
-    private String anyTypeClass;
+    private final List<String> anyTypeClasses = new ArrayList<>();
 
     private String accountPolicy;
 
@@ -106,12 +106,10 @@ public class RealmTO implements NamedEntityTO, 
TemplatableTO, AttributableTO {
         this.fullPath = fullPath;
     }
 
-    public String getAnyTypeClass() {
-        return anyTypeClass;
-    }
-
-    public void setAnyTypeClass(final String anyTypeClass) {
-        this.anyTypeClass = anyTypeClass;
+    @JacksonXmlElementWrapper(localName = "anyTypeClasses")
+    @JacksonXmlProperty(localName = "anyTypeClasses")
+    public List<String> getAnyTypeClasses() {
+        return anyTypeClasses;
     }
 
     public String getAccountPolicy() {
@@ -222,7 +220,7 @@ public class RealmTO implements NamedEntityTO, 
TemplatableTO, AttributableTO {
                 append(name, other.name).
                 append(parent, other.parent).
                 append(fullPath, other.fullPath).
-                append(anyTypeClass, other.anyTypeClass).
+                append(anyTypeClasses, other.anyTypeClasses).
                 append(accountPolicy, other.accountPolicy).
                 append(passwordPolicy, other.passwordPolicy).
                 append(authPolicy, other.authPolicy).
@@ -244,7 +242,7 @@ public class RealmTO implements NamedEntityTO, 
TemplatableTO, AttributableTO {
                 append(name).
                 append(parent).
                 append(fullPath).
-                append(anyTypeClass).
+                append(anyTypeClasses).
                 append(accountPolicy).
                 append(passwordPolicy).
                 append(authPolicy).
diff --git 
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Realm.java
 
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Realm.java
index c512c8b2a8..43ba185e36 100644
--- 
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Realm.java
+++ 
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Realm.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.api.entity;
 
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 import org.apache.syncope.core.persistence.api.entity.policy.AccessPolicy;
 import org.apache.syncope.core.persistence.api.entity.policy.AccountPolicy;
 import org.apache.syncope.core.persistence.api.entity.policy.AttrReleasePolicy;
@@ -39,9 +40,9 @@ public interface Realm extends Attributable {
 
     String getFullPath();
 
-    AnyTypeClass getAnyTypeClass();
+    boolean add(AnyTypeClass anyTypeClass);
 
-    void setAnyTypeClass(AnyTypeClass anyTypeClass);
+    Set<? extends AnyTypeClass> getAnyTypeClasses();
 
     AccountPolicy getAccountPolicy();
 
diff --git 
a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/validation/RealmValidator.java
 
b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/validation/RealmValidator.java
index ffeec05625..5929828282 100644
--- 
a/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/validation/RealmValidator.java
+++ 
b/core/persistence-common/src/main/java/org/apache/syncope/core/persistence/common/validation/RealmValidator.java
@@ -19,8 +19,9 @@
 package org.apache.syncope.core.persistence.common.validation;
 
 import jakarta.validation.ConstraintValidatorContext;
-import java.util.List;
 import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.EntityViolationType;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
@@ -62,20 +63,17 @@ public class RealmValidator extends 
AbstractValidator<RealmCheck, Realm> {
             }
         }
 
-        if (realm.getAnyTypeClass() != null) {
-            List<String> allowedPlainSchemas = 
Optional.ofNullable(realm.getAnyTypeClass()).
-                    map(atc -> 
atc.getPlainSchemas().stream().map(PlainSchema::getKey).toList()).
-                    orElseGet(() -> List.of());
-            for (PlainAttr attr : realm.getPlainAttrs()) {
-                String plainSchema = 
Optional.ofNullable(attr).map(PlainAttr::getSchema).orElse(null);
-                if (plainSchema != null && 
!allowedPlainSchemas.contains(plainSchema)) {
-                    isValid = false;
+        Set<String> allowedPlainSchemas = realm.getAnyTypeClasses().stream().
+                flatMap(atc -> 
atc.getPlainSchemas().stream()).map(PlainSchema::getKey).collect(Collectors.toSet());
+        for (PlainAttr attr : realm.getPlainAttrs()) {
+            String plainSchema = 
Optional.ofNullable(attr).map(PlainAttr::getSchema).orElse(null);
+            if (plainSchema != null && 
!allowedPlainSchemas.contains(plainSchema)) {
+                isValid = false;
 
-                    context.buildConstraintViolationWithTemplate(
-                            getTemplate(EntityViolationType.InvalidPlainAttr,
-                                    plainSchema + " not allowed for this 
instance")).
-                            
addPropertyNode("plainAttrs").addConstraintViolation();
-                }
+                context.buildConstraintViolationWithTemplate(
+                        getTemplate(EntityViolationType.InvalidPlainAttr,
+                                plainSchema + " not allowed for this 
instance")).
+                        addPropertyNode("plainAttrs").addConstraintViolation();
             }
         }
 
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java
index 8d55a6ca63..1ce36dd8c0 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARealm.java
@@ -34,8 +34,10 @@ import jakarta.persistence.Transient;
 import jakarta.persistence.UniqueConstraint;
 import jakarta.validation.constraints.Size;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 import org.apache.syncope.common.lib.types.IdRepoImplementationType;
 import org.apache.syncope.core.persistence.api.entity.AnyTemplateRealm;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
@@ -84,8 +86,12 @@ public class JPARealm extends AbstractAttributable 
implements Realm {
     @Transient
     private final List<PlainAttr> plainAttrsList = new ArrayList<>();
 
-    @ManyToOne(fetch = FetchType.EAGER)
-    private JPAAnyTypeClass anyTypeClass;
+    @ManyToMany
+    @JoinTable(joinColumns =
+            @JoinColumn(name = "realm_id", referencedColumnName = "id"),
+            inverseJoinColumns =
+            @JoinColumn(name = "anyTypeClass_id", referencedColumnName = "id"))
+    private Set<JPAAnyTypeClass> anyTypeClasses = new HashSet<>();
 
     @ManyToOne(fetch = FetchType.EAGER)
     private JPAPasswordPolicy passwordPolicy;
@@ -195,14 +201,14 @@ public class JPARealm extends AbstractAttributable 
implements Realm {
     }
 
     @Override
-    public AnyTypeClass getAnyTypeClass() {
-        return anyTypeClass;
+    public boolean add(final AnyTypeClass anyTypeClass) {
+        checkType(anyTypeClass, JPAAnyTypeClass.class);
+        return anyTypeClasses.add((JPAAnyTypeClass) anyTypeClass);
     }
 
     @Override
-    public void setAnyTypeClass(final AnyTypeClass anyTypeClass) {
-        checkType(anyTypeClass, JPAAnyTypeClass.class);
-        this.anyTypeClass = (JPAAnyTypeClass) anyTypeClass;
+    public Set<? extends AnyTypeClass> getAnyTypeClasses() {
+        return anyTypeClasses;
     }
 
     @Override
diff --git 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/RealmTest.java
 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/RealmTest.java
index fac6a2d829..ad9bb45f72 100644
--- 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/RealmTest.java
+++ 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/RealmTest.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.persistence.jpa.outer;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import 
org.apache.syncope.core.persistence.api.attrvalue.PlainAttrValidationManager;
@@ -61,15 +60,15 @@ public class RealmTest extends AbstractTest {
     @Test
     public void plainAttrs() {
         Realm realm = realmSearchDAO.findByFullPath("/odd").orElseThrow();
-        assertNull(realm.getAnyTypeClass());
+        assertTrue(realm.getAnyTypeClasses().isEmpty());
         assertTrue(realm.getPlainAttrs().isEmpty());
 
-        realm.setAnyTypeClass(anyTypeClassDAO.findById("other").orElseThrow());
+        realm.add(anyTypeClassDAO.findById("other").orElseThrow());
         realm = realmDAO.save(realm);
         entityManager.flush();
 
         realm = realmDAO.findById(realm.getKey()).orElseThrow();
-        assertEquals(anyTypeClassDAO.findById("other").orElseThrow(), 
realm.getAnyTypeClass());
+        assertEquals(anyTypeClassDAO.findById("other").orElseThrow(), 
realm.getAnyTypeClasses().iterator().next());
 
         PlainAttr aLong = new PlainAttr();
         aLong.setSchema("aLong");
@@ -80,7 +79,7 @@ public class RealmTest extends AbstractTest {
         entityManager.flush();
 
         realm = realmDAO.findById(realm.getKey()).orElseThrow();
-        assertEquals(anyTypeClassDAO.findById("other").orElseThrow(), 
realm.getAnyTypeClass());
+        assertEquals(anyTypeClassDAO.findById("other").orElseThrow(), 
realm.getAnyTypeClasses().iterator().next());
         assertEquals(1, realm.getPlainAttrs().size());
         assertEquals(9, 
realm.getPlainAttr("aLong").orElseThrow().getValues().get(0).getLongValue());
     }
diff --git 
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/Neo4jRealm.java
 
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/Neo4jRealm.java
index 67db399bed..8fb88357de 100644
--- 
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/Neo4jRealm.java
+++ 
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/Neo4jRealm.java
@@ -22,9 +22,11 @@ import jakarta.validation.constraints.NotNull;
 import jakarta.validation.constraints.Size;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import org.apache.syncope.common.lib.types.IdRepoImplementationType;
@@ -64,7 +66,7 @@ public class Neo4jRealm extends AbstractAttributable 
implements Realm {
 
     public static final String PARENT_REL = "PARENT";
 
-    public static final String REALM_ANYTYPECLASS_REL = "REALM_ANYTYPECLASS";
+    public static final String REALM_ANYTYPECLASSES_REL = "REALM_ANYTYPECLASS";
 
     public static final String REALM_PASSWORD_POLICY_REL = 
"REALM_PASSWORD_POLICY";
 
@@ -94,8 +96,8 @@ public class Neo4jRealm extends AbstractAttributable 
implements Realm {
     @CompositeProperty(converterRef = "plainAttrsConverter")
     protected Map<String, PlainAttr> plainAttrs = new HashMap<>();
 
-    @Relationship(type = REALM_ANYTYPECLASS_REL, direction = 
Relationship.Direction.OUTGOING)
-    private Neo4jAnyTypeClass anyTypeClass;
+    @Relationship(type = REALM_ANYTYPECLASSES_REL, direction = 
Relationship.Direction.OUTGOING)
+    private Set<Neo4jAnyTypeClass> anyTypeClasses = new HashSet<>();
 
     @Relationship(type = REALM_PASSWORD_POLICY_REL, direction = 
Relationship.Direction.OUTGOING)
     private Neo4jPasswordPolicy passwordPolicy;
@@ -164,14 +166,14 @@ public class Neo4jRealm extends AbstractAttributable 
implements Realm {
     }
 
     @Override
-    public AnyTypeClass getAnyTypeClass() {
-        return anyTypeClass;
+    public boolean add(final AnyTypeClass anyTypeClass) {
+        checkType(anyTypeClass, Neo4jAnyTypeClass.class);
+        return anyTypeClasses.add((Neo4jAnyTypeClass) anyTypeClass);
     }
 
     @Override
-    public void setAnyTypeClass(final AnyTypeClass anyTypeClass) {
-        checkType(anyTypeClass, Neo4jAnyTypeClass.class);
-        this.anyTypeClass = (Neo4jAnyTypeClass) anyTypeClass;
+    public Set<? extends AnyTypeClass> getAnyTypeClasses() {
+        return anyTypeClasses;
     }
 
     @Override
diff --git 
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/RealmTest.java
 
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/RealmTest.java
index acea10970a..941889f3cb 100644
--- 
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/RealmTest.java
+++ 
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/outer/RealmTest.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.persistence.neo4j.outer;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.UUID;
@@ -69,14 +68,14 @@ public class RealmTest extends AbstractTest {
     @Test
     public void plainAttrs() {
         Realm realm = realmSearchDAO.findByFullPath("/odd").orElseThrow();
-        assertNull(realm.getAnyTypeClass());
+        assertTrue(realm.getAnyTypeClasses().isEmpty());
         assertTrue(realm.getPlainAttrs().isEmpty());
 
-        realm.setAnyTypeClass(anyTypeClassDAO.findById("other").orElseThrow());
+        realm.add(anyTypeClassDAO.findById("other").orElseThrow());
         realm = realmDAO.save(realm);
 
         realm = realmDAO.findById(realm.getKey()).orElseThrow();
-        assertEquals(anyTypeClassDAO.findById("other").orElseThrow(), 
realm.getAnyTypeClass());
+        assertEquals(anyTypeClassDAO.findById("other").orElseThrow(), 
realm.getAnyTypeClasses().iterator().next());
 
         PlainAttr aLong = new PlainAttr();
         aLong.setSchema("aLong");
@@ -86,7 +85,7 @@ public class RealmTest extends AbstractTest {
         realm = realmDAO.save(realm);
 
         realm = realmDAO.findById(realm.getKey()).orElseThrow();
-        assertEquals(anyTypeClassDAO.findById("other").orElseThrow(), 
realm.getAnyTypeClass());
+        assertEquals(anyTypeClassDAO.findById("other").orElseThrow(), 
realm.getAnyTypeClasses().iterator().next());
         assertEquals(1, realm.getPlainAttrs().size());
         assertEquals(9, 
realm.getPlainAttr("aLong").orElseThrow().getValues().get(0).getLongValue());
     }
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultDerAttrHandler.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultDerAttrHandler.java
index cad5cff4ff..edd822dc7a 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultDerAttrHandler.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultDerAttrHandler.java
@@ -22,6 +22,7 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
@@ -71,7 +72,7 @@ public class DefaultDerAttrHandler implements DerAttrHandler {
 
     @Override
     public String getValue(final Realm realm, final DerSchema schema) {
-        if (realm.getAnyTypeClass() == null || 
!realm.getAnyTypeClass().getDerSchemas().contains(schema)) {
+        if (realm.getAnyTypeClasses().stream().flatMap(atc -> 
atc.getDerSchemas().stream()).anyMatch(schema::equals)) {
             LOG.debug("{} not allowed for {}", schema, realm);
             return null;
         }
@@ -103,13 +104,10 @@ public class DefaultDerAttrHandler implements 
DerAttrHandler {
 
     @Override
     public Map<DerSchema, String> getValues(final Realm realm) {
-        if (realm.getAnyTypeClass() == null || 
!realm.getAnyTypeClass().getDerSchemas().isEmpty()) {
-            return Map.of();
-        }
-
         return getValues(
                 realm,
-                realm.getAnyTypeClass().getDerSchemas());
+                realm.getAnyTypeClasses().stream().
+                        flatMap(atc -> 
atc.getDerSchemas().stream()).collect(Collectors.toSet()));
     }
 
     @Override
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
index 111bbda798..0b44044f11 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
@@ -166,8 +166,7 @@ public class AnyTypeDataBinderImpl implements 
AnyTypeDataBinder {
         AnyTypeTO anyTypeTO = new AnyTypeTO();
         anyTypeTO.setKey(anyType.getKey());
         anyTypeTO.setKind(anyType.getKind());
-        anyTypeTO.getClasses().addAll(anyType.getClasses().stream().
-                map(AnyTypeClass::getKey).toList());
+        
anyTypeTO.getClasses().addAll(anyType.getClasses().stream().map(AnyTypeClass::getKey).toList());
         return anyTypeTO;
     }
 }
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
index 519f7feb6f..2e3de205da 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
@@ -106,6 +106,18 @@ public class RealmDataBinderImpl extends 
AttributableDataBinder implements Realm
         this.templateUtils = templateUtils;
     }
 
+    protected SyncopeClientException checkMandatory(final Realm realm) {
+        SyncopeClientException reqValMissing = 
SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+
+        // Check if there is some mandatory schema defined for which no value 
has been provided
+        realm.getAnyTypeClasses().stream().
+                flatMap(atc -> atc.getPlainSchemas().stream()).
+                forEach(schema -> checkMandatory(
+                schema, realm.getPlainAttr(schema.getKey()).orElse(null), 
realm, reqValMissing));
+
+        return reqValMissing;
+    }
+
     protected void fill(
             final RealmTO realmTO,
             final Realm realm,
@@ -135,29 +147,21 @@ public class RealmDataBinderImpl extends 
AttributableDataBinder implements Realm
             scce.addException(invalidValues);
         }
 
-        SyncopeClientException reqValMissing = 
SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
-        // Check if there is some mandatory schema defined for which no value 
has been provided
-        realm.getAnyTypeClass().getPlainSchemas().forEach(schema -> 
checkMandatory(
-                schema, realm.getPlainAttr(schema.getKey()).orElse(null), 
realm, reqValMissing));
-        if (!reqValMissing.isEmpty()) {
-            scce.addException(reqValMissing);
+        SyncopeClientException requiredValuesMissing = checkMandatory(realm);
+        if (!requiredValuesMissing.isEmpty()) {
+            scce.addException(requiredValuesMissing);
         }
     }
 
     protected void bind(final Realm realm, final RealmTO realmTO, final 
SyncopeClientCompositeException scce) {
         realm.setName(realmTO.getName());
 
-        if (realmTO.getAnyTypeClass() == null) {
-            realm.setAnyTypeClass(null);
-        } else {
-            
anyTypeClassDAO.findById(realmTO.getAnyTypeClass()).ifPresentOrElse(
-                    realm::setAnyTypeClass,
-                    () -> LOG.debug("Invalid {} {}, ignoring...",
-                            AnyTypeClass.class.getSimpleName(), 
realmTO.getAnyTypeClass()));
-        }
-        if (realm.getAnyTypeClass() != null) {
-            fill(realmTO, realm, scce);
-        }
+        realmTO.getAnyTypeClasses().forEach(anyTypeClass -> 
anyTypeClassDAO.findById(anyTypeClass).ifPresentOrElse(
+                realm::add,
+                () -> LOG.debug("Invalid {} {}, ignoring...", 
AnyTypeClass.class.getSimpleName(), anyTypeClass)));
+        realm.getAnyTypeClasses().removeIf(c -> c == null || 
!realmTO.getAnyTypeClasses().contains(c.getKey()));
+
+        fill(realmTO, realm, scce);
 
         realm.setAccessPolicy(Optional.ofNullable(realmTO.getAccessPolicy()).
                 flatMap(p -> policyDAO.findById(p, 
AccessPolicy.class)).orElse(null));
@@ -317,7 +321,7 @@ public class RealmDataBinderImpl extends 
AttributableDataBinder implements Realm
         realmTO.setName(realm.getName());
         Optional.ofNullable(realm.getParent()).ifPresent(parent -> 
realmTO.setParent(parent.getKey()));
         realmTO.setFullPath(realm.getFullPath());
-        
Optional.ofNullable(realm.getAnyTypeClass()).map(AnyTypeClass::getKey).ifPresent(realmTO::setAnyTypeClass);
+        
realmTO.getAnyTypeClasses().addAll(realm.getAnyTypeClasses().stream().map(AnyTypeClass::getKey).toList());
 
         realm.getPlainAttrs().forEach(plainAttr -> realmTO.getPlainAttrs().
                 add(new 
Attr.Builder(plainAttr.getSchema()).values(plainAttr.getValuesAsStrings()).build()));
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index 168195496c..9bc5f3ace2 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -243,11 +243,6 @@ public class ResourceDataBinderImpl implements 
ResourceDataBinder {
 
             orgUnit.setIgnoreCaseMatch(orgUnitTO.isIgnoreCaseMatch());
 
-            if (orgUnitTO.getConnObjectLink() == null) {
-                SyncopeClientException sce = 
SyncopeClientException.build(ClientExceptionType.InvalidOrgUnit);
-                sce.getElements().add("Null connObjectLink");
-                throw sce;
-            }
             orgUnit.setConnObjectLink(orgUnitTO.getConnObjectLink());
 
             SyncopeClientCompositeException scce = 
SyncopeClientException.buildComposite();
@@ -265,42 +260,37 @@ public class ResourceDataBinderImpl implements 
ResourceDataBinder {
                     requiredValuesMissing.getElements().add("intAttrName");
                     scce.addException(requiredValuesMissing);
                 } else {
-                    if (!"name".equals(itemTO.getIntAttrName()) && 
!"fullpath".equals(itemTO.getIntAttrName())) {
-                        LOG.error("Only 'name' and 'fullpath' are supported 
for Realms");
-                        invalidMapping.getElements().add("Only 'name' and 
'fullpath' are supported for Realms");
-                    } else {
-                        if (itemTO.getMandatoryCondition() != null
-                                && 
!jexlTools.isExpressionValid(itemTO.getMandatoryCondition())) {
-
-                            SyncopeClientException invalidMandatoryCondition = 
SyncopeClientException.build(
-                                    ClientExceptionType.InvalidValues);
-                            
invalidMandatoryCondition.getElements().add(itemTO.getMandatoryCondition());
-                            scce.addException(invalidMandatoryCondition);
-                        }
-
-                        Item item = new Item();
-                        item.setIntAttrName(itemTO.getIntAttrName());
-                        item.setExtAttrName(itemTO.getExtAttrName());
-                        item.setPurpose(itemTO.getPurpose());
-                        
item.setMandatoryCondition(itemTO.getMandatoryCondition());
-                        item.setConnObjectKey(itemTO.isConnObjectKey());
-                        item.setPassword(itemTO.isPassword());
-                        
item.setPropagationJEXLTransformer(itemTO.getPropagationJEXLTransformer());
-                        
item.setPullJEXLTransformer(itemTO.getPullJEXLTransformer());
+                    if (itemTO.getMandatoryCondition() != null
+                            && 
!jexlTools.isExpressionValid(itemTO.getMandatoryCondition())) {
 
-                        itemTO.getTransformers().forEach(key -> 
implementationDAO.findById(key).ifPresentOrElse(
-                                transformer -> 
item.getTransformers().add(transformer.getKey()),
-                                () -> LOG.debug("Invalid {} {}, ignoring...",
-                                        Implementation.class.getSimpleName(), 
key)));
-                        // remove all implementations not contained in the TO
-                        item.getTransformers().
-                                removeIf(implementation -> 
!itemTO.getTransformers().contains(implementation));
+                        SyncopeClientException invalidMandatoryCondition = 
SyncopeClientException.build(
+                                ClientExceptionType.InvalidValues);
+                        
invalidMandatoryCondition.getElements().add(itemTO.getMandatoryCondition());
+                        scce.addException(invalidMandatoryCondition);
+                    }
 
-                        if (item.isConnObjectKey()) {
-                            orgUnit.setConnObjectKeyItem(item);
-                        } else {
-                            orgUnit.add(item);
-                        }
+                    Item item = new Item();
+                    item.setIntAttrName(itemTO.getIntAttrName());
+                    item.setExtAttrName(itemTO.getExtAttrName());
+                    item.setPurpose(itemTO.getPurpose());
+                    item.setMandatoryCondition(itemTO.getMandatoryCondition());
+                    item.setConnObjectKey(itemTO.isConnObjectKey());
+                    item.setPassword(itemTO.isPassword());
+                    
item.setPropagationJEXLTransformer(itemTO.getPropagationJEXLTransformer());
+                    
item.setPullJEXLTransformer(itemTO.getPullJEXLTransformer());
+
+                    itemTO.getTransformers().forEach(key -> 
implementationDAO.findById(key).ifPresentOrElse(
+                            transformer -> 
item.getTransformers().add(transformer.getKey()),
+                            () -> LOG.debug("Invalid {} {}, ignoring...",
+                                    Implementation.class.getSimpleName(), 
key)));
+                    // remove all implementations not contained in the TO
+                    item.getTransformers().
+                            removeIf(implementation -> 
!itemTO.getTransformers().contains(implementation));
+
+                    if (item.isConnObjectKey()) {
+                        orgUnit.setConnObjectKeyItem(item);
+                    } else {
+                        orgUnit.add(item);
                     }
                 }
             }
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
index 8b0d5d9751..ba1197c7d8 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationManager.java
@@ -27,7 +27,6 @@ import java.util.Set;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.request.AnyUR;
 import org.apache.syncope.common.lib.request.LinkedAccountUR;
@@ -554,17 +553,13 @@ public class DefaultPropagationManager implements 
PropagationManager {
         List<PropagationTaskInfo> tasks = new ArrayList<>();
 
         propByRes.asMap().forEach((resourceKey, operation) -> {
-            ExternalResource resource = resourceDAO.findById(resourceKey).
-                    orElseThrow(() -> new NotFoundException("Resource " + 
resourceKey));
+            ExternalResource resource = 
resourceDAO.findById(resourceKey).orElse(null);
             OrgUnit orgUnit = 
Optional.ofNullable(resource).map(ExternalResource::getOrgUnit).orElse(null);
 
             if (resource == null) {
                 LOG.error("Invalid resource name specified: {}, ignoring...", 
resourceKey);
             } else if (orgUnit == null) {
                 LOG.error("No orgUnit specified on resource {}, ignoring...", 
resource);
-            } else if (StringUtils.isBlank(orgUnit.getConnObjectLink())) {
-                LOG.warn("Requesting propagation for {} but no ConnObjectLink 
provided for {}",
-                        realm.getFullPath(), resource);
             } else {
                 MappingManager.PreparedAttrs preparedAttrs = 
mappingManager.prepareAttrsFromRealm(realm, resource);
 
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
index 1e1a30bdc4..987780c3ac 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/RealmITCase.java
@@ -338,13 +338,13 @@ public class RealmITCase extends AbstractITCase {
         // 1. create realm and add the LDAP resource
         RealmTO realm = new RealmTO();
         realm.setName("test");
-        realm.setAnyTypeClass("other");
+        realm.getAnyTypeClasses().add("other");
         realm.getPlainAttrs().add(new 
Attr.Builder("ctype").value("number1").build());
         realm.getResources().add(RESOURCE_NAME_LDAP_ORGUNIT);
 
         RealmTO childRealm = new RealmTO();
         childRealm.setName("child");
-        childRealm.setAnyTypeClass("other");
+        childRealm.getAnyTypeClasses().add("other");
         childRealm.getPlainAttrs().add(new 
Attr.Builder("ctype").value("number2").build());
         childRealm.getResources().add(RESOURCE_NAME_LDAP_ORGUNIT);
 
diff --git a/src/main/asciidoc/reference-guide/concepts/realms.adoc 
b/src/main/asciidoc/reference-guide/concepts/realms.adoc
index 4a3b972d45..0e2b7836a3 100644
--- a/src/main/asciidoc/reference-guide/concepts/realms.adoc
+++ b/src/main/asciidoc/reference-guide/concepts/realms.adoc
@@ -27,7 +27,7 @@ Each realm:
 . is either a leaf or root of a sub-tree of realms;
 . is uniquely identified by the path from the root realm, e.g. `/a/b/c` 
identifies the sub-realm `c` in the sub-tree
 rooted at `b`, having in turn `a` as parent realm, directly under the root 
realm;
-. optionally refers to an <<anytypeclass>> which allows to define plain and 
derived attributes for the realm;
+. refers to <<anytypeclass,any type class(es)>> which allow to define plain 
and derived attributes;
 . optionally refers to various <<policies,policies>> that are enforced on all 
Users, Groups and Any Objects in the given
 realm and sub-realms, unless some sub-realms define their own policies.
 . optionally refers to <<logicactions,logic action(s)>>

Reply via email to