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

ilgrosso pushed a commit to branch SYNCOPE-1400_SYNCOPE-1401
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 25dfcc05994b11fe4b33cb8458b2bd57cd93e4d9
Author: Francesco Chicchiriccò <ilgro...@apache.org>
AuthorDate: Mon Dec 3 13:18:36 2018 +0100

    [SYNCOPE-1400] Adding support for MySQL 8 via OpenJPA 3.0.1 + 
[SYNCOPE-1401] Adding support for MySQL with JSON type
---
 core/persistence-jpa-json/pom.xml                  | 129 ++++++---
 ...AJSONAnyDAO.java => AbstractJPAJSONAnyDAO.java} |  81 ++----
 .../jpa/dao/AbstractJPAJSONAnySearchDAO.java       | 125 +++++++++
 .../core/persistence/jpa/dao/MyJPAJSONAnyDAO.java  | 120 ++++++++
 ...nySearchDAO.java => MyJPAJSONAnySearchDAO.java} | 131 ++-------
 .../core/persistence/jpa/dao/PGJPAJSONAnyDAO.java  | 305 ++-------------------
 .../persistence/jpa/dao/PGJPAJSONAnySearchDAO.java | 110 +-------
 .../jpa/entity/JPAJSONEntityFactory.java           |   3 +-
 .../jpa/entity/MyJPAJSONEntityFactory.java         |  37 +++
 .../main/resources/META-INF/spring-orm-myjson.xml  | 137 +++++++++
 .../resources/myjson}/domains/Master.properties    |  10 +-
 .../src/main/resources/myjson/indexes.xml          |  58 ++++
 .../main/resources/myjson/persistence.properties   |  23 +-
 .../src/main/resources/myjson/views.xml            | 181 ++++++++++++
 .../{pgjsonb => }/domains/MasterContent.xml        |   0
 .../core/persistence/jpa/dao/JPAAnySearchDAO.java  |   4 +
 .../main/resources/audit/audit_mysql_innodb.sql    |   2 +-
 .../core/persistence/jpa/inner/AnyTypeTest.java    |   2 +
 fit/core-reference/pom.xml                         | 168 +++++++++++-
 .../{mysql => myjson}/domains/Master.properties    |  10 +-
 .../{mysql => myjson}/provisioning.properties      |   2 +-
 .../main/resources/mysql/domains/Master.properties |   8 +-
 .../main/resources/mysql/provisioning.properties   |   2 +-
 pom.xml                                            |   5 +-
 24 files changed, 1035 insertions(+), 618 deletions(-)

diff --git a/core/persistence-jpa-json/pom.xml 
b/core/persistence-jpa-json/pom.xml
index dfd7bb2..0331a27 100644
--- a/core/persistence-jpa-json/pom.xml
+++ b/core/persistence-jpa-json/pom.xml
@@ -227,10 +227,6 @@ under the License.
             <filtering>true</filtering>
           </testResource>
           <testResource>
-            <directory>src/test/resources/pgjsonb</directory>
-            <filtering>true</filtering>
-          </testResource>
-          <testResource>
             <directory>src/main/resources</directory>
             <filtering>true</filtering>
           </testResource>
@@ -243,62 +239,119 @@ under the License.
     </profile>
     
     <profile>
-      <id>sqlgen</id>
-      
-      <properties>
-        <skipTests>true</skipTests>
-      </properties>
+      <id>mysql</id>
       
+      <dependencies>
+        <dependency>
+          <groupId>mysql</groupId>
+          <artifactId>mysql-connector-java</artifactId>
+          <version>${jdbc.mysql.version}</version>
+          <scope>test</scope>
+        </dependency>
+      </dependencies>
+
       <build>
         <defaultGoal>clean verify</defaultGoal>
         
         <plugins>
           <plugin>
-            <groupId>org.apache.openjpa</groupId>
-            <artifactId>openjpa-maven-plugin</artifactId>
-            <inherited>true</inherited>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>build-helper-maven-plugin</artifactId>
             <executions>
               <execution>
-                <id>sqlgen</id>
-                <phase>process-classes</phase>
+                <id>add-test-source</id>
+                <phase>generate-test-sources</phase>
                 <goals>
-                  <goal>sql</goal>
+                  <goal>add-test-source</goal>
                 </goals>
+                <configuration>
+                  <sources>
+                    
<source>${basedir}/../persistence-jpa/src/test/java</source>
+                  </sources>
+                </configuration>
               </execution>
             </executions>
-          </plugin>          
-        </plugins>
-      </build>
-    </profile>
-    
-    <profile>
-      <id>schemagen</id>
-      
-      <properties>
-        <skipTests>true</skipTests>
-      </properties>
+          </plugin>
       
-      <build>
-        <defaultGoal>clean verify</defaultGoal>
-        
-        <plugins>
           <plugin>
