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 2019/01/29 17:00:27 UTC

[syncope] branch master updated: [SYNCOPE-1430] Now ItemTransformer#beforePropagation requires (and returns) AttrSchemaType to avoid unwante attribute value type mess

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


The following commit(s) were added to refs/heads/master by this push:
     new dae2c2a  [SYNCOPE-1430] Now ItemTransformer#beforePropagation requires (and returns) AttrSchemaType to avoid unwante attribute value type mess
dae2c2a is described below

commit dae2c2a442a928c351bbe25a9bc3b652a706e36c
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Tue Jan 29 15:18:21 2019 +0100

    [SYNCOPE-1430] Now ItemTransformer#beforePropagation requires (and returns) AttrSchemaType to avoid unwante attribute value type mess
---
 .../implementations/MyItemTransformer.groovy       |   8 +-
 .../syncope/core/persistence/api/dao/AnyDAO.java   |   8 +-
 core/persistence-jpa-json/pom.xml                  |   3 +
 .../core/persistence/api/dao/JPAJSONAnyDAO.java    |  20 ++-
 .../persistence/jpa/dao/JPAJSONAnyObjectDAO.java   |  19 +--
 .../core/persistence/jpa/dao/JPAJSONGroupDAO.java  |  19 +--
 .../core/persistence/jpa/dao/JPAJSONUserDAO.java   |  19 +--
 .../core/persistence/jpa/dao/PGJPAJSONAnyDAO.java  |  28 ++--
 .../core/persistence/jpa/dao/AbstractAnyDAO.java   |  21 ++-
 .../jpa/entity/AbstractPlainAttrValue.java         |  45 +++++-
 .../core/persistence/jpa/inner/UserTest.java       |  26 ++--
 .../core/persistence/jpa/outer/UserTest.java       |   4 +-
 .../syncope/core/provisioning/api/IntAttrName.java |  17 ++-
 .../core/provisioning/api/MappingManager.java      |   7 +-
 .../provisioning/api/data/ItemTransformer.java     |   8 +-
 .../core/provisioning/java/IntAttrNameParser.java  |  16 +-
 .../core/provisioning/java/MappingManagerImpl.java | 142 ++++++++----------
 .../java/data/AbstractAnyDataBinder.java           |  15 +-
 .../java/data/JEXLItemTransformerImpl.java         |  11 +-
 .../java/data/ResourceDataBinderImpl.java          |   6 +-
 .../core/provisioning/java/pushpull/PullUtils.java |  11 +-
 .../provisioning/java/IntAttrNameParserTest.java   |  35 +++--
 .../syncope/core/logic/oidc/OIDCUserManager.java   |  19 ++-
 .../java/data/OIDCProviderDataBinderImpl.java      |   6 +-
 .../syncope/core/logic/saml2/SAML2UserManager.java |  19 ++-
 .../java/data/SAML2IdPDataBinderImpl.java          |   6 +-
 .../core/reference/DateToDateItemTransformer.java} |  65 +++-----
 .../core/reference/DateToLongItemTransformer.java} |  66 ++++-----
 .../fit/core/reference/ITImplementationLookup.java |   2 +
 .../syncope/fit/core/PropagationTaskITCase.java    | 164 +++++++++++++++++++--
 .../org/apache/syncope/fit/core/VirAttrITCase.java |   6 +-
 .../test/resources/PrefixItemTransformer.groovy    |  20 +--
 32 files changed, 529 insertions(+), 332 deletions(-)

diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/implementations/MyItemTransformer.groovy b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/implementations/MyItemTransformer.groovy
index fd4b5d4..971b558 100644
--- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/implementations/MyItemTransformer.groovy
+++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/implementations/MyItemTransformer.groovy
@@ -17,7 +17,10 @@
  * under the License.
  */
 import groovy.transform.CompileStatic
+import java.util.List;
+import org.apache.commons.lang3.tuple.Pair
 import org.apache.syncope.common.lib.to.EntityTO
+import org.apache.syncope.common.lib.types.AttrSchemaType
 import org.apache.syncope.core.persistence.api.entity.Entity
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue
 import org.apache.syncope.core.persistence.api.entity.resource.Item