-            <groupId>org.apache.openjpa</groupId>
-            <artifactId>openjpa-maven-plugin</artifactId>
-            <inherited>true</inherited>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-failsafe-plugin</artifactId>
+            <configuration>
+              <includes>
+                <include>**/*Test.java</include>
+              </includes>
+              <excludedGroups>multitenancy,plainAttrTable</excludedGroups>
+            </configuration>
+          </plugin>
+
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+            <configuration>
+              <images>
+                <image>
+                  <name>mysql/mysql-server:${docker.mysql.version}</name>
+                  <run>
+                    <cmd>--skip-log-bin --server-id=1</cmd>
+                    <env>
+                      <MYSQL_ROOT_PASSWORD>password</MYSQL_ROOT_PASSWORD>
+                      <MYSQL_DATABASE>syncope</MYSQL_DATABASE>
+                      <MYSQL_USER>syncope</MYSQL_USER>
+                      <MYSQL_PASSWORD>syncope</MYSQL_PASSWORD>
+                    </env>
+                    <ports>
+                      <port>3306:3306</port>
+                    </ports>
+                    <wait>
+                      <log>MySQL init process done. Ready for start up.</log>
+                      <time>30000</time>
+                    </wait>
+                  </run>
+                </image>
+              </images>
+            </configuration>
             <executions>
               <execution>
-                <id>schemagen</id>
-                <phase>process-classes</phase>
+                <id>start-mysql</id>
+                <phase>pre-integration-test</phase>
+                <goals>
+                  <goal>start</goal>
+                </goals>
+              </execution>
+              <execution>
+                <id>stop-mysql</id>
+                <phase>post-integration-test</phase>
                 <goals>
-                  <goal>schema</goal>
+                  <goal>stop</goal>
+                  <goal>remove</goal>
                 </goals>
               </execution>
             </executions>
-          </plugin>          
+          </plugin>
         </plugins>
+        
+        <testResources>
+          <testResource>
+            <directory>src/test/resources</directory>
+            <filtering>true</filtering>
+          </testResource>
+          <testResource>
+            <directory>src/main/resources</directory>
+            <filtering>true</filtering>
+          </testResource>
+          <testResource>
+            <directory>src/main/resources/myjson</directory>
+            <filtering>true</filtering>
+          </testResource>
+        </testResources>
       </build>
     </profile>
   </profiles>
-
 </project>
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/AbstractJPAJSONAnyDAO.java
similarity index 81%
copy from 
core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnyDAO.java
copy to 
core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java
index 94bb72a..f0bca9a 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/AbstractJPAJSONAnyDAO.java
@@ -20,40 +20,37 @@ package org.apache.syncope.core.persistence.jpa.dao;
 
 import java.io.StringReader;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
-import java.util.StringJoiner;
 import java.util.regex.Pattern;
 import javax.persistence.Query;
 import org.apache.commons.jexl3.parser.Parser;
 import org.apache.commons.jexl3.parser.ParserConstants;
 import org.apache.commons.jexl3.parser.Token;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.DuplicateException;
+import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 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.PlainAttr;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractEntity;
-import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
-import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
-import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
 
-@Repository
-public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements 
JPAJSONAnyDAO {
+abstract class AbstractJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> 
implements JPAJSONAnyDAO {
 
     @Autowired
     private PlainSchemaDAO plainSchemaDAO;
@@ -61,22 +58,19 @@ public class PGJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> implements JPAJ
     @Autowired
     private DerSchemaDAO derSchemaDAO;
 
-    private String queryBegin(final String table) {
-        return "SELECT DISTINCT id FROM " + table + " u,"
-                + "jsonb_array_elements(u.plainAttrs) attrs,"
-                + "jsonb_array_elements(COALESCE(attrs -> 'values', 
'[{}]'::jsonb)) attrValues ";
-    }
+    protected abstract String queryBegin(String table);
 
-    private String attrValueMatch(
-            final AnyUtils anyUtils,
-            final PlainSchema schema,
-            final PlainAttrValue attrValue,
-            final boolean ignoreCaseMatch) {
+    protected abstract String attrValueMatch(
+            AnyUtils anyUtils,
+            PlainSchema schema,
+            PlainAttrValue attrValue,
+            boolean ignoreCaseMatch);
 
+    protected Pair<String, Boolean> schemaInfo(final AttrSchemaType 
schemaType, final boolean ignoreCaseMatch) {
         String key;
         boolean lower = false;
 
-        switch (schema.getType()) {
+        switch (schemaType) {
             case Boolean:
                 key = "booleanValue";
                 break;
@@ -102,29 +96,10 @@ public class PGJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> implements JPAJ
                 key = "stringValue";
         }
 
-        if (lower) {
-            return "attrs ->> 'schema' = ? "
-                    + "AND "
-                    + (lower ? "LOWER(" : "")
-                    + (schema.isUniqueConstraint() ? "attrs -> 'uniqueValue'" 
: "attrValues") + " ->> '" + key
-                    + "'" + (lower ? ")" : "")
-                    + " = "
-                    + (lower ? "LOWER(" : "")
-                    + "?"
-                    + (lower ? ")" : "");
-        } else {
-            PlainAttr<?> container = anyUtils.newPlainAttr();
-            container.setSchema(schema);
-            if (attrValue instanceof PlainAttrUniqueValue) {
-                container.setUniqueValue((PlainAttrUniqueValue) attrValue);
-            } else {
-                ((JSONPlainAttr) container).add(attrValue);
-            }
-            return "plainAttrs @> '" + 
POJOHelper.serialize(Arrays.asList(container)) + "'::jsonb";
-        }
+        return Pair.of(key, lower);
     }
 
-    private <A extends Any<?>> List<A> buildResult(final AnyUtils anyUtils, 
final List<Object> queryResult) {
+    protected <A extends Any<?>> List<A> buildResult(final AnyUtils anyUtils, 
final List<Object> queryResult) {
         List<A> result = new ArrayList<>();
         queryResult.forEach(anyKey -> {
             A any = anyUtils.<A>dao().find(anyKey.toString());
@@ -210,6 +185,8 @@ public class PGJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> implements JPAJ
         return attrValues;
     }
 
+    protected abstract List<Object> findByDerAttrValue(String table, 
Map<String, List<Object>> clauses);
+
     @SuppressWarnings("unchecked")
     @Transactional(readOnly = true)
     @Override
@@ -272,7 +249,7 @@ public class PGJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> implements JPAJ
             return Collections.emptyList();
         }
 
-        StringJoiner clauses = new StringJoiner(" AND id IN ");
+        Map<String, List<Object>> clauses = new LinkedHashMap<>();
 
         // builder to build the clauses
         StringBuilder bld = new StringBuilder();
@@ -280,8 +257,6 @@ public class PGJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> implements JPAJ
         // Contains used identifiers in order to avoid replications
         Set<String> used = new HashSet<>();
 
-        List<Object> queryParams = new ArrayList<>();
-
         // Create several clauses: one for eanch identifiers
         for (int i = 0; i < identifiers.size(); i++) {
             if (!used.contains(identifiers.get(i))) {
@@ -306,25 +281,21 @@ public class PGJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> implements JPAJ
                             append("WHERE ").
                             append(attrValueMatch(anyUtils, schema, attrValue, 
ignoreCaseMatch)).
                             append(')');
-                    queryParams.add(schema.getKey());
-                    queryParams.add(attrValues.get(i));
 
                     used.add(identifiers.get(i));
 
-                    clauses.add(bld.toString());
+                    List<Object> queryParams = new ArrayList<>();
+                    queryParams.add(schema.getKey());
+                    queryParams.add(attrValues.get(i));
+
+                    clauses.put(bld.toString(), queryParams);
                 }
             }
         }
 
         LOG.debug("Generated where clauses {}", clauses);
 
-        Query query = entityManager().createNativeQuery(
-                "SELECT DISTINCT id FROM " + table + " u WHERE id IN " + 
clauses.toString());
-        for (int i = 0; i < queryParams.size(); i++) {
-            query.setParameter(i + 1, queryParams.get(i));
-        }
-
-        return buildResult(anyUtils, query.getResultList());
+        return buildResult(anyUtils, findByDerAttrValue(table, clauses));
     }
 
     @Transactional
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnySearchDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnySearchDAO.java
new file mode 100644
index 0000000..693d791
--- /dev/null
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnySearchDAO.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
+
+abstract class AbstractJPAJSONAnySearchDAO extends JPAAnySearchDAO {
+
+    @Override
+    SearchSupport buildSearchSupport(final AnyTypeKind kind) {
+        return new SearchSupport(kind);
+    }
+
+    @Override
+    protected void processOBS(final SearchSupport svs, final OrderBySupport 
obs, final StringBuilder where) {
+        obs.views.forEach(searchView -> {
+            where.append(',').
+                    append(searchView.name).
+                    append(' ').append(searchView.alias);
+        });
+    }
+
+    protected Pair<String, Boolean> schemaInfo(final AttrSchemaType 
schemaType, final AttributeCond.Type condType) {
+        String key;
+        boolean lower = false;
+        switch (schemaType) {
+            case Boolean:
+                key = "booleanValue";
+                break;
+
+            case Date:
+                key = "dateValue";
+                break;
+
+            case Double:
+                key = "doubleValue";
+                break;
+
+            case Long:
+                key = "longValue";
+                break;
+
+            case Binary:
+                key = "binaryValue";
+                break;
+
+            default:
+                lower = condType == AttributeCond.Type.IEQ || condType == 
AttributeCond.Type.ILIKE;
+                key = "stringValue";
+        }
+
+        return Pair.of(key, lower);
+    }
+
+    protected void appendOp(final StringBuilder query, final 
AttributeCond.Type condType, final boolean not) {
+        switch (condType) {
+            case LIKE:
+            case ILIKE:
+                if (not) {
+                    query.append("NOT ");
+                }
+                query.append(" LIKE ");
+                break;
+
+            case GE:
+                if (not) {
+                    query.append('<');
+                } else {
+                    query.append(">=");
+                }
+                break;
+
+            case GT:
+                if (not) {
+                    query.append("<=");
+                } else {
+                    query.append('>');
+                }
+                break;
+
+            case LE:
+                if (not) {
+                    query.append('>');
+                } else {
+                    query.append("<=");
+                }
+                break;
+
+            case LT:
+                if (not) {
+                    query.append(">=");
+                } else {
+                    query.append('<');
+                }
+                break;
+
+            case EQ:
+            case IEQ:
+            default:
+                if (not) {
+                    query.append('!');
+                }
+                query.append('=');
+        }
+    }
+}
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnyDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnyDAO.java
new file mode 100644
index 0000000..e15e690
--- /dev/null
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnyDAO.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.persistence.Query;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
+
+public class MyJPAJSONAnyDAO extends AbstractJPAJSONAnyDAO {
+
+    @Override
+    protected String queryBegin(final String table) {
+        String view = StringUtils.containsIgnoreCase(table, 
AnyTypeKind.USER.name())
+                ? "user_search"
+                : StringUtils.containsIgnoreCase(table, 
AnyTypeKind.GROUP.name())
+                ? "group_search"
+                : "anyObject_search";
+        return "SELECT DISTINCT id FROM " + view + " ";
+    }
+
+    @Override
+    protected String attrValueMatch(
+            final AnyUtils anyUtils,
+            final PlainSchema schema,
+            final PlainAttrValue attrValue,
+            final boolean ignoreCaseMatch) {
+
+        Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), 
ignoreCaseMatch);
+        if (schemaInfo.getRight()) {
+            return "plainSchema = ? "
+                    + "AND "
+                    + (schemaInfo.getRight() ? "LOWER(" : "")
+                    + (schema.isUniqueConstraint()
+                    ? "attrUniqueValue ->> '$." + schemaInfo.getLeft() + "'"
+                    : schemaInfo.getLeft())
+                    + (schemaInfo.getRight() ? ")" : "")
+                    + " = "
+                    + (schemaInfo.getRight() ? "LOWER(" : "")
+                    + "?"
+                    + (schemaInfo.getRight() ? ")" : "");
+        } else {
+            PlainAttr<?> container = anyUtils.newPlainAttr();
+            container.setSchema(schema);
+            if (attrValue instanceof PlainAttrUniqueValue) {
+                container.setUniqueValue((PlainAttrUniqueValue) attrValue);
+            } else {
+                ((JSONPlainAttr) container).add(attrValue);
+            }
+            return "JSON_CONTAINS(plainAttrs, '" + 
POJOHelper.serialize(Arrays.asList(container)) + "')";
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * This method is a workaround for a bug experienced with MySQL 8.0.13, 
where the correct implementation (as shown
+     * in PGJPAJSONAnyDAO.findByDerAttrValue(String, Map&lt;String, 
List&lt;Object&gt;&gt;)) generates a core dump.
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    protected List<Object> findByDerAttrValue(
+            final String table,
+            final Map<String, List<Object>> clauses) {
+
+        if (clauses.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        Set<Object> result = new HashSet<>();
+        AtomicReference<Boolean> first = new AtomicReference<>(Boolean.TRUE);
+        clauses.forEach((clause, parameters) -> {
+            Query query = 
entityManager().createNativeQuery(StringUtils.replaceIgnoreCase(clause, 
"DISTINCT", ""));
+            for (int i = 0; i < parameters.size(); i++) {
+                query.setParameter(i + 1, parameters.get(i));
+            }
+
+            Set<Object> local = new HashSet<>(query.getResultList());
+            if (first.get()) {
+                result.addAll(local);
+                first.set(Boolean.FALSE);
+            } else {
+                result.retainAll(local);
+            }
+        });
+
+        return new ArrayList<>(result);
+    }
+}
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
similarity index 55%
copy from 
core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
copy to 
core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
index f240705..4707372 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
@@ -21,7 +21,6 @@ package org.apache.syncope.core.persistence.jpa.dao;
 import java.util.Arrays;
 import java.util.List;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -32,21 +31,7 @@ import 
org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
 
-public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
-
-    @Override
-    SearchSupport buildSearchSupport(final AnyTypeKind kind) {
-        return new SearchSupport(kind);
-    }
-
-    @Override
-    protected void processOBS(final SearchSupport svs, final OrderBySupport 
obs, final StringBuilder where) {
-        obs.views.forEach(searchView -> {
-            where.append(',').
-                    append(searchView.name).
-                    append(' ').append(searchView.alias);
-        });
-    }
+public class MyJPAJSONAnySearchDAO extends AbstractJPAJSONAnySearchDAO {
 
     @Override
     protected void parseOrderByForPlainSchema(
@@ -62,8 +47,10 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
 
         obs.views.add(svs.field());
 
-        item.select = svs.field().alias + ".attrValues ->> '" + fieldName + "' 
AS " + fieldName;
-        item.where = "attrs ->> 'schema' = '" + fieldName + "'";
+        item.select = svs.field().alias + "."
+                + (schema.isUniqueConstraint() ? "attrUniqueValue" : 
svs.fieldName(schema.getType()))
+                + " AS " + fieldName;
+        item.where = "plainSchema = '" + fieldName + "'";
         item.orderBy = fieldName + " " + clause.getDirection().name();
     }
 
@@ -76,33 +63,7 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
             final boolean not,
             final List<Object> parameters) {
 
-        String key;
-        boolean lower = false;
-        switch (schema.getType()) {
-            case Boolean:
-                key = "booleanValue";
-                break;
-
-            case Date:
-                key = "dateValue";
-                break;
-
-            case Double:
-                key = "doubleValue";
-                break;
-
-            case Long:
-                key = "longValue";
-                break;
-
-            case Binary:
-                key = "binaryValue";
-                break;
-
-            default:
-                lower = cond.getType() == AttributeCond.Type.IEQ || 
cond.getType() == AttributeCond.Type.ILIKE;
-                key = "stringValue";
-        }
+        Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), 
cond.getType());
 
         if (!not && cond.getType() == AttributeCond.Type.EQ) {
             PlainAttr<?> container = anyUtils.newPlainAttr();
@@ -113,71 +74,23 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO 
{
                 ((JSONPlainAttr) container).add(attrValue);
             }
 
-            query.append("plainAttrs @> '").
+            query.append("JSON_CONTAINS(plainAttrs, '").
                     append(POJOHelper.serialize(Arrays.asList(container))).
-                    append("'::jsonb");
+                    append("')");
         } else {
-            query.append("attrs ->> 'schema' = 
?").append(setParameter(parameters, cond.getSchema())).
+            query.append("plainSchema = ?").append(setParameter(parameters, 
cond.getSchema())).
                     append(" AND ").
-                    append(lower ? "LOWER(" : "").
+                    append(schemaInfo.getRight() ? "LOWER(" : "").
                     append(schema.isUniqueConstraint()
-                            ? "attrs -> 'uniqueValue'" : "attrValues").
-                    append(" ->> '").append(key).append("'").
-                    append(lower ? ")" : "");
-
-            switch (cond.getType()) {
-                case LIKE:
-                case ILIKE:
-                    if (not) {
-                        query.append("NOT ");
-                    }
-                    query.append(" LIKE ");
-                    break;
-
-                case GE:
-                    if (not) {
-                        query.append('<');
-                    } else {
-                        query.append(">=");
-                    }
-                    break;
-
-                case GT:
-                    if (not) {
-                        query.append("<=");
-                    } else {
-                        query.append('>');
-                    }
-                    break;
-
-                case LE:
-                    if (not) {
-                        query.append('>');
-                    } else {
-                        query.append("<=");
-                    }
-                    break;
-
-                case LT:
-                    if (not) {
-                        query.append(">=");
-                    } else {
-                        query.append('<');
-                    }
-                    break;
-
-                case EQ:
-                case IEQ:
-                default:
-                    if (not) {
-                        query.append('!');
-                    }
-                    query.append('=');
-            }
+                            ? "attrUniqueValue ->> '$." + schemaInfo.getLeft() 
+ "'"
+                            : schemaInfo.getLeft()).
+                    append(schemaInfo.getRight() ? ")" : "");
+
+            appendOp(query, cond.getType(), not);
 
-            query.append(lower ? "LOWER(" : "").
+            query.append(schemaInfo.getRight() ? "LOWER(" : "").
                     append("?").append(setParameter(parameters, 
cond.getExpression())).
-                    append(lower ? ")" : "");
+                    append(schemaInfo.getRight() ? ")" : "");
         }
     }
 
@@ -208,17 +121,15 @@ public class PGJPAJSONAnySearchDAO extends 
JPAAnySearchDAO {
                 append(svs.field().name).append(" WHERE ");
         switch (cond.getType()) {
             case ISNOTNULL:
-                query.append("plainAttrs @> '[{\"schema\":\"").
+                query.append("JSON_SEARCH(plainAttrs, 'one', '").
                         append(checked.getLeft().getKey()).
-                        append("\"}]'::jsonb");
+                        append("', NULL, '$[*].schema') IS NOT NULL");
                 break;
 
             case ISNULL:
-                query.append("any_id NOT IN (").
-                        append("SELECT any_id FROM ").append(svs.field().name).
-                        append(" WHERE plainAttrs @> '[{\"schema\":\"").
+                query.append("JSON_SEARCH(plainAttrs, 'one', '").
                         append(checked.getLeft().getKey()).
-                        append("\"}]'::jsonb)");
+                        append("', NULL, '$[*].schema') IS NULL");
                 break;
 
             default:
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..ed1664b 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
@@ -18,100 +18,49 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
-import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
+import java.util.Map;
 import java.util.StringJoiner;
-import java.util.regex.Pattern;
 import javax.persistence.Query;
-import org.apache.commons.jexl3.parser.Parser;
-import org.apache.commons.jexl3.parser.ParserConstants;
-import org.apache.commons.jexl3.parser.Token;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
-import org.apache.syncope.core.persistence.api.dao.DuplicateException;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
-import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.commons.lang3.tuple.Pair;
 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.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractEntity;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
-import org.apache.syncope.core.spring.security.AuthContextUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
 import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
-import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
 
-@Repository
-public class PGJPAJSONAnyDAO extends AbstractDAO<AbstractEntity> implements 
JPAJSONAnyDAO {
+public class PGJPAJSONAnyDAO extends AbstractJPAJSONAnyDAO {
 
-    @Autowired
-    private PlainSchemaDAO plainSchemaDAO;
-
-    @Autowired
-    private DerSchemaDAO derSchemaDAO;
-
-    private String queryBegin(final String table) {
+    @Override
+    protected String queryBegin(final String table) {
         return "SELECT DISTINCT id FROM " + table + " u,"
                 + "jsonb_array_elements(u.plainAttrs) attrs,"
                 + "jsonb_array_elements(COALESCE(attrs -> 'values', 
'[{}]'::jsonb)) attrValues ";
     }
 
-    private String attrValueMatch(
+    @Override
+    protected String attrValueMatch(
             final AnyUtils anyUtils,
             final PlainSchema schema,
             final PlainAttrValue attrValue,
             final boolean ignoreCaseMatch) {
 
-        String key;
-        boolean lower = false;
-
-        switch (schema.getType()) {
-            case Boolean:
-                key = "booleanValue";
-                break;
-
-            case Date:
-                key = "dateValue";
-                break;
-
-            case Double:
-                key = "doubleValue";
-                break;
-
-            case Long:
-                key = "longValue";
-                break;
-
-            case Binary:
-                key = "binaryValue";
-                break;
-
-            default:
-                lower = ignoreCaseMatch;
-                key = "stringValue";
-        }
-
-        if (lower) {
+        Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), 
ignoreCaseMatch);
+        if (schemaInfo.getRight()) {
             return "attrs ->> 'schema' = ? "
                     + "AND "
-                    + (lower ? "LOWER(" : "")
-                    + (schema.isUniqueConstraint() ? "attrs -> 'uniqueValue'" 
: "attrValues") + " ->> '" + key
-                    + "'" + (lower ? ")" : "")
+                    + (schemaInfo.getRight() ? "LOWER(" : "")
+                    + (schema.isUniqueConstraint() ? "attrs -> 'uniqueValue'" 
: "attrValues")
+                    + " ->> '" + schemaInfo.getLeft()
+                    + "'" + (schemaInfo.getRight() ? ")" : "")
                     + " = "
-                    + (lower ? "LOWER(" : "")
+                    + (schemaInfo.getRight() ? "LOWER(" : "")
                     + "?"
-                    + (lower ? ")" : "");
+                    + (schemaInfo.getRight() ? ")" : "");
         } else {
             PlainAttr<?> container = anyUtils.newPlainAttr();
             container.setSchema(schema);
@@ -124,232 +73,26 @@ public class PGJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> implements JPAJ
         }
     }
 
-    private <A extends Any<?>> List<A> buildResult(final AnyUtils anyUtils, 
final List<Object> queryResult) {
-        List<A> result = new ArrayList<>();
-        queryResult.forEach(anyKey -> {
-            A any = anyUtils.<A>dao().find(anyKey.toString());
-            if (any == null) {
-                LOG.error("Could not find any for key {}", anyKey);
-            } else {
-                result.add(any);
-            }
-        });
-        return result;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Transactional(readOnly = true)
     @Override
-    public <A extends Any<?>> List<A> findByPlainAttrValue(
-            final String table,
-            final AnyUtils anyUtils,
-            final String schemaKey,
-            final PlainAttrValue attrValue,
-            final boolean ignoreCaseMatch) {
-
-        PlainSchema schema = plainSchemaDAO.find(schemaKey);
-        if (schema == null) {
-            LOG.error("Invalid schema '{}'", schemaKey);
-            return Collections.<A>emptyList();
-        }
-
-        Query query = entityManager().createNativeQuery(
-                queryBegin(table)
-                + "WHERE " + attrValueMatch(anyUtils, schema, attrValue, 
ignoreCaseMatch));
-        query.setParameter(1, schemaKey);
-        query.setParameter(2, attrValue.getValue());
-
-        return buildResult(anyUtils, query.getResultList());
-    }
-
-    @Transactional(readOnly = true)
-    @Override
-    public <A extends Any<?>> A findByPlainAttrUniqueValue(
-            final String table,
-            final AnyUtils anyUtils,
-            final String schemaKey,
-            final PlainAttrValue attrUniqueValue,
-            final boolean ignoreCaseMatch) {
-
-        PlainSchema schema = plainSchemaDAO.find(schemaKey);
-        if (schema == null) {
-            LOG.error("Invalid schema '{}'", schemaKey);
-            return null;
-        }
-        if (!schema.isUniqueConstraint()) {
-            LOG.error("This schema has not unique constraint: '{}'", 
schemaKey);
-            return null;
-        }
-
-        List<A> result = findByPlainAttrValue(table, anyUtils, schemaKey, 
attrUniqueValue, ignoreCaseMatch);
-        return result.isEmpty()
-                ? null
-                : result.get(0);
-    }
-
-    /**
-     * Split an attribute value recurring on provided literals/tokens.
-     *
-     * @param attrValue value to be split
-     * @param literals literals/tokens
-     * @return split value
-     */
-    private List<String> split(final String attrValue, final List<String> 
literals) {
-        final List<String> attrValues = new ArrayList<>();
-
-        if (literals.isEmpty()) {
-            attrValues.add(attrValue);
-        } else {
-            for (String token : 
attrValue.split(Pattern.quote(literals.get(0)))) {
-                if (!token.isEmpty()) {
-                    attrValues.addAll(split(token, literals.subList(1, 
literals.size())));
-                }
-            }
-        }
-
-        return attrValues;
-    }
-
     @SuppressWarnings("unchecked")
-    @Transactional(readOnly = true)
-    @Override
-    public <A extends Any<?>> List<A> findByDerAttrValue(
+    protected List<Object> findByDerAttrValue(
             final String table,
-            final AnyUtils anyUtils,
-            final String schemaKey,
-            final String value,
-            final boolean ignoreCaseMatch) {
-
-        DerSchema derSchema = derSchemaDAO.find(schemaKey);
-        if (derSchema == null) {
-            LOG.error("Invalid schema '{}'", schemaKey);
-            return Collections.<A>emptyList();
-        }
-
-        Parser parser = new Parser(new 
StringReader(derSchema.getExpression()));
-
-        // Schema keys
-        List<String> identifiers = new ArrayList<>();
-
-        // Literals
-        List<String> literals = new ArrayList<>();
-
-        // Get schema keys and literals
-        for (Token token = parser.getNextToken(); token != null && 
StringUtils.isNotBlank(token.toString());
-                token = parser.getNextToken()) {
-
-            if (token.kind == ParserConstants.STRING_LITERAL) {
-                literals.add(token.toString().substring(1, 
token.toString().length() - 1));
-            }
-
-            if (token.kind == ParserConstants.IDENTIFIER) {
-                identifiers.add(token.toString());
-            }
-        }
-
-        // Sort literals in order to process later literals included into 
others
-        Collections.sort(literals, (l1, l2) -> {
-            if (l1 == null && l2 == null) {
-                return 0;
-            } else if (l1 != null && l2 == null) {
-                return -1;
-            } else if (l1 == null && l2 != null) {
-                return 1;
-            } else if (l1.length() == l2.length()) {
-                return 0;
-            } else if (l1.length() > l2.length()) {
-                return -1;
-            } else {
-                return 1;
-            }
-        });
-
-        // Split value on provided literals
-        List<String> attrValues = split(value, literals);
-
-        if (attrValues.size() != identifiers.size()) {
-            LOG.error("Ambiguous JEXL expression resolution: literals and 
values have different size");
-            return Collections.emptyList();
-        }
-
-        StringJoiner clauses = new StringJoiner(" AND id IN ");
-
-        // builder to build the clauses
-        StringBuilder bld = new StringBuilder();
-
-        // Contains used identifiers in order to avoid replications
-        Set<String> used = new HashSet<>();
+            final Map<String, List<Object>> clauses) {
 
+        StringJoiner actualClauses = new StringJoiner(" AND id IN ");
         List<Object> queryParams = new ArrayList<>();
 
-        // Create several clauses: one for eanch identifiers
-        for (int i = 0; i < identifiers.size(); i++) {
-            if (!used.contains(identifiers.get(i))) {
-                // verify schema existence and get schema type
-                PlainSchema schema = plainSchemaDAO.find(identifiers.get(i));
-                if (schema == null) {
-                    LOG.error("Invalid schema '{}', ignoring", 
identifiers.get(i));
-                } else {
-                    // clear builder
-                    bld.delete(0, bld.length());
-
-                    PlainAttrValue attrValue;
-                    if (schema.isUniqueConstraint()) {
-                        attrValue = anyUtils.newPlainAttrUniqueValue();
-                    } else {
-                        attrValue = anyUtils.newPlainAttrValue();
-                    }
-                    attrValue.setStringValue(attrValues.get(i));
-
-                    bld.append('(').
-                            append(queryBegin(table)).
-                            append("WHERE ").
-                            append(attrValueMatch(anyUtils, schema, attrValue, 
ignoreCaseMatch)).
-                            append(')');
-                    queryParams.add(schema.getKey());
-                    queryParams.add(attrValues.get(i));
-
-                    used.add(identifiers.get(i));
-
-                    clauses.add(bld.toString());
-                }
-            }
-        }
-
-        LOG.debug("Generated where clauses {}", clauses);
+        clauses.forEach((clause, parameters) -> {
+            actualClauses.add(clause);
+            queryParams.addAll(parameters);
+        });
 
         Query query = entityManager().createNativeQuery(
-                "SELECT DISTINCT id FROM " + table + " u WHERE id IN " + 
clauses.toString());
+                "SELECT DISTINCT id FROM " + table + " u WHERE id IN " + 
actualClauses.toString());
         for (int i = 0; i < queryParams.size(); i++) {
             query.setParameter(i + 1, queryParams.get(i));
         }
 
-        return buildResult(anyUtils, query.getResultList());
-    }
-
-    @Transactional
-    @Override
-    public <A extends Any<?>> void checkBeforeSave(final String table, final 
AnyUtils anyUtils, final A any) {
-        // check UNIQUE constraints
-        any.getPlainAttrs().stream().
-                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);
-                    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);
-                    }
-                });
-
-        // update sysInfo - as 
org.apache.syncope.core.persistence.jpa.entity.PlainAttrListener is not invoked
-        Date now = new Date();
-        String username = AuthContextUtils.getUsername();
-        LOG.debug("Set last change date '{}' and modifier '{}' for '{}'", now, 
username, any);
-        any.setLastModifier(username);
-        any.setLastChangeDate(now);
+        return query.getResultList();
     }
 }
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
index f240705..399573a 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAnySearchDAO.java
@@ -21,7 +21,6 @@ package org.apache.syncope.core.persistence.jpa.dao;
 import java.util.Arrays;
 import java.util.List;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -32,21 +31,7 @@ import 