@@ -27,12 +30,13 @@ import org.apache.syncope.core.provisioning.api.data.ItemTransformer
 class MyItemTransformer implements ItemTransformer {
 	
   @Override
-  List<PlainAttrValue> beforePropagation(
+  Pair<AttrSchemaType, List<PlainAttrValue>> beforePropagation(
     Item item,
     Entity entity,
+    AttrSchemaType schemaType,
     List<PlainAttrValue> values) {
 
-    return values;
+    return Pair.of(schemaType, values);
   }
     
   @Override
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
index 6675de6..a55abf5 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
@@ -23,8 +23,10 @@ import java.util.Date;
 import java.util.List;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Schema;
 
 public interface AnyDAO<A extends Any<?>> extends DAO<A> {
@@ -39,9 +41,9 @@ public interface AnyDAO<A extends Any<?>> extends DAO<A> {
 
     A find(String key);
 
-    List<A> findByPlainAttrValue(String schema, PlainAttrValue attrValue, boolean ignoreCaseMatch);
+    List<A> findByPlainAttrValue(PlainSchema schema, PlainAttrValue attrValue, boolean ignoreCaseMatch);
 
-    A findByPlainAttrUniqueValue(String schema, PlainAttrValue attrUniqueValue, boolean ignoreCaseMatch);
+    A findByPlainAttrUniqueValue(PlainSchema schema, PlainAttrValue attrUniqueValue, boolean ignoreCaseMatch);
 
     /**
      * Find any objects by derived attribute value. This method could fail if one or more string literals contained
@@ -54,7 +56,7 @@ public interface AnyDAO<A extends Any<?>> extends DAO<A> {
      * @param ignoreCaseMatch whether comparison for string values should take case into account or not
      * @return list of any objects
      */
-    List<A> findByDerAttrValue(String schema, String value, boolean ignoreCaseMatch);
+    List<A> findByDerAttrValue(DerSchema schema, String value, boolean ignoreCaseMatch);
 
     List<A> findByResource(ExternalResource resource);
 
diff --git a/core/persistence-jpa-json/pom.xml b/core/persistence-jpa-json/pom.xml
index 911446e..9d8d328 100644
--- a/core/persistence-jpa-json/pom.xml
+++ b/core/persistence-jpa-json/pom.xml
@@ -241,6 +241,9 @@ under the License.
           <testResource>
             <directory>src/main/resources/pgjsonb</directory>
             <filtering>true</filtering>
+            <excludes>
+              <exclude>domains/MasterContent.xml</exclude>
+            </excludes>
           </testResource>
         </testResources>
       </build>
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/api/dao/JPAJSONAnyDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/api/dao/JPAJSONAnyDAO.java
index 9794cc8..04be3da 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/api/dao/JPAJSONAnyDAO.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/api/dao/JPAJSONAnyDAO.java
@@ -21,18 +21,28 @@ package org.apache.syncope.core.persistence.api.dao;
 import java.util.List;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 
 public interface JPAJSONAnyDAO {
 
-    <A extends Any<?>> List<A> findByDerAttrValue(
-            String table, AnyUtils anyUtils, String schemaKey, String value, boolean ignoreCaseMatch);
+    <A extends Any<?>> List<A> findByPlainAttrValue(
+            String table,
+            AnyUtils anyUtils,
+            PlainSchema schema,
+            PlainAttrValue attrValue,
+            boolean ignoreCaseMatch);
 
     <A extends Any<?>> A findByPlainAttrUniqueValue(
-            String table, AnyUtils anyUtils, String schemaKey, PlainAttrValue attrUniqueValue, boolean ignoreCaseMatch);
+            String table,
+            AnyUtils anyUtils,
+            PlainSchema schema,
+            PlainAttrValue attrUniqueValue,
+            boolean ignoreCaseMatch);
 
-    <A extends Any<?>> List<A> findByPlainAttrValue(
-            String table, AnyUtils anyUtils, String schemaKey, PlainAttrValue attrValue, boolean ignoreCaseMatch);
+    <A extends Any<?>> List<A> findByDerAttrValue(
+            String table, AnyUtils anyUtils, DerSchema schema, String value, boolean ignoreCaseMatch);
 
     <A extends Any<?>> void checkBeforeSave(String table, AnyUtils anyUtils, A any);
 }
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONAnyObjectDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONAnyObjectDAO.java
index 3e07af3..a6906bd 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONAnyObjectDAO.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONAnyObjectDAO.java
@@ -24,6 +24,8 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 
 public class JPAJSONAnyObjectDAO extends JPAAnyObjectDAO {
 
@@ -37,33 +39,32 @@ public class JPAJSONAnyObjectDAO extends JPAAnyObjectDAO {
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public List<AnyObject> findByPlainAttrValue(
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrValue,
             final boolean ignoreCaseMatch) {
 
-        return anyDAO().findByPlainAttrValue(JPAJSONAnyObject.TABLE, anyUtils(), schemaKey, attrValue, ignoreCaseMatch);
+        return anyDAO().findByPlainAttrValue(
+                JPAJSONAnyObject.TABLE, anyUtils(), schema, attrValue, ignoreCaseMatch);
     }
 
     @Override
     public AnyObject findByPlainAttrUniqueValue(
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrUniqueValue,
             final boolean ignoreCaseMatch) {
 
-        return anyDAO().findByPlainAttrUniqueValue(JPAJSONAnyObject.TABLE, anyUtils(),
-                schemaKey, attrUniqueValue, ignoreCaseMatch);
+        return anyDAO().findByPlainAttrUniqueValue(
+                JPAJSONAnyObject.TABLE, anyUtils(), schema, attrUniqueValue, ignoreCaseMatch);
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public List<AnyObject> findByDerAttrValue(
-            final String schemaKey,
+            final DerSchema schema,
             final String value,
             final boolean ignoreCaseMatch) {
 
-        return anyDAO().findByDerAttrValue(JPAJSONAnyObject.TABLE, anyUtils(), schemaKey, value, ignoreCaseMatch);
+        return anyDAO().findByDerAttrValue(JPAJSONAnyObject.TABLE, anyUtils(), schema, value, ignoreCaseMatch);
     }
 
     @Override
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONGroupDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONGroupDAO.java
index f6223ec..2eac134 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONGroupDAO.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONGroupDAO.java
@@ -24,6 +24,8 @@ import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 
 public class JPAJSONGroupDAO extends JPAGroupDAO {
 
@@ -37,33 +39,32 @@ public class JPAJSONGroupDAO extends JPAGroupDAO {
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public List<Group> findByPlainAttrValue(
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrValue,
             final boolean ignoreCaseMatch) {
 
-        return anyDAO().findByPlainAttrValue(JPAGroup.TABLE, anyUtils(), schemaKey, attrValue, ignoreCaseMatch);
+        return anyDAO().findByPlainAttrValue(
+                JPAGroup.TABLE, anyUtils(), schema, attrValue, ignoreCaseMatch);
     }
 
     @Override
     public Group findByPlainAttrUniqueValue(
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrUniqueValue,
             final boolean ignoreCaseMatch) {
 
-        return anyDAO().findByPlainAttrUniqueValue(JPAGroup.TABLE, anyUtils(),
-                schemaKey, attrUniqueValue, ignoreCaseMatch);
+        return anyDAO().findByPlainAttrUniqueValue(
+                JPAGroup.TABLE, anyUtils(), schema, attrUniqueValue, ignoreCaseMatch);
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public List<Group> findByDerAttrValue(
-            final String schemaKey,
+            final DerSchema schema,
             final String value,
             final boolean ignoreCaseMatch) {
 
-        return anyDAO().findByDerAttrValue(JPAGroup.TABLE, anyUtils(), schemaKey, value, ignoreCaseMatch);
+        return anyDAO().findByDerAttrValue(JPAGroup.TABLE, anyUtils(), schema, value, ignoreCaseMatch);
     }
 
     @Override
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONUserDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONUserDAO.java
index 62d804c..c2c43be 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONUserDAO.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAJSONUserDAO.java
@@ -26,6 +26,8 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 
 public class JPAJSONUserDAO extends JPAUserDAO {
 
@@ -39,33 +41,32 @@ public class JPAJSONUserDAO extends JPAUserDAO {
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public List<User> findByPlainAttrValue(
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrValue,
             final boolean ignoreCaseMatch) {
 
-        return anyDAO().findByPlainAttrValue(JPAJSONUser.TABLE, anyUtils(), schemaKey, attrValue, ignoreCaseMatch);
+        return anyDAO().findByPlainAttrValue(
+                JPAJSONUser.TABLE, anyUtils(), schema, attrValue, ignoreCaseMatch);
     }
 
     @Override
     public User findByPlainAttrUniqueValue(
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrUniqueValue,
             final boolean ignoreCaseMatch) {
 
-        return anyDAO().findByPlainAttrUniqueValue(JPAJSONUser.TABLE, anyUtils(),
-                schemaKey, attrUniqueValue, ignoreCaseMatch);
+        return anyDAO().findByPlainAttrUniqueValue(
+                JPAJSONUser.TABLE, anyUtils(), schema, attrUniqueValue, ignoreCaseMatch);
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public List<User> findByDerAttrValue(
-            final String schemaKey,
+            final DerSchema schema,
             final String value,
             final boolean ignoreCaseMatch) {
 
-        return anyDAO().findByDerAttrValue(JPAJSONUser.TABLE, anyUtils(), schemaKey, value, ignoreCaseMatch);
+        return anyDAO().findByDerAttrValue(JPAJSONUser.TABLE, anyUtils(), schema, value, ignoreCaseMatch);
     }
 
     @Override
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java
index 94bb72a..a68423c 100644
--- a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java
@@ -143,20 +143,19 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
     public <A extends Any<?>> List<A> findByPlainAttrValue(
             final String table,
             final AnyUtils anyUtils,
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrValue,
             final boolean ignoreCaseMatch) {
 
-        PlainSchema schema = plainSchemaDAO.find(schemaKey);
         if (schema == null) {
-            LOG.error("Invalid schema '{}'", schemaKey);
+            LOG.error("No PlainSchema");
             return Collections.<A>emptyList();
         }
 
         Query query = entityManager().createNativeQuery(
                 queryBegin(table)
                 + "WHERE " + attrValueMatch(anyUtils, schema, attrValue, ignoreCaseMatch));
-        query.setParameter(1, schemaKey);
+        query.setParameter(1, schema.getKey());
         query.setParameter(2, attrValue.getValue());
 
         return buildResult(anyUtils, query.getResultList());
@@ -167,21 +166,20 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
     public <A extends Any<?>> A findByPlainAttrUniqueValue(
             final String table,
             final AnyUtils anyUtils,
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrUniqueValue,
             final boolean ignoreCaseMatch) {
 
-        PlainSchema schema = plainSchemaDAO.find(schemaKey);
         if (schema == null) {
-            LOG.error("Invalid schema '{}'", schemaKey);
+            LOG.error("No PlainSchema");
             return null;
         }
         if (!schema.isUniqueConstraint()) {
-            LOG.error("This schema has not unique constraint: '{}'", schemaKey);
+            LOG.error("This schema has not unique constraint: '{}'", schema.getKey());
             return null;
         }
 
-        List<A> result = findByPlainAttrValue(table, anyUtils, schemaKey, attrUniqueValue, ignoreCaseMatch);
+        List<A> result = findByPlainAttrValue(table, anyUtils, schema, attrUniqueValue, ignoreCaseMatch);
         return result.isEmpty()
                 ? null
                 : result.get(0);
@@ -216,13 +214,12 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
     public <A extends Any<?>> List<A> findByDerAttrValue(
             final String table,
             final AnyUtils anyUtils,
-            final String schemaKey,
+            final DerSchema derSchema,
             final String value,
             final boolean ignoreCaseMatch) {
 
-        DerSchema derSchema = derSchemaDAO.find(schemaKey);
         if (derSchema == null) {
-            LOG.error("Invalid schema '{}'", schemaKey);
+            LOG.error("No DerSchema");
             return Collections.<A>emptyList();
         }
 
@@ -335,13 +332,14 @@ public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements JPAJ
                 filter(attr -> attr.getUniqueValue() != null).
                 map(JSONPlainAttr.class::cast).
                 forEach(attr -> {
-                    String schemaKey = attr.getSchemaKey();
-                    List<A> others = findByPlainAttrValue(table, anyUtils, schemaKey, attr.getUniqueValue(), false);
+                    PlainSchema schema = attr.getSchema();
+                    List<A> others = findByPlainAttrValue(table, anyUtils, schema, attr.getUniqueValue(), false);
                     if (others.isEmpty() || (others.size() == 1 && others.get(0).getKey().equals(any.getKey()))) {
                         LOG.debug("No duplicate value found for {}", attr.getUniqueValue().getValueAsString());
                     } else {
                         throw new DuplicateException(
-                                "Value " + attr.getUniqueValue().getValueAsString() + " existing for " + schemaKey);
+                                "Value " + attr.getUniqueValue().getValueAsString()
+                                + " existing for " + schema.getKey());
                     }
                 });
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
index 7cd75d4..f440124 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
@@ -176,13 +176,12 @@ public abstract class AbstractAnyDAO<A extends Any<?>> extends AbstractDAO<A> im
     @Override
     @SuppressWarnings("unchecked")
     public List<A> findByPlainAttrValue(
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrValue,
             final boolean ignoreCaseMatch) {
 
-        PlainSchema schema = plainSchemaDAO.find(schemaKey);
         if (schema == null) {
-            LOG.error("Invalid schema '{}'", schemaKey);
+            LOG.error("No PlainSchema");
             return Collections.<A>emptyList();
         }
 
@@ -190,7 +189,7 @@ public abstract class AbstractAnyDAO<A extends Any<?>> extends AbstractDAO<A> im
                 ? anyUtils().plainAttrUniqueValueClass().getName()
                 : anyUtils().plainAttrValueClass().getName();
         Query query = findByPlainAttrValueQuery(entityName, ignoreCaseMatch);
-        query.setParameter("schemaKey", schemaKey);
+        query.setParameter("schemaKey", schema.getKey());
         query.setParameter("stringValue", attrValue.getStringValue());
         query.setParameter("booleanValue", attrValue.getBooleanValue());
         if (attrValue.getDateValue() == null) {
@@ -214,21 +213,20 @@ public abstract class AbstractAnyDAO<A extends Any<?>> extends AbstractDAO<A> im
 
     @Override
     public A findByPlainAttrUniqueValue(
-            final String schemaKey,
+            final PlainSchema schema,
             final PlainAttrValue attrUniqueValue,
             final boolean ignoreCaseMatch) {
 
-        PlainSchema schema = plainSchemaDAO.find(schemaKey);
         if (schema == null) {
-            LOG.error("Invalid schema '{}'", schemaKey);
+            LOG.error("No PlainSchema");
             return null;
         }
         if (!schema.isUniqueConstraint()) {
-            LOG.error("This schema has not unique constraint: '{}'", schemaKey);
+            LOG.error("This schema has not unique constraint: '{}'", schema.getKey());
             return null;
         }
 
-        List<A> result = findByPlainAttrValue(schemaKey, attrUniqueValue, ignoreCaseMatch);
+        List<A> result = findByPlainAttrValue(schema, attrUniqueValue, ignoreCaseMatch);
         return result.isEmpty()
                 ? null
                 : result.get(0);
@@ -376,10 +374,9 @@ public abstract class AbstractAnyDAO<A extends Any<?>> extends AbstractDAO<A> im
     }
 
     @Override
-    public List<A> findByDerAttrValue(final String schemaKey, final String value, final boolean ignoreCaseMatch) {
-        DerSchema schema = derSchemaDAO.find(schemaKey);
+    public List<A> findByDerAttrValue(final DerSchema schema, final String value, final boolean ignoreCaseMatch) {
         if (schema == null) {
-            LOG.error("Invalid schema '{}'", schemaKey);
+            LOG.error("No DerSchema");
             return Collections.<A>emptyList();
         }
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
index 988ef58..2ed3468 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
@@ -208,7 +208,51 @@ public abstract class AbstractPlainAttrValue extends AbstractGeneratedKeyEntity
                                                 : getStringValue());
     }
 
+    private Object getValue(final AttrSchemaType type) {
+        Object value;
+        switch (type) {
+
+            case Boolean:
+                value = getBooleanValue();
+                break;
+
+            case Long:
+                value = getLongValue();
+                break;
+
+            case Double:
+                value = getDoubleValue();
+                break;
+
+            case Date:
+                value = getDateValue();
+                break;
+
+            case Binary:
+                value = getBinaryValue();
+                break;
+
+            case String:
+            case Enum:
+            case Encrypted:
+                value = getStringValue();
+                break;
+
+            default:
+                value = null;
+        }
+
+        return value;
+    }
+
     private String getValueAsString(final AttrSchemaType type, final PlainSchema schema) {
+        if (getValue(type) == null) {
+            LOG.warn("Could not find expected value for type {} in {}, reverting to getValue().toString()", type, this);
+
+            Object value = getValue();
+            return value == null ? null : value.toString();
+        }
+
         String result;
         switch (type) {
 
@@ -243,7 +287,6 @@ public abstract class AbstractPlainAttrValue extends AbstractGeneratedKeyEntity
             case Encrypted:
             default:
                 result = getStringValue();
-                break;
         }
 
         return result;
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
index b35d83b..740df30 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
@@ -29,7 +29,9 @@ import java.util.Date;
 import java.util.List;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
+import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.user.User;
@@ -58,6 +60,12 @@ public class UserTest extends AbstractTest {
     @Autowired
     private ExternalResourceDAO resourceDAO;
 
+    @Autowired
+    private PlainSchemaDAO plainSchemaDAO;
+
+    @Autowired
+    private DerSchemaDAO derSchemaDAO;
+
     @Test
     public void find() {
         User user = userDAO.find("823074dc-d280-436d-a7dd-07399fae48ec");
@@ -109,24 +117,24 @@ public class UserTest extends AbstractTest {
 
     @Test
     public void findByDerAttrValue() {
-        List<User> list = userDAO.findByDerAttrValue("cn", "Vivaldi, Antonio", false);
+        List<User> list = userDAO.findByDerAttrValue(derSchemaDAO.find("cn"), "Vivaldi, Antonio", false);
         assertEquals(1, list.size());
 
-        list = userDAO.findByDerAttrValue("cn", "VIVALDI, ANTONIO", false);
+        list = userDAO.findByDerAttrValue(derSchemaDAO.find("cn"), "VIVALDI, ANTONIO", false);
         assertEquals(0, list.size());
 
-        list = userDAO.findByDerAttrValue("cn", "VIVALDI, ANTONIO", true);
+        list = userDAO.findByDerAttrValue(derSchemaDAO.find("cn"), "VIVALDI, ANTONIO", true);
         assertEquals(1, list.size());
     }
 
     @Test
     public void findByInvalidDerAttrValue() {
-        assertTrue(userDAO.findByDerAttrValue("cn", "Antonio, Maria, Rossi", false).isEmpty());
+        assertTrue(userDAO.findByDerAttrValue(derSchemaDAO.find("cn"), "Antonio, Maria, Rossi", false).isEmpty());
     }
 
     @Test
     public void findByInvalidDerAttrExpression() {
-        assertTrue(userDAO.findByDerAttrValue("noschema", "Antonio, Maria", false).isEmpty());
+        assertTrue(userDAO.findByDerAttrValue(derSchemaDAO.find("noschema"), "Antonio, Maria", false).isEmpty());
     }
 
     @Test
@@ -134,15 +142,15 @@ public class UserTest extends AbstractTest {
         UPlainAttrUniqueValue fullnameValue = entityFactory.newEntity(UPlainAttrUniqueValue.class);
         fullnameValue.setStringValue("Gioacchino Rossini");
 
-        List<User> list = userDAO.findByPlainAttrValue("fullname", fullnameValue, false);
+        List<User> list = userDAO.findByPlainAttrValue(plainSchemaDAO.find("fullname"), fullnameValue, false);
         assertEquals(1, list.size());
 
         fullnameValue.setStringValue("Gioacchino ROSSINI");
 
-        list = userDAO.findByPlainAttrValue("fullname", fullnameValue, false);
+        list = userDAO.findByPlainAttrValue(plainSchemaDAO.find("fullname"), fullnameValue, false);
         assertEquals(0, list.size());
 
-        list = userDAO.findByPlainAttrValue("fullname", fullnameValue, true);
+        list = userDAO.findByPlainAttrValue(plainSchemaDAO.find("fullname"), fullnameValue, true);
         assertEquals(1, list.size());
     }
 
@@ -151,7 +159,7 @@ public class UserTest extends AbstractTest {
         final UPlainAttrValue coolValue = entityFactory.newEntity(UPlainAttrValue.class);
         coolValue.setBooleanValue(true);
 
-        final List<User> list = userDAO.findByPlainAttrValue("cool", coolValue, false);
+        final List<User> list = userDAO.findByPlainAttrValue(plainSchemaDAO.find("cool"), coolValue, false);
         assertEquals(1, list.size());
     }
 
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
index 46c2444..7dfe167 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
@@ -242,11 +242,11 @@ public class UserTest extends AbstractTest {
         assertNotNull(firstname);
 
         // search by ksuffix derived attribute
-        List<User> list = userDAO.findByDerAttrValue("ksuffix", firstname + "k", false);
+        List<User> list = userDAO.findByDerAttrValue(derSchemaDAO.find("ksuffix"), firstname + "k", false);
         assertEquals(1, list.size());
 
         // search by kprefix derived attribute
-        list = userDAO.findByDerAttrValue("kprefix", "k" + firstname, false);
+        list = userDAO.findByDerAttrValue(derSchemaDAO.find("kprefix"), "k" + firstname, false);
         assertEquals(1, list.size());
     }
 
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/IntAttrName.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/IntAttrName.java
index e8d5cb4..180a112 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/IntAttrName.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/IntAttrName.java
@@ -23,6 +23,7 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.core.persistence.api.entity.Schema;
 
 public class IntAttrName {
 
@@ -32,7 +33,7 @@ public class IntAttrName {
 
     private SchemaType schemaType;
 
-    private String schemaName;
+    private Schema schema;
 
     private String enclosingGroup;
 
@@ -72,12 +73,12 @@ public class IntAttrName {
         this.schemaType = schemaType;
     }
 
-    public String getSchemaName() {
-        return schemaName;
+    public Schema getSchema() {
+        return schema;
     }
 
-    public void setSchemaName(final String schemaName) {
-        this.schemaName = schemaName;
+    public void setSchema(final Schema schemaName) {
+        this.schema = schemaName;
     }
 
     public String getEnclosingGroup() {
@@ -142,7 +143,7 @@ public class IntAttrName {
                 append(anyTypeKind).
                 append(field).
                 append(schemaType).
-                append(schemaName).
+                append(schema).
                 append(enclosingGroup).
                 append(relatedUser).
                 append(relatedAnyObject).
@@ -169,7 +170,7 @@ public class IntAttrName {
                 append(anyTypeKind, other.anyTypeKind).
                 append(field, other.field).
                 append(schemaType, other.schemaType).
-                append(schemaName, other.schemaName).
+                append(schema, other.schema).
                 append(enclosingGroup, other.enclosingGroup).
                 append(relatedUser, other.relatedUser).
                 append(relatedAnyObject, other.relatedAnyObject).
@@ -186,7 +187,7 @@ public class IntAttrName {
                 append(anyTypeKind).
                 append(field).
                 append(schemaType).
-                append(schemaName).
+                append(schema).
                 append(enclosingGroup).
                 append(relatedUser).
                 append(relatedAnyObject).
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
index a7d4252..a662e58 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
@@ -24,6 +24,7 @@ import java.util.Set;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.RealmTO;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.Realm;
@@ -58,10 +59,12 @@ public interface MappingManager {
      * @param provision provision information
      * @param mapItem mapping item
      * @param intAttrName int attr name
+     * @param schemaType schema type
      * @param any any object
-     * @return attribute values.
+     * @return attribute values and their type
      */
-    List<PlainAttrValue> getIntValues(Provision provision, Item mapItem, IntAttrName intAttrName, Any<?> any);
+    Pair<AttrSchemaType, List<PlainAttrValue>> getIntValues(
+            Provision provision, Item mapItem, IntAttrName intAttrName, AttrSchemaType schemaType, Any<?> any);
 
     /**
      * Prepare attribute for sending to a connector instance.
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ItemTransformer.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ItemTransformer.java
index 4962d8f..786d8cb 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ItemTransformer.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ItemTransformer.java
@@ -19,7 +19,9 @@
 package org.apache.syncope.core.provisioning.api.data;
 
 import java.util.List;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.resource.Item;
@@ -37,15 +39,17 @@ public interface ItemTransformer {
      *
      * @param item mapping item
      * @param entity entity
+     * @param schemaType schema type
      * @param values original values
      * @return transformed values
      */
-    default List<PlainAttrValue> beforePropagation(
+    default Pair<AttrSchemaType, List<PlainAttrValue>> beforePropagation(
             Item item,
             Entity entity,
+            AttrSchemaType schemaType,
             List<PlainAttrValue> values) {
 
-        return values;
+        return Pair.of(schemaType, values);
     }
 
     /**
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/IntAttrNameParser.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/IntAttrNameParser.java
index 0a7a2c0..ab1dc4d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/IntAttrNameParser.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/IntAttrNameParser.java
@@ -22,6 +22,7 @@ import java.text.ParseException;
 import org.apache.syncope.core.provisioning.api.IntAttrName;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -66,7 +67,7 @@ public class IntAttrNameParser {
     @Autowired
     private AnyUtilsFactory anyUtilsFactory;
 
-    private SchemaType find(final String key) {
+    private Pair<Schema, SchemaType> find(final String key) {
         Schema schema = plainSchemaDAO.find(key);
         if (schema == null) {
             schema = derSchemaDAO.find(key);
@@ -75,13 +76,13 @@ public class IntAttrNameParser {
                 if (schema == null) {
                     return null;
                 } else {
-                    return SchemaType.VIRTUAL;
+                    return Pair.of(schema, SchemaType.VIRTUAL);
                 }
             } else {
-                return SchemaType.DERIVED;
+                return Pair.of(schema, SchemaType.DERIVED);
             }
         } else {
-            return SchemaType.PLAIN;
+            return Pair.of(schema, SchemaType.PLAIN);
         }
     }
 
@@ -91,8 +92,11 @@ public class IntAttrNameParser {
             final IntAttrName result) {
 
         if (anyUtilsFactory.getInstance(anyTypeKind).getField(fieldOrSchemaName) == null) {
-            result.setSchemaType(find(fieldOrSchemaName));
-            result.setSchemaName(fieldOrSchemaName);
+            Pair<Schema, SchemaType> schemaInfo = find(fieldOrSchemaName);
+            if (schemaInfo != null) {
+                result.setSchemaType(schemaInfo.getRight());
+                result.setSchema(schemaInfo.getLeft());
+            }
         } else {
             result.setField(fieldOrSchemaName);
         }
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 d9d992d..c7bf964 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
@@ -46,13 +46,10 @@ import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.ApplicationDAO;
-import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.dao.RelationshipTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
-import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -67,7 +64,6 @@ import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Relationship;
 import org.apache.syncope.core.persistence.api.entity.RelationshipType;
-import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
@@ -112,15 +108,6 @@ public class MappingManagerImpl implements MappingManager {
     private AnyTypeDAO anyTypeDAO;
 
     @Autowired
-    private PlainSchemaDAO plainSchemaDAO;
-
-    @Autowired
-    private DerSchemaDAO derSchemaDAO;
-
-    @Autowired
-    private VirSchemaDAO virSchemaDAO;
-
-    @Autowired
     private UserDAO userDAO;
 
     @Autowired
@@ -319,36 +306,26 @@ public class MappingManagerImpl implements MappingManager {
             return null;
         }
 
-        boolean readOnlyVirSchema = false;
-        Schema schema = null;
-        AttrSchemaType schemaType = AttrSchemaType.String;
-        if (intAttrName.getSchemaType() != null) {
-            switch (intAttrName.getSchemaType()) {
-                case PLAIN:
-                    schema = plainSchemaDAO.find(intAttrName.getSchemaName());
-                    if (schema != null) {
-                        schemaType = schema.getType();
-                    }
-                    break;
-
-                case VIRTUAL:
-                    schema = virSchemaDAO.find(intAttrName.getSchemaName());
-                    readOnlyVirSchema = (schema != null && schema.isReadonly());
-                    break;
+        AttrSchemaType schemaType = intAttrName.getSchema() instanceof PlainSchema
+                ? ((PlainSchema) intAttrName.getSchema()).getType()
+                : AttrSchemaType.String;
+        boolean readOnlyVirSchema = intAttrName.getSchema() instanceof VirSchema
+                ? intAttrName.getSchema().isReadonly()
+                : false;
 
-                default:
-            }
-        }
-
-        List<PlainAttrValue> values = getIntValues(provision, item, intAttrName, any);
+        Pair<AttrSchemaType, List<PlainAttrValue>> intValues =
+                getIntValues(provision, item, intAttrName, schemaType, any);
+        schemaType = intValues.getLeft();
+        List<PlainAttrValue> values = intValues.getRight();
 
         LOG.debug("Define mapping for: "
                 + "\n* ExtAttrName " + item.getExtAttrName()
                 + "\n* is connObjectKey " + item.isConnObjectKey()
                 + "\n* is password " + item.isPassword()
                 + "\n* mandatory condition " + item.getMandatoryCondition()
-                + "\n* Schema " + intAttrName.getSchemaName()
+                + "\n* Schema " + intAttrName.getSchema()
                 + "\n* ClassType " + schemaType.getType().getName()
+                + "\n* AttrSchemaType " + schemaType
                 + "\n* Values " + values);
 
         Pair<String, Attribute> result;
@@ -361,10 +338,13 @@ public class MappingManagerImpl implements MappingManager {
                 if (FrameworkUtil.isSupportedAttributeType(schemaType.getType())) {
                     objValues.add(value.getValue());
                 } else {
-                    if (schema instanceof PlainSchema) {
-                        objValues.add(value.getValueAsString((PlainSchema) schema));
-                    } else {
+                    PlainSchema plainSchema = intAttrName.getSchema() instanceof PlainSchema
+                            ? (PlainSchema) intAttrName.getSchema()
+                            : null;
+                    if (plainSchema == null || plainSchema.getType() != schemaType) {
                         objValues.add(value.getValueAsString(schemaType));
+                    } else {
+                        objValues.add(value.getValueAsString(plainSchema));
                     }
                 }
             }
@@ -407,10 +387,11 @@ public class MappingManagerImpl implements MappingManager {
 
     @Transactional(readOnly = true)
     @Override
-    public List<PlainAttrValue> getIntValues(
+    public Pair<AttrSchemaType, List<PlainAttrValue>> getIntValues(
             final Provision provision,
             final Item mapItem,
             final IntAttrName intAttrName,
+            final AttrSchemaType schemaType,
             final Any<?> any) {
 
         LOG.debug("Get internal values for {} as '{}' on {}", any, mapItem.getIntAttrName(), provision.getResource());
@@ -474,7 +455,7 @@ public class MappingManagerImpl implements MappingManager {
         }
         if (references.isEmpty()) {
             LOG.warn("Could not determine the reference instance for {}", mapItem.getIntAttrName());
-            return Collections.emptyList();
+            return Pair.of(schemaType, Collections.<PlainAttrValue>emptyList());
         }
 
         List<PlainAttrValue> values = new ArrayList<>();
@@ -566,14 +547,14 @@ public class MappingManagerImpl implements MappingManager {
                     case PLAIN:
                         PlainAttr<?> attr;
                         if (membership == null) {
-                            attr = reference.getPlainAttr(intAttrName.getSchemaName()).orElse(null);
+                            attr = reference.getPlainAttr(intAttrName.getSchema().getKey()).orElse(null);
                         } else {
                             attr = ((GroupableRelatable<?, ?, ?, ?, ?>) reference).getPlainAttr(
-                                    intAttrName.getSchemaName(), membership).orElse(null);
+                                    intAttrName.getSchema().getKey(), membership).orElse(null);
                         }
                         if (attr == null) {
                             LOG.warn("Invalid PlainSchema {} or PlainAttr not found for {}",
-                                    intAttrName.getSchemaName(), reference);
+                                    intAttrName.getSchema().getKey(), reference);
                         } else {
                             if (attr.getUniqueValue() != null) {
                                 values.add(anyUtils.clonePlainAttrValue(attr.getUniqueValue()));
@@ -584,18 +565,14 @@ public class MappingManagerImpl implements MappingManager {
                         break;
 
                     case DERIVED:
-                        DerSchema derSchema = derSchemaDAO.find(intAttrName.getSchemaName());
-                        if (derSchema == null) {
-                            LOG.warn("Invalid DerSchema: {}", intAttrName.getSchemaName());
-                        } else {
-                            String derValue = membership == null
-                                    ? derAttrHandler.getValue(reference, derSchema)
-                                    : derAttrHandler.getValue(reference, membership, derSchema);
-                            if (derValue != null) {
-                                PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                                attrValue.setStringValue(derValue);
-                                values.add(attrValue);
-                            }
+                        DerSchema derSchema = (DerSchema) intAttrName.getSchema();
+                        String derValue = membership == null
+                                ? derAttrHandler.getValue(reference, derSchema)
+                                : derAttrHandler.getValue(reference, membership, derSchema);
+                        if (derValue != null) {
+                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                            attrValue.setStringValue(derValue);
+                            values.add(attrValue);
                         }
                         break;
 
@@ -603,23 +580,19 @@ public class MappingManagerImpl implements MappingManager {
                         // virtual attributes don't get transformed
                         transform = false;
 
-                        VirSchema virSchema = virSchemaDAO.find(intAttrName.getSchemaName());
-                        if (virSchema == null) {
-                            LOG.warn("Invalid VirSchema: {}", intAttrName.getSchemaName());
-                        } else {
-                            LOG.debug("Expire entry cache {}-{}", reference, intAttrName.getSchemaName());
-                            virAttrCache.expire(
-                                    reference.getType().getKey(), reference.getKey(), intAttrName.getSchemaName());
-
-                            List<String> virValues = membership == null
-                                    ? virAttrHandler.getValues(reference, virSchema)
-                                    : virAttrHandler.getValues(reference, membership, virSchema);
-                            virValues.forEach(virValue -> {
-                                PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                                attrValue.setStringValue(virValue);
-                                values.add(attrValue);
-                            });
-                        }
+                        VirSchema virSchema = (VirSchema) intAttrName.getSchema();
+                        LOG.debug("Expire entry cache {}-{}", reference, intAttrName.getSchema().getKey());
+                        virAttrCache.expire(
+                                reference.getType().getKey(), reference.getKey(), intAttrName.getSchema().getKey());
+
+                        List<String> virValues = membership == null
+                                ? virAttrHandler.getValues(reference, virSchema)
+                                : virAttrHandler.getValues(reference, membership, virSchema);
+                        virValues.forEach(virValue -> {
+                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                            attrValue.setStringValue(virValue);
+                            values.add(attrValue);
+                        });
                         break;
 
                     default:
@@ -642,17 +615,17 @@ public class MappingManagerImpl implements MappingManager {
 
         LOG.debug("Internal values: {}", values);
 
-        List<PlainAttrValue> transformed = values;
+        Pair<AttrSchemaType, List<PlainAttrValue>> trans = Pair.of(schemaType, values);
         if (transform) {
             for (ItemTransformer transformer : MappingUtils.getItemTransformers(mapItem)) {
-                transformed = transformer.beforePropagation(mapItem, any, transformed);
+                trans = transformer.beforePropagation(mapItem, any, trans.getLeft(), trans.getRight());
             }
             LOG.debug("Transformed values: {}", values);
         } else {
             LOG.debug("No transformation occurred");
         }
 
-        return transformed;
+        return trans;
     }
 
     private String getGroupOwnerValue(final Provision provision, final Any<?> any) {
@@ -672,20 +645,21 @@ public class MappingManagerImpl implements MappingManager {
     @Override
     public Optional<String> getConnObjectKeyValue(final Any<?> any, final Provision provision) {
         MappingItem mapItem = provision.getMapping().getConnObjectKeyItem().get();
-        List<PlainAttrValue> values;
+        Pair<AttrSchemaType, List<PlainAttrValue>> intValues;
         try {
-            values = getIntValues(
+            intValues = getIntValues(
                     provision,
                     mapItem,
                     intAttrNameParser.parse(mapItem.getIntAttrName(), provision.getAnyType().getKind()),
+                    AttrSchemaType.String,
                     any);
         } catch (ParseException e) {
             LOG.error("Invalid intAttrName '{}' specified, ignoring", mapItem.getIntAttrName(), e);
-            values = Collections.emptyList();
+            intValues = Pair.of(AttrSchemaType.String, Collections.<PlainAttrValue>emptyList());
         }
-        return Optional.ofNullable(values.isEmpty()
+        return Optional.ofNullable(intValues.getRight().isEmpty()
                 ? null
-                : values.get(0).getValueAsString());
+                : intValues.getRight().get(0).getValueAsString());
     }
 
     @Transactional(readOnly = true)
@@ -783,9 +757,9 @@ public class MappingManagerImpl implements MappingManager {
             switch (intAttrName.getSchemaType()) {
                 case PLAIN:
                     Attr attrTO = new Attr();
-                    attrTO.setSchema(intAttrName.getSchemaName());
+                    attrTO.setSchema(intAttrName.getSchema().getKey());
 
-                    PlainSchema schema = plainSchemaDAO.find(intAttrName.getSchemaName());
+                    PlainSchema schema = (PlainSchema) intAttrName.getSchema();
 
                     for (Object value : values) {
                         AttrSchemaType schemaType = schema == null ? AttrSchemaType.String : schema.getType();
@@ -812,7 +786,7 @@ public class MappingManagerImpl implements MappingManager {
 
                 case DERIVED:
                     attrTO = new Attr();
-                    attrTO.setSchema(intAttrName.getSchemaName());
+                    attrTO.setSchema(intAttrName.getSchema().getKey());
 
                     if (groupableTO == null || group == null) {
                         anyTO.getDerAttrs().add(attrTO);
@@ -828,7 +802,7 @@ public class MappingManagerImpl implements MappingManager {
 
                 case VIRTUAL:
                     attrTO = new Attr();
-                    attrTO.setSchema(intAttrName.getSchemaName());
+                    attrTO.setSchema(intAttrName.getSchema().getKey());
 
                     // virtual attributes don't get transformed, iterate over original attr.getValue()
                     if (attr.getValue() != null && !attr.getValue().isEmpty()) {
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 61851e6..96e986d 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
@@ -29,6 +29,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.request.AnyCR;
@@ -39,6 +40,7 @@ import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.Attr;
 import org.apache.syncope.common.lib.to.MembershipTO;
 import org.apache.syncope.common.lib.to.RelationshipTO;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.common.lib.types.ResourceOperation;
@@ -209,9 +211,16 @@ abstract class AbstractAnyDataBinder {
             } catch (ParseException e) {
                 LOG.error("Invalid intAttrName '{}', ignoring", mapItem.getIntAttrName(), e);
             }
-            if (intAttrName != null && intAttrName.getSchemaType() != null) {
-                List<PlainAttrValue> values = mappingManager.getIntValues(provision, mapItem, intAttrName, any);
-                if (values.isEmpty() && JexlUtils.evaluateMandatoryCondition(mapItem.getMandatoryCondition(), any)) {
+            if (intAttrName != null && intAttrName.getSchema() != null) {
+                AttrSchemaType schemaType = intAttrName.getSchema() instanceof PlainSchema
+                        ? ((PlainSchema) intAttrName.getSchema()).getType()
+                        : AttrSchemaType.String;
+
+                Pair<AttrSchemaType, List<PlainAttrValue>> intValues =
+                        mappingManager.getIntValues(provision, mapItem, intAttrName, schemaType, any);
+                if (intValues.getRight().isEmpty()
+                        && JexlUtils.evaluateMandatoryCondition(mapItem.getMandatoryCondition(), any)) {
+
                     missingAttrNames.add(mapItem.getIntAttrName());
                 }
             }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLItemTransformerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLItemTransformerImpl.java
index d7cca45..e3d69e5 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLItemTransformerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLItemTransformerImpl.java
@@ -23,9 +23,11 @@ import java.util.List;
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.commons.jexl3.MapContext;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.common.lib.to.RealmTO;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
@@ -50,9 +52,10 @@ public class JEXLItemTransformerImpl implements JEXLItemTransformer {
     }
 
     @Override
-    public List<PlainAttrValue> beforePropagation(
+    public Pair<AttrSchemaType, List<PlainAttrValue>> beforePropagation(
             final Item item,
             final Entity entity,
+            final AttrSchemaType schemaType,
             final List<PlainAttrValue> values) {
 
         if (StringUtils.isNotBlank(propagationJEXL) && values != null) {
@@ -67,7 +70,7 @@ public class JEXLItemTransformerImpl implements JEXLItemTransformer {
                             JexlUtils.addDerAttrsToContext(((Any<?>) entity), jexlContext);
                         }
                     }
-                    jexlContext.set("value", originalValue.toString());
+                    jexlContext.set("value", originalValue);
 
                     value.setBinaryValue(null);
                     value.setBooleanValue(null);
@@ -78,10 +81,10 @@ public class JEXLItemTransformerImpl implements JEXLItemTransformer {
                 }
             });
 
-            return values;
+            return Pair.of(AttrSchemaType.String, values);
         }
 
-        return JEXLItemTransformer.super.beforePropagation(item, entity, values);
+        return JEXLItemTransformer.super.beforePropagation(item, entity, schemaType, values);
     }
 
     @Override
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 c9f6eb0..6725466 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
@@ -453,15 +453,15 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
 
                         switch (intAttrName.getSchemaType()) {
                             case PLAIN:
-                                allowed = allowedSchemas.getPlainSchemas().contains(intAttrName.getSchemaName());
+                                allowed = allowedSchemas.getPlainSchemas().contains(intAttrName.getSchema().getKey());
                                 break;
 
                             case DERIVED:
-                                allowed = allowedSchemas.getDerSchemas().contains(intAttrName.getSchemaName());
+                                allowed = allowedSchemas.getDerSchemas().contains(intAttrName.getSchema().getKey());
                                 break;
 
                             case VIRTUAL:
-                                allowed = allowedSchemas.getVirSchemas().contains(intAttrName.getSchemaName());
+                                allowed = allowedSchemas.getVirSchemas().contains(intAttrName.getSchema().getKey());
                                 break;
 
                             default:
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
index 34175db..330172d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
@@ -41,6 +42,7 @@ import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
@@ -278,12 +280,11 @@ public class PullUtils {
                 case PLAIN:
                     PlainAttrValue value = anyUtils.newPlainAttrValue();
 
-                    PlainSchema schema = plainSchemaDAO.find(intAttrName.getSchemaName());
-                    if (schema == null) {
+                    if (intAttrName.getSchemaType() == SchemaType.PLAIN) {
                         value.setStringValue(connObjectKey);
                     } else {
                         try {
-                            value.parseValue(schema, connObjectKey);
+                            value.parseValue((PlainSchema) intAttrName.getSchema(), connObjectKey);
                         } catch (ParsingValidationException e) {
                             LOG.error("While parsing provided __UID__ {}", value, e);
                             value.setStringValue(connObjectKey);
@@ -291,13 +292,13 @@ public class PullUtils {
                     }
 
                     result.addAll(anyUtils.dao().findByPlainAttrValue(
-                            intAttrName.getSchemaName(), value, provision.isIgnoreCaseMatch()).
+                            (PlainSchema) intAttrName.getSchema(), value, provision.isIgnoreCaseMatch()).
                             stream().map(Entity::getKey).collect(Collectors.toList()));
                     break;
 
                 case DERIVED:
                     result.addAll(anyUtils.dao().findByDerAttrValue(
-                            intAttrName.getSchemaName(), connObjectKey, provision.isIgnoreCaseMatch()).
+                            (DerSchema) intAttrName.getSchema(), connObjectKey, provision.isIgnoreCaseMatch()).
                             stream().map(Entity::getKey).collect(Collectors.toList()));
                     break;
 
diff --git a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/IntAttrNameParserTest.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/IntAttrNameParserTest.java
index 205300f..b10a4b9 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/IntAttrNameParserTest.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/IntAttrNameParserTest.java
@@ -21,11 +21,15 @@ package org.apache.syncope.core.provisioning.java;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.text.ParseException;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.provisioning.api.IntAttrName;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -44,7 +48,7 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertEquals(AnyTypeKind.USER, intAttrName.getAnyTypeKind());
         assertNotNull(intAttrName.getField());
         assertEquals("key", intAttrName.getField());
-        assertNull(intAttrName.getSchemaName());
+        assertNull(intAttrName.getSchema());
         assertNull(intAttrName.getSchemaType());
         assertNull(intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getMembershipOfGroup());
@@ -59,7 +63,7 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertEquals(AnyTypeKind.GROUP, intAttrName.getAnyTypeKind());
         assertNotNull(intAttrName.getField());
         assertEquals("name", intAttrName.getField());
-        assertNull(intAttrName.getSchemaName());
+        assertNull(intAttrName.getSchema());
         assertNull(intAttrName.getSchemaType());
         assertNull(intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getMembershipOfGroup());
@@ -74,7 +78,7 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertEquals(AnyTypeKind.GROUP, intAttrName.getAnyTypeKind());
         assertNotNull(intAttrName.getField());
         assertEquals("userOwner", intAttrName.getField());
-        assertNull(intAttrName.getSchemaName());
+        assertNull(intAttrName.getSchema());
         assertNull(intAttrName.getSchemaType());
         assertNull(intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getMembershipOfGroup());
@@ -96,8 +100,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNotNull(intAttrName);
         assertEquals(AnyTypeKind.USER, intAttrName.getAnyTypeKind());
         assertNull(intAttrName.getField());
-        assertEquals("email", intAttrName.getSchemaName());
+        assertEquals("email", intAttrName.getSchema().getKey());
         assertEquals(SchemaType.PLAIN, intAttrName.getSchemaType());
+        assertTrue(intAttrName.getSchema() instanceof PlainSchema);
         assertNull(intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
@@ -110,8 +115,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNotNull(intAttrName);
         assertEquals(AnyTypeKind.ANY_OBJECT, intAttrName.getAnyTypeKind());
         assertNull(intAttrName.getField());
-        assertEquals("cn", intAttrName.getSchemaName());
+        assertEquals("cn", intAttrName.getSchema().getKey());
         assertEquals(SchemaType.DERIVED, intAttrName.getSchemaType());
+        assertTrue(intAttrName.getSchema() instanceof DerSchema);
         assertNull(intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
@@ -124,8 +130,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNotNull(intAttrName);
         assertEquals(AnyTypeKind.ANY_OBJECT, intAttrName.getAnyTypeKind());
         assertNull(intAttrName.getField());
-        assertEquals("rvirtualdata", intAttrName.getSchemaName());
+        assertEquals("rvirtualdata", intAttrName.getSchema().getKey());
         assertEquals(SchemaType.VIRTUAL, intAttrName.getSchemaType());
+        assertTrue(intAttrName.getSchema() instanceof VirSchema);
         assertNull(intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
@@ -141,8 +148,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNotNull(intAttrName);
         assertEquals(AnyTypeKind.GROUP, intAttrName.getAnyTypeKind());
         assertNull(intAttrName.getField());
-        assertEquals("cn", intAttrName.getSchemaName());
+        assertEquals("cn", intAttrName.getSchema().getKey());
         assertEquals(SchemaType.DERIVED, intAttrName.getSchemaType());
+        assertTrue(intAttrName.getSchema() instanceof DerSchema);
         assertEquals("readers", intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
@@ -158,8 +166,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNotNull(intAttrName);
         assertEquals(AnyTypeKind.USER, intAttrName.getAnyTypeKind());
         assertNull(intAttrName.getField());
-        assertEquals("firstname", intAttrName.getSchemaName());
+        assertEquals("firstname", intAttrName.getSchema().getKey());
         assertEquals(SchemaType.PLAIN, intAttrName.getSchemaType());
+        assertTrue(intAttrName.getSchema() instanceof PlainSchema);
         assertEquals("bellini", intAttrName.getRelatedUser());
         assertNull(intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getMembershipOfGroup());
@@ -175,7 +184,7 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNotNull(intAttrName);
         assertEquals(AnyTypeKind.ANY_OBJECT, intAttrName.getAnyTypeKind());
         assertEquals("name", intAttrName.getField());
-        assertNull(intAttrName.getSchemaName());
+        assertNull(intAttrName.getSchema());
         assertNull(intAttrName.getSchemaType());
         assertNull(intAttrName.getEnclosingGroup());
         assertEquals("hp", intAttrName.getRelatedAnyObject());
@@ -192,8 +201,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNotNull(intAttrName);
         assertEquals(AnyTypeKind.USER, intAttrName.getAnyTypeKind());
         assertNull(intAttrName.getField());
-        assertEquals("cn", intAttrName.getSchemaName());
+        assertEquals("cn", intAttrName.getSchema().getKey());
         assertEquals(SchemaType.DERIVED, intAttrName.getSchemaType());
+        assertTrue(intAttrName.getSchema() instanceof DerSchema);
         assertNull(intAttrName.getEnclosingGroup());
         assertEquals("top", intAttrName.getMembershipOfGroup());
         assertNull(intAttrName.getRelatedAnyObject());
@@ -209,7 +219,7 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNotNull(intAttrName);
         assertEquals(AnyTypeKind.USER, intAttrName.getAnyTypeKind());
         assertNull(intAttrName.getField());
-        assertNull(intAttrName.getSchemaName());
+        assertNull(intAttrName.getSchema());
         assertNull(intAttrName.getSchemaType());
         assertNull(intAttrName.getEnclosingGroup());
         assertNull(intAttrName.getRelatedAnyObject());
@@ -226,8 +236,9 @@ public class IntAttrNameParserTest extends AbstractTest {
         assertNotNull(intAttrName);
         assertEquals(AnyTypeKind.ANY_OBJECT, intAttrName.getAnyTypeKind());
         assertNull(intAttrName.getField());
-        assertEquals("location", intAttrName.getSchemaName());
+        assertEquals("location", intAttrName.getSchema().getKey());
         assertEquals(SchemaType.PLAIN, intAttrName.getSchemaType());
+        assertTrue(intAttrName.getSchema() instanceof PlainSchema);
         assertEquals("inclusion", intAttrName.getRelationshipType());
         assertEquals("PRINTER", intAttrName.getRelationshipAnyType());
         assertNull(intAttrName.getEnclosingGroup());
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 de2b42a..d0f321e 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
@@ -36,9 +36,11 @@ import org.apache.syncope.common.lib.to.OIDCLoginResponseTO;
 import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.OIDCProvider;
 import org.apache.syncope.core.persistence.api.entity.OIDCProviderItem;
@@ -135,24 +137,25 @@ public class OIDCUserManager {
                 case PLAIN:
                     PlainAttrValue value = entityFactory.newEntity(UPlainAttrValue.class);
 
-                    PlainSchema schema = plainSchemaDAO.find(intAttrName.getSchemaName());
-                    if (schema == null) {
+                    if (intAttrName.getSchemaType() == SchemaType.PLAIN) {
                         value.setStringValue(transformed);
                     } else {
                         try {
-                            value.parseValue(schema, transformed);
+                            value.parseValue((PlainSchema) intAttrName.getSchema(), transformed);
                         } catch (ParsingValidationException e) {
                             LOG.error("While parsing provided key value {}", transformed, e);
                             value.setStringValue(transformed);
                         }
                     }
 
-                    result.addAll(userDAO.findByPlainAttrValue(intAttrName.getSchemaName(), value, false).stream().
+                    result.addAll(userDAO.findByPlainAttrValue(
+                            (PlainSchema) intAttrName.getSchema(), value, false).stream().
                             map(User::getUsername).collect(Collectors.toList()));
                     break;
 
                 case DERIVED:
-                    result.addAll(userDAO.findByDerAttrValue(intAttrName.getSchemaName(), transformed, false).stream().
+                    result.addAll(userDAO.findByDerAttrValue(
+                            (DerSchema) intAttrName.getSchema(), transformed, false).stream().
                             map(User::getUsername).collect(Collectors.toList()));
                     break;
 
@@ -221,18 +224,18 @@ public class OIDCUserManager {
             } else if (intAttrName != null && intAttrName.getSchemaType() != null) {
                 switch (intAttrName.getSchemaType()) {
                     case PLAIN:
-                        Optional<Attr> attr = userTO.getPlainAttr(intAttrName.getSchemaName());
+                        Optional<Attr> attr = userTO.getPlainAttr(intAttrName.getSchema().getKey());
                         if (attr.isPresent()) {
                             attr.get().getValues().clear();
                         } else {
-                            attr = Optional.of(new Attr.Builder(intAttrName.getSchemaName()).build());
+                            attr = Optional.of(new Attr.Builder(intAttrName.getSchema().getKey()).build());
                             userTO.getPlainAttrs().add(attr.get());
                         }
                         attr.get().getValues().addAll(values);
                         break;
 
                     default:
-                        LOG.warn("Unsupported: {} {}", intAttrName.getSchemaType(), intAttrName.getSchemaName());
+                        LOG.warn("Unsupported: {} {}", intAttrName.getSchemaType(), intAttrName.getSchema().getKey());
                 }
             }
         });
diff --git a/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
index bf3c5bb..45f19ab 100644
--- a/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
+++ b/ext/oidcclient/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/OIDCProviderDataBinderImpl.java
@@ -107,15 +107,15 @@ public class OIDCProviderDataBinderImpl implements OIDCProviderDataBinder {
                             && intAttrName.getRelatedAnyObject() == null) {
                         switch (intAttrName.getSchemaType()) {
                             case PLAIN:
-                                allowed = allowedSchemas.getPlainSchemas().contains(intAttrName.getSchemaName());
+                                allowed = allowedSchemas.getPlainSchemas().contains(intAttrName.getSchema().getKey());
                                 break;
 
                             case DERIVED:
-                                allowed = allowedSchemas.getDerSchemas().contains(intAttrName.getSchemaName());
+                                allowed = allowedSchemas.getDerSchemas().contains(intAttrName.getSchema().getKey());
                                 break;
 
                             case VIRTUAL:
-                                allowed = allowedSchemas.getVirSchemas().contains(intAttrName.getSchemaName());
+                                allowed = allowedSchemas.getVirSchemas().contains(intAttrName.getSchema().getKey());
                                 break;
 
                             default:
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 1934a24..81c3373 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
@@ -36,10 +36,12 @@ import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.SAML2LoginResponseTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.SAML2IdPDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
@@ -145,24 +147,25 @@ public class SAML2UserManager {
                 case PLAIN:
                     PlainAttrValue value = entityFactory.newEntity(UPlainAttrValue.class);
 
-                    PlainSchema schema = plainSchemaDAO.find(intAttrName.getSchemaName());
-                    if (schema == null) {
+                    if (intAttrName.getSchemaType() == SchemaType.PLAIN) {
                         value.setStringValue(transformed);
                     } else {
                         try {
-                            value.parseValue(schema, transformed);
+                            value.parseValue((PlainSchema) intAttrName.getSchema(), transformed);
                         } catch (ParsingValidationException e) {
                             LOG.error("While parsing provided key value {}", transformed, e);
                             value.setStringValue(transformed);
                         }
                     }
 
-                    result.addAll(userDAO.findByPlainAttrValue(intAttrName.getSchemaName(), value, false).stream().
+                    result.addAll(userDAO.findByPlainAttrValue(
+                            (PlainSchema) intAttrName.getSchema(), value, false).stream().
                             map(User::getUsername).collect(Collectors.toList()));
                     break;
 
                 case DERIVED:
-                    result.addAll(userDAO.findByDerAttrValue(intAttrName.getSchemaName(), transformed, false).stream().
+                    result.addAll(userDAO.findByDerAttrValue(
+                            (DerSchema) intAttrName.getSchema(), transformed, false).stream().
                             map(User::getUsername).collect(Collectors.toList()));
                     break;
 
@@ -235,18 +238,18 @@ public class SAML2UserManager {
             } else if (intAttrName != null && intAttrName.getSchemaType() != null) {
                 switch (intAttrName.getSchemaType()) {
                     case PLAIN:
-                        Optional<Attr> attr = userTO.getPlainAttr(intAttrName.getSchemaName());
+                        Optional<Attr> attr = userTO.getPlainAttr(intAttrName.getSchema().getKey());
                         if (attr.isPresent()) {
                             attr.get().getValues().clear();
                         } else {
-                            attr = Optional.of(new Attr.Builder(intAttrName.getSchemaName()).build());
+                            attr = Optional.of(new Attr.Builder(intAttrName.getSchema().getKey()).build());
                             userTO.getPlainAttrs().add(attr.get());
                         }
                         attr.get().getValues().addAll(values);
                         break;
 
                     default:
-                        LOG.warn("Unsupported: {} {}", intAttrName.getSchemaType(), intAttrName.getSchemaName());
+                        LOG.warn("Unsupported: {} {}", intAttrName.getSchemaType(), intAttrName.getSchema().getKey());
                 }
             }
         });
diff --git a/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java b/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
index fe0f8f0..7f2a482 100644
--- a/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
+++ b/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
@@ -105,15 +105,15 @@ public class SAML2IdPDataBinderImpl implements SAML2IdPDataBinder {
                             && intAttrName.getRelatedAnyObject() == null) {
                         switch (intAttrName.getSchemaType()) {
                             case PLAIN:
-                                allowed = allowedSchemas.getPlainSchemas().contains(intAttrName.getSchemaName());
+                                allowed = allowedSchemas.getPlainSchemas().contains(intAttrName.getSchema().getKey());
                                 break;
 
                             case DERIVED:
-                                allowed = allowedSchemas.getDerSchemas().contains(intAttrName.getSchemaName());
+                                allowed = allowedSchemas.getDerSchemas().contains(intAttrName.getSchema().getKey());
                                 break;
 
                             case VIRTUAL:
-                                allowed = allowedSchemas.getVirSchemas().contains(intAttrName.getSchemaName());
+                                allowed = allowedSchemas.getVirSchemas().contains(intAttrName.getSchema().getKey());
                                 break;
 
                             default:
diff --git a/fit/core-reference/src/test/resources/PrefixItemTransformer.groovy b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToDateItemTransformer.java
similarity index 51%
copy from fit/core-reference/src/test/resources/PrefixItemTransformer.groovy
copy to fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToDateItemTransformer.java
index c26aef1..7e4f042 100644
--- a/fit/core-reference/src/test/resources/PrefixItemTransformer.groovy
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToDateItemTransformer.java
@@ -16,52 +16,35 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import java.util.ArrayList;
-import groovy.transform.CompileStatic
+package org.apache.syncope.fit.core.reference;
+
+import java.util.Calendar;
 import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.resource.Item;
 import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
 
-@CompileStatic
-class PrefixItemTransformer implements ItemTransformer {
-	
-  public static String PREFIX = "PREFIX_";
-
-  @Override
-  List<PlainAttrValue> beforePropagation(
-    Item item,
-    Entity entity,
-    List<PlainAttrValue> values) {
-
-    if (values == null || values.isEmpty() || values.get(0).getStringValue() == null) {
-      return values;
-    } else {
-      String value = values.get(0).getStringValue();
-      values.get(0).setStringValue(PREFIX + value);
-
-      return values;
-    }
-  }
-
-  @Override
-  List<Object> beforePull(
-    Item item,
-    EntityTO entityTO,
-    List<Object> values) {
-
-    if (values == null || values.isEmpty() || values.get(0) == null) {
-      return values;
-    } else {
-      List<Object> newValues = new ArrayList<>(values);
-      newValues.set(0, StringUtils.substringAfter(values.get(0).toString(), PREFIX));
-
-      return newValues;
+public class DateToDateItemTransformer implements ItemTransformer {
+
+    @Override
+    public Pair<AttrSchemaType, List<PlainAttrValue>> beforePropagation(
+            final Item item,
+            final Entity entity,
+            final AttrSchemaType schemaType,
+            final List<PlainAttrValue> values) {
+
+        if (values == null || values.isEmpty() || values.get(0).getDateValue() == null) {
+            return ItemTransformer.super.beforePropagation(item, entity, schemaType, values);
+        } else {
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(values.get(0).getDateValue());
+            cal.add(Calendar.DAY_OF_MONTH, 1);
+            values.get(0).setDateValue(cal.getTime());
+
+            return Pair.of(schemaType, values);
+        }
     }
-  }
-
 }
-
diff --git a/fit/core-reference/src/test/resources/PrefixItemTransformer.groovy b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToLongItemTransformer.java
similarity index 51%
copy from fit/core-reference/src/test/resources/PrefixItemTransformer.groovy
copy to fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToLongItemTransformer.java
index c26aef1..a54bb05 100644
--- a/fit/core-reference/src/test/resources/PrefixItemTransformer.groovy
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DateToLongItemTransformer.java
@@ -16,52 +16,36 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import java.util.ArrayList;
-import groovy.transform.CompileStatic
+package org.apache.syncope.fit.core.reference;
+
 import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.resource.Item;
 import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
 
-@CompileStatic
-class PrefixItemTransformer implements ItemTransformer {
-	
-  public static String PREFIX = "PREFIX_";
-
-  @Override
-  List<PlainAttrValue> beforePropagation(
-    Item item,
-    Entity entity,
-    List<PlainAttrValue> values) {
-
-    if (values == null || values.isEmpty() || values.get(0).getStringValue() == null) {
-      return values;
-    } else {
-      String value = values.get(0).getStringValue();
-      values.get(0).setStringValue(PREFIX + value);
-
-      return values;
-    }
-  }
-
-  @Override
-  List<Object> beforePull(
-    Item item,
-    EntityTO entityTO,
-    List<Object> values) {
-
-    if (values == null || values.isEmpty() || values.get(0) == null) {
-      return values;
-    } else {
-      List<Object> newValues = new ArrayList<>(values);
-      newValues.set(0, StringUtils.substringAfter(values.get(0).toString(), PREFIX));
-
-      return newValues;
+public class DateToLongItemTransformer implements ItemTransformer {
+
+    @Override
+    public Pair<AttrSchemaType, List<PlainAttrValue>> beforePropagation(
+            final Item item,
+            final Entity entity,
+            final AttrSchemaType schemaType,
+            final List<PlainAttrValue> values) {
+
+        if (values == null || values.isEmpty() || values.get(0).getDateValue() == null) {
+            return ItemTransformer.super.beforePropagation(item, entity, schemaType, values);
+        } else {
+            values.get(0).setLongValue(values.get(0).getDateValue().getTime());
+            values.get(0).setBinaryValue(null);
+            values.get(0).setBooleanValue(null);
+            values.get(0).setDateValue(null);
+            values.get(0).setDoubleValue(null);
+            values.get(0).setStringValue(null);
+
+            return Pair.of(AttrSchemaType.Long, values);
+        }
     }
-  }
-
 }
-
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
index 0bccc53..2d333a7 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
@@ -175,6 +175,8 @@ public class ITImplementationLookup implements ImplementationLookup {
             put(ImplementationType.PASSWORD_RULE, classNames);
 
             classNames = new HashSet<>();
+            classNames.add(DateToDateItemTransformer.class.getName());
+            classNames.add(DateToLongItemTransformer.class.getName());
             put(ImplementationType.ITEM_TRANSFORMER, classNames);
 
             classNames = new HashSet<>();
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 abadc0b..cf9aa77 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
@@ -24,18 +24,25 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
 import java.util.Collections;
-import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
 import javax.ws.rs.core.Response;
-import org.apache.commons.lang3.SerializationUtils;
 import org.apache.syncope.client.lib.batch.BatchRequest;
 import org.apache.syncope.common.lib.request.AnyObjectCR;
 import org.apache.syncope.common.lib.request.AttrPatch;
 import org.apache.syncope.common.lib.request.UserCR;
 import org.apache.syncope.common.lib.request.UserUR;
+import java.util.Set;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.TaskTO;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.Attr;
@@ -43,23 +50,69 @@ import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.PropagationTaskTO;
 import org.apache.syncope.common.lib.to.ExecTO;
+import org.apache.syncope.common.lib.to.ImplementationTO;
 import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.to.ProvisionTO;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ImplementationEngine;
+import org.apache.syncope.common.lib.types.ImplementationType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.common.rest.api.beans.ExecuteQuery;
 import org.apache.syncope.common.rest.api.beans.ExecQuery;
 import org.apache.syncope.common.rest.api.beans.TaskQuery;
 import org.apache.syncope.common.rest.api.service.TaskService;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.fit.core.reference.DateToDateItemTransformer;
+import org.apache.syncope.fit.core.reference.DateToLongItemTransformer;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeUtil;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeAll;
 
 public class PropagationTaskITCase extends AbstractTaskITCase {
 
+    @BeforeAll
+    public static void testItemTransformersSetup() {
+        ImplementationTO dateToLong = null;
+        ImplementationTO dateToDate = null;
+        try {
+            dateToLong = implementationService.read(
+                    ImplementationType.ITEM_TRANSFORMER, DateToLongItemTransformer.class.getSimpleName());
+            dateToDate = implementationService.read(
+                    ImplementationType.ITEM_TRANSFORMER, DateToDateItemTransformer.class.getSimpleName());
+        } catch (SyncopeClientException e) {
+            if (e.getType().getResponseStatus() == Response.Status.NOT_FOUND) {
+                dateToLong = new ImplementationTO();
+                dateToLong.setKey(DateToLongItemTransformer.class.getSimpleName());
+                dateToLong.setEngine(ImplementationEngine.JAVA);
+                dateToLong.setType(ImplementationType.ITEM_TRANSFORMER);
+                dateToLong.setBody(DateToLongItemTransformer.class.getName());
+                Response response = implementationService.create(dateToLong);
+                dateToLong = implementationService.read(
+                        dateToLong.getType(), response.getHeaderString(RESTHeaders.RESOURCE_KEY));
+                assertNotNull(dateToLong);
+
+                dateToDate = new ImplementationTO();
+                dateToDate.setKey(DateToDateItemTransformer.class.getSimpleName());
+                dateToDate.setEngine(ImplementationEngine.JAVA);
+                dateToDate.setType(ImplementationType.ITEM_TRANSFORMER);
+                dateToDate.setBody(DateToDateItemTransformer.class.getName());
+                response = implementationService.create(dateToDate);
+                dateToDate = implementationService.read(
+                        dateToDate.getType(), response.getHeaderString(RESTHeaders.RESOURCE_KEY));
+                assertNotNull(dateToDate);
+            }
+        }
+        assertNotNull(dateToLong);
+        assertNotNull(dateToDate);
+    }
+
     @Test
     public void paginatedList() {
         PagedResult<PropagationTaskTO> tasks = taskService.search(
@@ -276,13 +329,7 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
                         page(1).
                         size(10).
                         build());
-        Collections.sort(unorderedTasks.getResult(), new Comparator<TaskTO>() {
-
-            @Override
-            public int compare(final TaskTO o1, final TaskTO o2) {
-                return o1.getStart().compareTo(o2.getStart());
-            }
-        });
+        Collections.sort(unorderedTasks.getResult(), (t1, t2) -> t1.getStart().compareTo(t2.getStart()));
         assertNotNull(unorderedTasks);
         assertFalse(unorderedTasks.getResult().isEmpty());
         assertEquals(10, unorderedTasks.getResult().size());
@@ -316,4 +363,103 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
 
         assertTrue(orderedTasks.getResult().equals(unorderedTasks.getResult()));
     }
+
+    @Test
+    public void issueSYNCOPE1430() throws ParseException {
+        ResourceTO ldap = resourceService.read(RESOURCE_NAME_LDAP);
+        try {
+            // 1. clone the LDAP resource and add some sensible mappings
+            ProvisionTO provision = ldap.getProvision(AnyTypeKind.USER.name()).orElse(null);
+            assertNotNull(provision);
+            provision.getMapping().getItems().removeIf(item -> "mail".equals(item.getExtAttrName()));
+            provision.getVirSchemas().clear();
+
+            // Date -> long (JEXL expression) -> string (as all JEXL in Syncope)
+            ItemTO loginDateForJexlAsLong = new ItemTO();
+            loginDateForJexlAsLong.setPurpose(MappingPurpose.PROPAGATION);
+            loginDateForJexlAsLong.setIntAttrName("loginDate");
+            loginDateForJexlAsLong.setExtAttrName("employeeNumber");
+            loginDateForJexlAsLong.setPropagationJEXLTransformer("value.getTime()");
+            provision.getMapping().add(loginDateForJexlAsLong);
+
+            // Date -> string (JEXL expression)
+            ItemTO loginDateForJexlAsString = new ItemTO();
+            loginDateForJexlAsString.setPurpose(MappingPurpose.PROPAGATION);
+            loginDateForJexlAsString.setIntAttrName("loginDate");
+            loginDateForJexlAsString.setExtAttrName("street");
+            loginDateForJexlAsString.setPropagationJEXLTransformer(
+                    "value.toInstant().toString().split(\"T\")[0].replace(\"-\", \"\")");
+            provision.getMapping().add(loginDateForJexlAsString);
+
+            // Date -> long
+            ItemTO loginDateForJavaToLong = new ItemTO();
+            loginDateForJavaToLong.setPurpose(MappingPurpose.PROPAGATION);
+            loginDateForJavaToLong.setIntAttrName("loginDate");
+            loginDateForJavaToLong.setExtAttrName("st");
+            loginDateForJavaToLong.getTransformers().add(DateToLongItemTransformer.class.getSimpleName());
+            provision.getMapping().add(loginDateForJavaToLong);
+
+            // Date -> date
+            ItemTO loginDateForJavaToDate = new ItemTO();
+            loginDateForJavaToDate.setPurpose(MappingPurpose.PROPAGATION);
+            loginDateForJavaToDate.setIntAttrName("loginDate");
+            loginDateForJavaToDate.setExtAttrName("carLicense");
+            loginDateForJavaToDate.getTransformers().add(DateToDateItemTransformer.class.getSimpleName());
+            provision.getMapping().add(loginDateForJavaToDate);
+
+            ldap.getProvisions().clear();
+            ldap.getProvisions().add(provision);
+            ldap.setKey(RESOURCE_NAME_LDAP + "1430" + getUUIDString());
+            resourceService.create(ldap);
+
+            // 2. create user with the new resource assigned
+            UserCR createReq = UserITCase.getUniqueSample("syncope1430@syncope.apache.org");
+            createReq.getResources().clear();
+            createReq.getResources().add(ldap.getKey());
+            createReq.getPlainAttrs().removeIf(attr -> "loginDate".equals(attr.getSchema()));
+            createReq.getPlainAttrs().add(attr("loginDate", "2019-01-29"));
+            UserTO user = createUser(createReq).getEntity();
+
+            // 3. check attributes prepared for propagation
+            PagedResult<PropagationTaskTO> tasks = taskService.search(new TaskQuery.Builder(TaskType.PROPAGATION).
+                    resource(user.getResources().iterator().next()).
+                    anyTypeKind(AnyTypeKind.USER).entityKey(user.getKey()).build());
+            assertEquals(1, tasks.getSize());
+
+            Set<Attribute> propagationAttrs = new HashSet<>();
+            if (StringUtils.isNotBlank(tasks.getResult().get(0).getAttributes())) {
+                propagationAttrs.addAll(Arrays.asList(
+                        POJOHelper.deserialize(tasks.getResult().get(0).getAttributes(), Attribute[].class)));
+            }
+
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+
+            Calendar loginDate = Calendar.getInstance();
+            loginDate.setTime(sdf.parse(user.getPlainAttr("loginDate").get().getValues().get(0)));
+
+            Attribute employeeNumber = AttributeUtil.find("employeeNumber", propagationAttrs);
+            assertNotNull(employeeNumber);
+            assertEquals(String.valueOf(loginDate.getTimeInMillis()), employeeNumber.getValue().get(0));
+
+            Attribute street = AttributeUtil.find("street", propagationAttrs);
+            assertNotNull(street);
+            assertEquals(loginDate.toInstant().toString().split("T")[0].replace("-", ""), street.getValue().get(0));
+
+            Attribute st = AttributeUtil.find("st", propagationAttrs);
+            assertNotNull(st);
+            assertEquals(loginDate.getTimeInMillis(), st.getValue().get(0));
+
+            loginDate.add(Calendar.DAY_OF_MONTH, 1);
+
+            Attribute carLicense = AttributeUtil.find("carLicense", propagationAttrs);
+            assertNotNull(carLicense);
+            assertEquals(sdf.format(loginDate.getTime()), carLicense.getValue().get(0));
+        } finally {
+            try {
+                resourceService.delete(ldap.getKey());
+            } catch (Exception ignore) {
+                // ignore
+            }
+        }
+    }
 }
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 98b791f..2900d03 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
@@ -23,11 +23,9 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
-import java.util.stream.Collectors;
 import javax.sql.DataSource;
 import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.Response;
@@ -623,9 +621,7 @@ public class VirAttrITCase extends AbstractITCase {
         try {
             ProvisionTO provision = ldap.getProvision(AnyTypeKind.USER.name()).orElse(null);
             assertNotNull(provision);
-            List<ItemTO> mail = provision.getMapping().getItems().stream().
-                    filter(item -> "mail".equals(item.getExtAttrName())).collect(Collectors.toList());
-            provision.getMapping().getItems().removeAll(mail);
+            provision.getMapping().getItems().removeIf(item -> "mail".equals(item.getExtAttrName()));
             provision.getVirSchemas().clear();
 
             ldap.getProvisions().clear();
diff --git a/fit/core-reference/src/test/resources/PrefixItemTransformer.groovy b/fit/core-reference/src/test/resources/PrefixItemTransformer.groovy
index c26aef1..e35e54d 100644
--- a/fit/core-reference/src/test/resources/PrefixItemTransformer.groovy
+++ b/fit/core-reference/src/test/resources/PrefixItemTransformer.groovy
@@ -16,14 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import java.util.ArrayList;
 import groovy.transform.CompileStatic
+import java.util.ArrayList;
 import java.util.List;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.to.EntityTO;
-import org.apache.syncope.core.persistence.api.entity.Entity;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.resource.Item;
+import org.apache.commons.lang3.tuple.Pair
+import org.apache.syncope.common.lib.to.EntityTO
+import org.apache.syncope.common.lib.types.AttrSchemaType
+import org.apache.syncope.core.persistence.api.entity.Entity
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue
+import org.apache.syncope.core.persistence.api.entity.resource.Item
 import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
 
 @CompileStatic
@@ -32,18 +34,19 @@ class PrefixItemTransformer implements ItemTransformer {
   public static String PREFIX = "PREFIX_";
 
   @Override
-  List<PlainAttrValue> beforePropagation(
+  Pair<AttrSchemaType, List<PlainAttrValue>> beforePropagation(
     Item item,
     Entity entity,
+    AttrSchemaType schemaType,
     List<PlainAttrValue> values) {
 
     if (values == null || values.isEmpty() || values.get(0).getStringValue() == null) {
-      return values;
+      return Pair.of(schemaType, values);
     } else {
       String value = values.get(0).getStringValue();
       values.get(0).setStringValue(PREFIX + value);
 
-      return values;
+      return Pair.of(schemaType, values);
     }
   }
 
@@ -62,6 +65,5 @@ class PrefixItemTransformer implements ItemTransformer {
       return newValues;
     }
   }
-
 }