org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
 
-public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
-
-    @Override
-    SearchSupport buildSearchSupport(final AnyTypeKind kind) {
-        return new SearchSupport(kind);
-    }
-
-    @Override
-    protected void processOBS(final SearchSupport svs, final OrderBySupport 
obs, final StringBuilder where) {
-        obs.views.forEach(searchView -> {
-            where.append(',').
-                    append(searchView.name).
-                    append(' ').append(searchView.alias);
-        });
-    }
+public class PGJPAJSONAnySearchDAO extends AbstractJPAJSONAnySearchDAO {
 
     @Override
     protected void parseOrderByForPlainSchema(
@@ -76,33 +61,7 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
             final boolean not,
             final List<Object> parameters) {
 
-        String key;
-        boolean lower = false;
-        switch (schema.getType()) {
-            case Boolean:
-                key = "booleanValue";
-                break;
-
-            case Date:
-                key = "dateValue";
-                break;
-
-            case Double:
-                key = "doubleValue";
-                break;
-
-            case Long:
-                key = "longValue";
-                break;
-
-            case Binary:
-                key = "binaryValue";
-                break;
-
-            default:
-                lower = cond.getType() == AttributeCond.Type.IEQ || 
cond.getType() == AttributeCond.Type.ILIKE;
-                key = "stringValue";
-        }
+        Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), 
cond.getType());
 
         if (!not && cond.getType() == AttributeCond.Type.EQ) {
             PlainAttr<?> container = anyUtils.newPlainAttr();
@@ -119,65 +78,16 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO 
{
         } else {
             query.append("attrs ->> 'schema' = 
?").append(setParameter(parameters, cond.getSchema())).
                     append(" AND ").
-                    append(lower ? "LOWER(" : "").
-                    append(schema.isUniqueConstraint()
-                            ? "attrs -> 'uniqueValue'" : "attrValues").
-                    append(" ->> '").append(key).append("'").
-                    append(lower ? ")" : "");
-
-            switch (cond.getType()) {
-                case LIKE:
-                case ILIKE:
-                    if (not) {
-                        query.append("NOT ");
-                    }
-                    query.append(" LIKE ");
-                    break;
-
-                case GE:
-                    if (not) {
-                        query.append('<');
-                    } else {
-                        query.append(">=");
-                    }
-                    break;
-
-                case GT:
-                    if (not) {
-                        query.append("<=");
-                    } else {
-                        query.append('>');
-                    }
-                    break;
-
-                case LE:
-                    if (not) {
-                        query.append('>');
-                    } else {
-                        query.append("<=");
-                    }
-                    break;
-
-                case LT:
-                    if (not) {
-                        query.append(">=");
-                    } else {
-                        query.append('<');
-                    }
-                    break;
-
-                case EQ:
-                case IEQ:
-                default:
-                    if (not) {
-                        query.append('!');
-                    }
-                    query.append('=');
-            }
+                    append(schemaInfo.getRight() ? "LOWER(" : "").
+                    append(schema.isUniqueConstraint() ? "attrs -> 
'uniqueValue'" : "attrValues").
+                    append(" ->> '").append(schemaInfo.getLeft()).append("'").
+                    append(schemaInfo.getRight() ? ")" : "");
+
+            appendOp(query, cond.getType(), not);
 
-            query.append(lower ? "LOWER(" : "").
+            query.append(schemaInfo.getRight() ? "LOWER(" : "").
                     append("?").append(setParameter(parameters, 
cond.getExpression())).
-                    append(lower ? ")" : "");
+                    append(schemaInfo.getRight() ? ")" : "");
         }
     }
 
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAJSONEntityFactory.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAJSONEntityFactory.java
index bcd046d..a27e5e3 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAJSONEntityFactory.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAJSONEntityFactory.java
@@ -140,6 +140,7 @@ public abstract class JPAJSONEntityFactory extends 
JPAEntityFactory implements I
 
     @Override
     public void afterPropertiesSet() throws Exception {
-        beanFactory.createBean(jpaJSONAnyDAOClass(), 
AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+        beanFactory.registerSingleton("jpaJSONAnyDAO",
+                beanFactory.createBean(jpaJSONAnyDAOClass(), 
AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false));
     }
 }
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/MyJPAJSONEntityFactory.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/MyJPAJSONEntityFactory.java
new file mode 100644
index 0000000..ca17f7b
--- /dev/null
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/MyJPAJSONEntityFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
+import org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAnyDAO;
+import org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAnySearchDAO;
+
+public class MyJPAJSONEntityFactory extends JPAJSONEntityFactory {
+
+    @Override
+    public Class<? extends AnySearchDAO> anySearchDAOClass() {
+        return MyJPAJSONAnySearchDAO.class;
+    }
+
+    @Override
+    protected Class<? extends JPAJSONAnyDAO> jpaJSONAnyDAOClass() {
+        return MyJPAJSONAnyDAO.class;
+    }
+}
diff --git 
a/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-myjson.xml 
b/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-myjson.xml
new file mode 100644
index 0000000..1c397a0
--- /dev/null
+++ 
b/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-myjson.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm";
+                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+                 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm 
+                                     
http://java.sun.com/xml/ns/persistence/orm_2_0.xsd";
+                 version="2.0">
+  
+  <persistence-unit-metadata>
+    <persistence-unit-defaults>
+      <entity-listeners>
+        <entity-listener 
class="org.apache.syncope.core.persistence.jpa.validation.entity.EntityValidationListener">
+          <pre-persist method-name="validate"/>
+          <pre-update method-name="validate"/>
+        </entity-listener>
+      </entity-listeners>
+    </persistence-unit-defaults>
+  </persistence-unit-metadata>
+ 
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject">
+    <attributes>
+      <basic name="plainAttrs">
+        <column column-definition="json"/>
+        <lob/>
+      </basic>
+    </attributes>
+  </entity>
+    
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup">
+    <attributes>
+      <basic name="plainAttrs">
+        <column column-definition="json"/>
+        <lob/>
+      </basic>
+    </attributes>
+  </entity>
+
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser">
+    <attributes>
+      <basic name="plainAttrs">
+        <column column-definition="json"/>
+        <lob/>
+      </basic>
+    </attributes>
+  </entity>
+
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.conf.JPAJSONConf">
+    <attributes>
+      <basic name="plainAttrs">
+        <column column-definition="json"/>
+        <lob/>
+      </basic>
+    </attributes>
+  </entity>
+
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup">
+    <attributes>
+      <many-to-one name="userOwner" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser"/>
+      <many-to-one name="groupOwner" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"/>
+    </attributes>
+  </entity>
+
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.group.JPATypeExtension">
+    <attributes>
+      <many-to-one name="group" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"/>
+    </attributes>
+  </entity>
+
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUMembership">
+    <attributes>
+      <many-to-one name="leftEnd" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser">
+        <join-column name="user_id"/>
+      </many-to-one>
+      <many-to-one name="rightEnd" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup">
+        <join-column name="group_id"/>
+      </many-to-one>        
+    </attributes>
+  </entity>
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.user.JPAUDynGroupMembership">
+    <attributes>
+      <one-to-one name="group" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"/>
+    </attributes>
+  </entity>
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.user.JPAURelationship">
+    <attributes>
+      <many-to-one name="leftEnd" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser">
+        <join-column name="user_id"/>
+      </many-to-one>
+      <many-to-one name="rightEnd" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject">
+        <join-column name="anyObject_id"/>
+      </many-to-one>
+    </attributes>
+  </entity>
+
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership">
+    <attributes>
+      <many-to-one name="leftEnd" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject">
+        <join-column name="anyObject_id"/>
+      </many-to-one>
+      <many-to-one name="rightEnd" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup">
+        <join-column name="group_id"/>
+      </many-to-one>
+    </attributes>
+  </entity>
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADynGroupMembership">
+    <attributes>
+      <one-to-one name="group" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup"/>
+    </attributes>
+  </entity>
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAARelationship">
+    <attributes>
+      <many-to-one name="leftEnd" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject">
+        <join-column name="left_anyObject_id"/>
+      </many-to-one>
+      <many-to-one name="rightEnd" 
target-entity="org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAJSONAnyObject">
+        <join-column name="right_anyObject_id"/>
+      </many-to-one>
+    </attributes>
+  </entity>
+</entity-mappings>
diff --git 
a/fit/core-reference/src/main/resources/mysql/domains/Master.properties 
b/core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties
similarity index 76%
copy from fit/core-reference/src/main/resources/mysql/domains/Master.properties
copy to 
core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties
index ce09eec..d945b5a 100644
--- a/fit/core-reference/src/main/resources/mysql/domains/Master.properties
+++ 
b/core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties
@@ -14,15 +14,15 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-Master.driverClassName=com.mysql.jdbc.Driver
-Master.url=jdbc:mysql://localhost:3306/syncope?characterEncoding=UTF-8&relaxAutoCommit=true
+Master.driverClassName=com.mysql.cj.jdbc.Driver
+Master.url=jdbc:mysql://localhost:3306/syncope?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8
 Master.schema=
 Master.username=syncope
 Master.password=syncope
-Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB)
-Master.orm=META-INF/spring-orm.xml
+Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB,timestampTypeName=DATETIME(3))
+Master.orm=META-INF/spring-orm-myjson.xml
 
 Master.pool.maxActive=10
 Master.pool.minIdle=2
 
-Master.audit.sql=audit.sql
+Master.audit.sql=audit_mysql_innodb.sql
diff --git a/core/persistence-jpa-json/src/main/resources/myjson/indexes.xml 
b/core/persistence-jpa-json/src/main/resources/myjson/indexes.xml
new file mode 100644
index 0000000..b16004d
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/resources/myjson/indexes.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd";>
+<properties>
+  <comment>Additional indexes (in respect to JPA's)</comment>
+
+  <entry key="UDynGroupMembers_any_id">CREATE INDEX UDynGroupMembers_any_id ON 
UDynGroupMembers(any_id)</entry>
+  <entry key="UDynGroupMembers_group_id">CREATE INDEX 
UDynGroupMembers_group_id ON UDynGroupMembers(group_id)</entry>
+  <entry key="ADynGroupMembers_any_id">CREATE INDEX ADynGroupMembers_any_id ON 
ADynGroupMembers(any_id)</entry>
+  <entry key="ADynGroupMembers_group_id">CREATE INDEX 
ADynGroupMembers_group_id ON ADynGroupMembers(group_id)</entry>
+
+  <entry key="DynRoleMembers_any_id">CREATE INDEX DynRoleMembers_any_id ON 
DynRoleMembers(any_id)</entry>
+  <entry key="DynRoleMembers_role_id">CREATE INDEX DynRoleMembers_role_id ON 
DynRoleMembers(role_id)</entry>
+
+  <entry key="DynRealmMembers_any_id">CREATE INDEX DynRealmMembers_any_id ON 
DynRealmMembers(any_id)</entry>
+  <entry key="DynRealmMembers_realm_id">CREATE INDEX 
DynRealmMembers_dynRealm_id ON DynRealmMembers(dynRealm_id)</entry>
+
+  <entry key="CPlainAttrValue_stringvalueIndex">CREATE INDEX 
CAttrValue_stringvalueIndex ON CPlainAttrValue(stringvalue)</entry>
+  <entry key="CPlainAttrValue_datevalueIndex">CREATE INDEX 
CAttrValue_datevalueIndex ON CPlainAttrValue(datevalue)</entry>
+  <entry key="CPlainAttrValue_longvalueIndex">CREATE INDEX 
CAttrValue_longvalueIndex ON CPlainAttrValue(longvalue)</entry>
+  <entry key="CPlainAttrValue_doublevalueIndex">CREATE INDEX 
CAttrValue_doublevalueIndex ON CPlainAttrValue(doublevalue)</entry>
+  <entry key="CPlainAttrValue_booleanvalueIndex">CREATE INDEX 
CAttrValue_booleanvalueIndex ON CPlainAttrValue(booleanvalue)</entry>
+
+  <entry key="UMembership_GroupIndex">CREATE INDEX UMembership_GroupIndex ON 
UMembership(group_id)</entry>
+  <entry key="UMembership_UserIndex">CREATE INDEX UMembership_UserIndex ON 
UMembership(user_id)</entry>
+  <entry key="AMembership_GroupIndex">CREATE INDEX AMembership_GroupIndex ON 
AMembership(group_id)</entry>
+  <entry key="AMembership_AnyObjectIndex">CREATE INDEX 
AMembership_AnyObjectIndex ON AMembership(anyObject_id)</entry>
+
+  <entry key="URelationship_RightIndex">CREATE INDEX URelationship_RightIndex 
ON URelationship(anyObject_id)</entry>
+  <entry key="URelationship_LeftIndex">CREATE INDEX URelationship_LeftIndex ON 
URelationship(user_id)</entry>
+  <entry key="ARelationship_RightIndex">CREATE INDEX ARelationship_RightIndex 
ON ARelationship(right_anyObject_id)</entry>
+  <entry key="ARelationship_AnyObjectIndex">CREATE INDEX 
ARelationship_AnyObjectIndex ON ARelationship(left_anyObject_id)</entry>
+
+  <entry key="CPlainAttrValue_attrIndex">CREATE INDEX 
CPlainAttrValue_attrIndex on CPlainAttrValue(attribute_id)</entry>
+  <entry key="CPAttrUniqueValue_attrIndex">CREATE INDEX 
CPAttrUniqueValue_attrIndex on CPlainAttrUniqueValue(attribute_id)</entry>
+
+  <entry key="CPlainAttr_owner_Index">CREATE INDEX CPlainAttr_owner_Index on 
CPlainAttr(owner_id)</entry>
+  <entry key="CPlainAttr_schema_Index">CREATE INDEX CPlainAttr_schema_Index on 
CPlainAttr(schema_id)</entry>
+
+  <entry key="Task_executedIndex">CREATE INDEX Task_executedIndex ON 
Task(executed)</entry>
+</properties>
diff --git 
a/fit/core-reference/src/main/resources/mysql/domains/Master.properties 
b/core/persistence-jpa-json/src/main/resources/myjson/persistence.properties
similarity index 50%
copy from fit/core-reference/src/main/resources/mysql/domains/Master.properties
copy to 
core/persistence-jpa-json/src/main/resources/myjson/persistence.properties
index ce09eec..31a2dd8 100644
--- a/fit/core-reference/src/main/resources/mysql/domains/Master.properties
+++ b/core/persistence-jpa-json/src/main/resources/myjson/persistence.properties
@@ -14,15 +14,14 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-Master.driverClassName=com.mysql.jdbc.Driver
-Master.url=jdbc:mysql://localhost:3306/syncope?characterEncoding=UTF-8&relaxAutoCommit=true
-Master.schema=
-Master.username=syncope
-Master.password=syncope
-Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB)
-Master.orm=META-INF/spring-orm.xml
-
-Master.pool.maxActive=10
-Master.pool.minIdle=2
-
-Master.audit.sql=audit.sql
+content.directory=${conf.directory}
+entity.factory=org.apache.syncope.core.persistence.jpa.entity.MyJPAJSONEntityFactory
+plainSchema.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONPlainSchemaDAO
+plainAttr.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONPlainAttrDAO
+plainAttrValue.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONPlainAttrValueDAO
+any.search.dao=org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAnySearchDAO
+user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONUserDAO
+group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONGroupDAO
+anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONAnyObjectDAO
+conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONConfDAO
+openjpa.RemoteCommitProvider=sjvm
diff --git a/core/persistence-jpa-json/src/main/resources/myjson/views.xml 
b/core/persistence-jpa-json/src/main/resources/myjson/views.xml
new file mode 100644
index 0000000..aa0e3c0
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/resources/myjson/views.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd";>
+<properties>
+  
+  <entry key="UDynGroupMembers">
+    CREATE TABLE UDynGroupMembers(
+    any_id CHAR(36),
+    group_id CHAR(36),
+    UNIQUE(any_id, group_id))
+  </entry>
+  <entry key="ADynGroupMembers">
+    CREATE TABLE ADynGroupMembers(
+    anyType_id VARCHAR(255),
+    any_id CHAR(36),
+    group_id CHAR(36),
+    UNIQUE(anyType_id, any_id, group_id))
+  </entry>
+  <entry key="DynRoleMembers">
+    CREATE TABLE DynRoleMembers(
+    any_id CHAR(36),
+    role_id VARCHAR(255),
+    UNIQUE(any_id, role_id))
+  </entry>
+  <entry key="DynRealmMembers">
+    CREATE TABLE DynRealmMembers(
+    any_id CHAR(36),
+    dynRealm_id VARCHAR(255),
+    UNIQUE(any_id, dynRealm_id))
+  </entry>
+
+  <!-- user -->
+  <entry key="user_search">
+    CREATE VIEW user_search AS
+
+    SELECT u.id as any_id, u.*, attrs.*
+    FROM SyncopeUser u, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' 
COLUMNS (
+    plainSchema VARCHAR(255) PATH '$.schema',
+    NESTED PATH '$.values[*]' COLUMNS (
+    binaryValue LONGBLOB PATH '$.binaryValue',
+    booleanValue INT PATH '$.booleanValue',
+    dateValue BIGINT(20) PATH '$.dateValue',
+    doubleValue DOUBLE PATH '$.doubleValue',
+    longValue BIGINT(20) PATH '$.longValue',
+    stringValue VARCHAR(255) PATH '$.stringValue'),
+    attrUniqueValue JSON PATH '$.uniqueValue')
+    ) AS attrs
+  </entry>
+  <entry key="user_search_urelationship">
+    CREATE VIEW user_search_urelationship AS
+
+    SELECT m.user_id AS any_id, m.anyObject_id AS right_any_id, m.type_id AS 
type
+    FROM URelationship m
+  </entry>
+  <entry key="user_search_umembership">
+    CREATE VIEW user_search_umembership AS
+
+    SELECT m.user_id AS any_id, g.id AS group_id, g.name AS group_name
+    FROM UMembership m, SyncopeGroup g
+    WHERE m.group_id = g.id
+  </entry>
+  <entry key="user_search_role">
+    CREATE VIEW user_search_role AS
+
+    SELECT ss.user_id AS any_id, ss.role_id AS role_id
+    FROM SyncopeUser_SyncopeRole ss
+  </entry>
+  <entry key="user_search_priv">
+    CREATE VIEW user_search_priv AS
+
+    SELECT ss.user_id AS any_id, sp.privilege_id AS privilege_id
+    FROM SyncopeUser_SyncopeRole ss, SyncopeRole_Privilege sp
+    WHERE ss.role_id = sp.role_id
+  </entry>
+  <entry key="user_search_dynpriv">
+    CREATE VIEW user_search_dynpriv AS
+
+    SELECT any_id, privilege_id
+    FROM DynRoleMembers drm, SyncopeRole_Privilege rp
+    WHERE drm.role_id = rp.role_id
+  </entry>
+  <entry key="user_search_resource">
+    CREATE VIEW user_search_resource AS
+
+    SELECT st.user_id AS any_id, st.resource_id AS resource_id
+    FROM SyncopeUser_ExternalResource st
+  </entry>
+  <entry key="user_search_group_res">
+    CREATE VIEW user_search_group_res AS
+
+    SELECT m.user_id AS any_id, st.resource_id AS resource_id
+    FROM UMembership m, SyncopeGroup r, SyncopeGroup_ExternalResource st
+    WHERE m.group_id = r.id AND st.group_id = r.id
+  </entry>
+
+  <!-- anyObject -->
+  <entry key="anyObject_search">
+    CREATE VIEW anyObject_search AS
+ 
+    SELECT a.id as any_id, a.*, attrs.*
+    FROM AnyObject a, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS (
+    plainSchema VARCHAR(255) PATH '$.schema',
+    NESTED PATH '$.values[*]' COLUMNS (
+    binaryValue LONGBLOB PATH '$.binaryValue',
+    booleanValue INT PATH '$.booleanValue',
+    dateValue BIGINT(20) PATH '$.dateValue',
+    doubleValue DOUBLE PATH '$.doubleValue',
+    longValue BIGINT(20) PATH '$.longValue',
+    stringValue VARCHAR(255) PATH '$.stringValue'),
+    attrUniqueValue JSON PATH '$.uniqueValue')
+    ) AS attrs
+  </entry>
+  <entry key="anyObject_search_arelationship">
+    CREATE VIEW anyObject_search_arelationship AS
+
+    SELECT m.left_anyObject_id AS any_id, m.right_anyObject_id AS 
right_any_id, m.type_id AS type
+    FROM ARelationship m
+  </entry>
+  <entry key="anyObject_search_amembership">
+    CREATE VIEW anyObject_search_amembership AS
+
+    SELECT m.anyObject_id AS any_id, g.id AS group_id, g.name AS group_name
+    FROM AMembership m, SyncopeGroup g
+    WHERE m.group_id = g.id
+  </entry>
+  <entry key="anyObject_search_resource">
+    CREATE VIEW anyObject_search_resource AS
+
+    SELECT st.anyObject_id AS any_id, st.resource_id AS resource_id
+    FROM AnyObject_ExternalResource st
+  </entry>
+  <entry key="anyObject_search_group_res">
+    CREATE VIEW anyObject_search_group_res AS
+
+    SELECT m.anyObject_id AS any_id, st.resource_id AS resource_id
+    FROM AMembership m, SyncopeGroup r, SyncopeGroup_ExternalResource st
+    WHERE m.group_id = r.id AND st.group_id = r.id
+  </entry>
+
+  <!-- group -->
+  <entry key="group_search">
+    CREATE VIEW group_search AS
+ 
+    SELECT g.id as any_id, g.*, attrs.*
+    FROM SyncopeGroup g, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' 
COLUMNS (
+    plainSchema VARCHAR(255) PATH '$.schema',
+    NESTED PATH '$.values[*]' COLUMNS (
+    binaryValue LONGBLOB PATH '$.binaryValue',
+    booleanValue INT PATH '$.booleanValue',
+    dateValue BIGINT(20) PATH '$.dateValue',
+    doubleValue DOUBLE PATH '$.doubleValue',
+    longValue BIGINT(20) PATH '$.longValue',
+    stringValue VARCHAR(255) PATH '$.stringValue'),
+    attrUniqueValue JSON PATH '$.uniqueValue')
+    ) AS attrs
+  </entry>
+  <entry key="group_search_resource">
+    CREATE VIEW group_search_resource AS
+
+    SELECT st.group_id AS any_id, st.resource_id AS resource_id
+    FROM SyncopeGroup_ExternalResource st
+  </entry>
+
+</properties>
diff --git 
a/core/persistence-jpa-json/src/test/resources/pgjsonb/domains/MasterContent.xml
 b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
similarity index 100%
rename from 
core/persistence-jpa-json/src/test/resources/pgjsonb/domains/MasterContent.xml
rename to core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index 02e2535..fcf3bba 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -166,6 +166,8 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
             // 1. get the query string from the search condition
             StringBuilder queryString = getQuery(buildEffectiveCond(cond, 
filter.getRight()), parameters, svs);
 
+            LOG.debug("Query: {}, parameters: {}", queryString, parameters);
+
             // 2. take into account realms and ordering
             OrderBySupport obs = parseOrderBy(kind, svs, orderBy);
             if (queryString.charAt(0) == '(') {
@@ -179,6 +181,8 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
                     append(filter.getLeft()).
                     append(buildOrderBy(obs));
 
+            LOG.debug("Query with auth and order by statements: {}, 
parameters: {}", queryString, parameters);
+
             // 3. prepare the search query
             Query query = 
entityManager().createNativeQuery(queryString.toString());
 
diff --git 
a/core/persistence-jpa/src/main/resources/audit/audit_mysql_innodb.sql 
b/core/persistence-jpa/src/main/resources/audit/audit_mysql_innodb.sql
index ff753fa..4d8426c 100644
--- a/core/persistence-jpa/src/main/resources/audit/audit_mysql_innodb.sql
+++ b/core/persistence-jpa/src/main/resources/audit/audit_mysql_innodb.sql
@@ -21,4 +21,4 @@ CREATE TABLE IF NOT EXISTS SYNCOPEAUDIT (
   LOGGER VARCHAR(255) NOT NULL,
   MESSAGE TEXT NOT NULL,
   THROWABLE TEXT
-) ENGINE=InnoDB
+) ENGINE=InnoDB;
diff --git 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyTypeTest.java
 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyTypeTest.java
index 1db62d8..26b1da9 100644
--- 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyTypeTest.java
+++ 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyTypeTest.java
@@ -90,6 +90,7 @@ public class AnyTypeTest extends AbstractTest {
             newType.setKey("new type");
             newType.setKind(AnyTypeKind.USER);
             anyTypeDAO.save(newType);
+            entityManager().flush();
         });
     }
 
@@ -100,6 +101,7 @@ public class AnyTypeTest extends AbstractTest {
             newType.setKey("group");
             newType.setKind(AnyTypeKind.ANY_OBJECT);
             anyTypeDAO.save(newType);
+            entityManager().flush();
         });
     }
 
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 85c992c..645dcca 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -724,7 +724,7 @@ under the License.
             <filtering>true</filtering>
           </resource>
           <resource>
-            
<directory>${basedir}/../../core/persistence-jpa-json/src/test/resources/pgjsonb/domains</directory>
+            
<directory>${basedir}/../../core/persistence-jpa-json/src/test/resources/domains</directory>
             <targetPath>${project.build.directory}/classes/domains</targetPath>
             <filtering>true</filtering>
           </resource>
@@ -851,7 +851,165 @@ under the License.
         </testResources>
       </build>
     </profile>
+
+    <profile>
+      <id>myjson-it</id>
+
+      <properties>
+        <jdbcdriver.groupId>mysql</jdbcdriver.groupId>
+        <jdbcdriver.artifactId>mysql-connector-java</jdbcdriver.artifactId>
+      </properties>
+
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.syncope.core</groupId>
+          <artifactId>syncope-core-persistence-jpa-json</artifactId>
+          <version>${project.version}</version>
+        </dependency>
     
+        <dependency>
+          <groupId>mysql</groupId>
+          <artifactId>mysql-connector-java</artifactId>
+          <version>${jdbc.mysql.version}</version>
+          <scope>test</scope>
+        </dependency>
+      </dependencies>
+
+      <build>
+        <defaultGoal>clean verify</defaultGoal>
+
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-war-plugin</artifactId>
+            <configuration>
+              
<packagingExcludes>WEB-INF/classes/domains/Two*</packagingExcludes>
+            </configuration>
+          </plugin>
+
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-antrun-plugin</artifactId>
+            <inherited>true</inherited>
+            <executions>
+              <execution>
+                <id>remove-domain-Two</id>
+                <phase>prepare-package</phase>
+                <configuration>
+                  <target>
+                    <delete>
+                      <fileset 
dir="${project.build.directory}/classes/domains" includes="Two*"/>
+                    </delete>
+                  </target>
+                </configuration>
+                <goals>
+                  <goal>run</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+            <configuration>
+              <images>
+                <image>
+                  <name>mysql/mysql-server:${docker.mysql.version}</name>
+                  <run>
+                    <cmd>--skip-log-bin --server-id=1</cmd>
+                    <env>
+                      <MYSQL_ROOT_PASSWORD>password</MYSQL_ROOT_PASSWORD>
+                      <MYSQL_DATABASE>syncope</MYSQL_DATABASE>
+                      <MYSQL_USER>syncope</MYSQL_USER>
+                      <MYSQL_PASSWORD>syncope</MYSQL_PASSWORD>
+                    </env>
+                    <ports>
+                      <port>3306:3306</port>
+                    </ports>
+                    <wait>
+                      <log>MySQL init process done. Ready for start up.</log>
+                      <time>30000</time>
+                    </wait>
+                  </run>
+                </image>
+              </images>
+            </configuration>
+            <executions>
+              <execution>
+                <id>start-mysql</id>
+                <phase>pre-integration-test</phase>
+                <goals>
+                  <goal>start</goal>
+                </goals>
+              </execution>
+              <execution>
+                <id>stop-mysql</id>
+                <phase>post-integration-test</phase>
+                <goals>
+                  <goal>stop</goal>
+                  <goal>remove</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+
+          <plugin>
+            <groupId>org.codehaus.cargo</groupId>
+            <artifactId>cargo-maven2-plugin</artifactId>
+            <inherited>true</inherited>
+            <executions>
+              <execution>
+                <id>start-container</id>
+                <phase>pre-integration-test</phase>
+                <goals>
+                  <goal>start</goal>
+                </goals>
+              </execution>
+              <execution>
+                <id>stop-container</id>
+                <phase>post-integration-test</phase>
+                <goals>
+                  <goal>stop</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+
+        <resources>
+          <resource>
+            <directory>src/main/resources</directory>
+            <filtering>true</filtering>
+            <excludes>
+              <exclude>provisioning.properties</exclude>
+              <exclude>indexes.xml</exclude>
+              <exclude>views.xml</exclude>
+            </excludes>
+          </resource>
+          <resource>
+            <directory>src/main/resources/myjson</directory>
+            <filtering>true</filtering>
+          </resource>
+          <resource>
+            
<directory>${basedir}/../../core/persistence-jpa-json/src/test/resources/domains</directory>
+            <targetPath>${project.build.directory}/classes/domains</targetPath>
+            <filtering>true</filtering>
+          </resource>
+        </resources>
+        <testResources>
+          <testResource>
+            
<directory>${basedir}/../../core/persistence-jpa-json/src/main/resources/myjson</directory>
+            <includes>
+              <include>persistence.properties</include>
+              <include>indexes.xml</include>
+              <include>views.xml</include>
+            </includes>            
+          </testResource>
+        </testResources>
+      </build>
+    </profile>
+
     <profile>
       <id>mysql-it</id>
 
@@ -879,9 +1037,11 @@ under the License.
             <configuration>
               <images>
                 <image>
-                  <name>mysql/mysql-server:5.7</name>
+                  <name>mysql/mysql-server:${docker.mysql.version}</name>
                   <run>
+                    <cmd>--skip-log-bin --server-id=1</cmd>
                     <env>
+                      <MYSQL_ROOT_PASSWORD>password</MYSQL_ROOT_PASSWORD>
                       <MYSQL_DATABASE>syncope</MYSQL_DATABASE>
                       <MYSQL_USER>syncope</MYSQL_USER>
                       <MYSQL_PASSWORD>syncope</MYSQL_PASSWORD>
@@ -889,6 +1049,10 @@ under the License.
                     <ports>
                       <port>3306:3306</port>
                     </ports>
+                    <wait>
+                      <log>MySQL init process done. Ready for start up.</log>
+                      <time>30000</time>
+                    </wait>
                   </run>
                 </image>
               </images>
diff --git 
a/fit/core-reference/src/main/resources/mysql/domains/Master.properties 
b/fit/core-reference/src/main/resources/myjson/domains/Master.properties
similarity index 76%
copy from fit/core-reference/src/main/resources/mysql/domains/Master.properties
copy to fit/core-reference/src/main/resources/myjson/domains/Master.properties
index ce09eec..d945b5a 100644
--- a/fit/core-reference/src/main/resources/mysql/domains/Master.properties
+++ b/fit/core-reference/src/main/resources/myjson/domains/Master.properties
@@ -14,15 +14,15 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-Master.driverClassName=com.mysql.jdbc.Driver
-Master.url=jdbc:mysql://localhost:3306/syncope?characterEncoding=UTF-8&relaxAutoCommit=true
+Master.driverClassName=com.mysql.cj.jdbc.Driver
+Master.url=jdbc:mysql://localhost:3306/syncope?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8
 Master.schema=
 Master.username=syncope
 Master.password=syncope
-Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB)
-Master.orm=META-INF/spring-orm.xml
+Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB,timestampTypeName=DATETIME(3))
+Master.orm=META-INF/spring-orm-myjson.xml
 
 Master.pool.maxActive=10
 Master.pool.minIdle=2
 
-Master.audit.sql=audit.sql
+Master.audit.sql=audit_mysql_innodb.sql
diff --git 
a/fit/core-reference/src/main/resources/mysql/provisioning.properties 
b/fit/core-reference/src/main/resources/myjson/provisioning.properties
similarity index 97%
copy from fit/core-reference/src/main/resources/mysql/provisioning.properties
copy to fit/core-reference/src/main/resources/myjson/provisioning.properties
index 48f9ef6..3883cb5 100644
--- a/fit/core-reference/src/main/resources/mysql/provisioning.properties
+++ b/fit/core-reference/src/main/resources/myjson/provisioning.properties
@@ -27,6 +27,6 @@ 
anyObjectProvisioningManager=org.apache.syncope.core.provisioning.java.DefaultAn
 virAttrCache=org.apache.syncope.core.provisioning.java.cache.MemoryVirAttrCache
 
 quartz.jobstore=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
-quartz.sql=tables_mysql.sql
+quartz.sql=tables_mysql_innodb.sql
 quartz.scheduler.idleWaitTime=5000
 quartz.disableInstance=false
diff --git 
a/fit/core-reference/src/main/resources/mysql/domains/Master.properties 
b/fit/core-reference/src/main/resources/mysql/domains/Master.properties
index ce09eec..e36e370 100644
--- a/fit/core-reference/src/main/resources/mysql/domains/Master.properties
+++ b/fit/core-reference/src/main/resources/mysql/domains/Master.properties
@@ -14,15 +14,15 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-Master.driverClassName=com.mysql.jdbc.Driver
-Master.url=jdbc:mysql://localhost:3306/syncope?characterEncoding=UTF-8&relaxAutoCommit=true
+Master.driverClassName=com.mysql.cj.jdbc.Driver
+Master.url=jdbc:mysql://localhost:3306/syncope?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8
 Master.schema=
 Master.username=syncope
 Master.password=syncope
-Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB)
+Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB,timestampTypeName=DATETIME(3))
 Master.orm=META-INF/spring-orm.xml
 
 Master.pool.maxActive=10
 Master.pool.minIdle=2
 
-Master.audit.sql=audit.sql
+Master.audit.sql=audit_mysql_innodb.sql
diff --git 
a/fit/core-reference/src/main/resources/mysql/provisioning.properties 
b/fit/core-reference/src/main/resources/mysql/provisioning.properties
index 48f9ef6..3883cb5 100644
--- a/fit/core-reference/src/main/resources/mysql/provisioning.properties
+++ b/fit/core-reference/src/main/resources/mysql/provisioning.properties
@@ -27,6 +27,6 @@ 
anyObjectProvisioningManager=org.apache.syncope.core.provisioning.java.DefaultAn
 virAttrCache=org.apache.syncope.core.provisioning.java.cache.MemoryVirAttrCache
 
 quartz.jobstore=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
-quartz.sql=tables_mysql.sql
+quartz.sql=tables_mysql_innodb.sql
 quartz.scheduler.idleWaitTime=5000
 quartz.disableInstance=false
diff --git a/pom.xml b/pom.xml
index 25df74d..5293fff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -396,7 +396,7 @@ under the License.
     <spring.version>5.1.3.RELEASE</spring.version>
     <spring-security.version>5.1.2.RELEASE</spring-security.version>
 
-    <openjpa.version>3.0.0</openjpa.version>
+    <openjpa.version>3.0.1-SNAPSHOT</openjpa.version>
     <hikaricp.version>3.2.0</hikaricp.version>
     <bval.version>1.1.2</bval.version>
 
@@ -518,10 +518,11 @@ under the License.
     <protractor.version>5.4.0</protractor.version>    
 
     <docker.postgresql.version>11.1</docker.postgresql.version>
+    <docker.mysql.version>8.0</docker.mysql.version>
     <docker.mariadb.version>10.4</docker.mariadb.version>
 
     <jdbc.postgresql.version>42.2.5</jdbc.postgresql.version>
-    <jdbc.mysql.version>5.1.47</jdbc.mysql.version>
+    <jdbc.mysql.version>8.0.13</jdbc.mysql.version>
     <jdbc.mariadb.version>2.3.0</jdbc.mariadb.version>
     <jdbc.mssql.version>6.4.0.jre</jdbc.mssql.version>
 

Reply via email to