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

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


The following commit(s) were added to refs/heads/master by this push:
     new b92248f160 [SYNCOPE-1700] Introducing ojson (#382)
b92248f160 is described below

commit b92248f160798e3f99c22ce80a5d54de32867d17
Author: Francesco Chicchiriccò <ilgro...@users.noreply.github.com>
AuthorDate: Fri Oct 21 14:17:42 2022 +0200

    [SYNCOPE-1700] Introducing ojson (#382)
---
 .github/workflows/oracle.yml                       |   4 +
 core/persistence-jpa-json/pom.xml                  | 122 +++++++++++-
 .../jpa/MyJPAJSONPersistenceContext.java           |   2 +-
 ...ontext.java => OJPAJSONPersistenceContext.java} |  34 ++--
 .../jpa/PGJPAJSONPersistenceContext.java           |   2 +-
 .../persistence/jpa/dao/AbstractJPAJSONAnyDAO.java |  37 +++-
 .../core/persistence/jpa/dao/MyJPAJSONAnyDAO.java  |   9 +-
 .../persistence/jpa/dao/MyJPAJSONAnySearchDAO.java |  20 +-
 .../persistence/jpa/dao/MyJPAJSONAuditConfDAO.java |   2 +-
 .../core/persistence/jpa/dao/OJPAJSONAnyDAO.java   |  79 ++++++++
 ...AnySearchDAO.java => OJPAJSONAnySearchDAO.java} | 209 ++++++++++-----------
 .../persistence/jpa/dao/OJPAJSONAuditConfDAO.java  |  83 ++++++++
 .../jpa/dao/OJPAJSONPlainSchemaDAO.java            |  48 +++++
 .../core/persistence/jpa/dao/PGJPAJSONAnyDAO.java  |  16 +-
 .../persistence/jpa/dao/PGJPAJSONAnySearchDAO.java |   5 +-
 .../persistence/jpa/dao/PGJPAJSONAuditConfDAO.java |   2 +-
 .../jpa/entity/OJPAJSONEntityFactory.java          |  30 +++
 .../jpa/entity/anyobject/JPAJSONAnyObject.java     |   2 -
 .../persistence/jpa/entity/group/JPAJSONGroup.java |   2 -
 .../jpa/entity/user/JPAJSONLinkedAccount.java      |   2 -
 .../persistence/jpa/entity/user/JPAJSONUser.java   |   2 -
 .../main/resources/META-INF/spring-orm-ojson.xml   | 136 ++++++++++++++
 .../src/main/resources/META-INF/spring.factories   |   3 +-
 .../src/main/resources/audit/audit_ojson.sql       |  24 +++
 .../spring.factories => core-ojson.properties}     |  20 +-
 .../src/main/resources/myjson/views.xml            |  12 +-
 .../src/main/resources/ojson/indexes.xml           |  59 ++++++
 .../src/main/resources/{myjson => ojson}/views.xml |  84 +++++----
 .../src/main/resources/persistence-enhance.xml     |   2 +-
 .../jpa/JPAJSONTestContextCustomizer.java          |  34 ++--
 .../resources/core-ojson-test.properties}          |  12 +-
 .../src/test/resources/domains/MasterContent.xml   |   5 +-
 .../core/persistence/jpa/dao/JPAAnySearchDAO.java  |   5 +
 .../core/persistence/jpa/inner/UserTest.java       |   4 +-
 fit/core-reference/pom.xml                         | 114 ++++++++++-
 .../fit/core/reference/ITImplementationLookup.java |  10 +
 .../src/main/resources/core-ojson.properties       |  20 +-
 .../apache/syncope/fit/core/AnyObjectITCase.java   |  20 +-
 .../org/apache/syncope/fit/core/AuditITCase.java   |   3 +-
 pom.xml                                            |   1 +
 .../getting-started/systemRequirements.adoc        |   4 +-
 .../reference-guide/configuration/dbms.adoc        |  55 +++++-
 42 files changed, 1076 insertions(+), 263 deletions(-)

diff --git a/.github/workflows/oracle.yml b/.github/workflows/oracle.yml
index 2253bec62b..e1c0bd4107 100644
--- a/.github/workflows/oracle.yml
+++ b/.github/workflows/oracle.yml
@@ -44,5 +44,9 @@ jobs:
         restore-keys: ${{ runner.os }}-m2
     - name: Build
       run: mvn -U -T 1C -P 'skipTests,all'
+    - name: 'Unit Tests: Oracle JPA JSON'
+      run: mvn -f core/persistence-jpa-json/pom.xml -P ojson 
-Dinvoker.streamLogs=true -Dmodernizer.skip=true -Dianal.phase=none 
-Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true
     - name: 'Integration Tests: Oracle'
       run: mvn -f fit/core-reference/pom.xml -P oracle-it 
-Dinvoker.streamLogs=true -Dmodernizer.skip=true -Drat.skip=true 
-Dcheckstyle.skip=true -Djacoco.skip=true
+    - name: 'Integration Tests: Oracle JPA JSON'
+      run: mvn -f fit/core-reference/pom.xml -P ojson-it 
-Dinvoker.streamLogs=true -Dmodernizer.skip=true -Drat.skip=true 
-Dcheckstyle.skip=true -Djacoco.skip=true
diff --git a/core/persistence-jpa-json/pom.xml 
b/core/persistence-jpa-json/pom.xml
index 682630b722..71350950c1 100644
--- a/core/persistence-jpa-json/pom.xml
+++ b/core/persistence-jpa-json/pom.xml
@@ -34,6 +34,7 @@ under the License.
   <packaging>jar</packaging>
   
   <properties>
+    <orm>pgjsonb</orm>
     <rootpom.basedir>${basedir}/../..</rootpom.basedir>
   </properties>
 
@@ -101,7 +102,7 @@ under the License.
           </dependency>
         </dependencies>
         <configuration>
-          
<persistenceXmlFile>${project.basedir}/src/main/resources/persistence-enhance.xml</persistenceXmlFile>
 
+          
<persistenceXmlFile>${project.build.directory}/classes/persistence-enhance.xml</persistenceXmlFile>
 
           
<includes>org/apache/syncope/core/persistence/jpa/entity/**/*.class</includes>
           
<connectionDriverName>org.springframework.jdbc.datasource.DriverManagerDataSource</connectionDriverName>
           <connectionProperties>
@@ -187,9 +188,15 @@ under the License.
     </profile>
     
     <profile>
-      <id>schemagen</id>
+      <id>openjpa</id>
       
       <properties>
+        <!-- possible values: sql | schema -->
+        <action>sql</action>
+
+        <!-- possible values: pgjsonb | myjson | ojson -->
+        <orm>ojson</orm>
+
         <skipTests>true</skipTests>
       </properties>
       
@@ -206,7 +213,7 @@ under the License.
                 <id>schemagen</id>
                 <phase>process-classes</phase>
                 <goals>
-                  <goal>schema</goal>
+                  <goal>${action}</goal>
                 </goals>
               </execution>
             </executions>
@@ -441,5 +448,114 @@ under the License.
         </testResources>
       </build>
     </profile>
+
+    <profile>
+      <id>ojson</id>
+
+      <dependencies>
+        <dependency>
+          <groupId>com.oracle.database.jdbc</groupId>
+          <artifactId>ojdbc11</artifactId>
+          <version>${jdbc.oracle.version}</version>
+          <scope>test</scope>
+        </dependency>
+      </dependencies>
+
+      <build>
+        <defaultGoal>clean verify</defaultGoal>
+        
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>build-helper-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>add-test-source</id>
+                <phase>generate-test-sources</phase>
+                <goals>
+                  <goal>add-test-source</goal>
+                </goals>
+                <configuration>
+                  <sources>
+                    
<source>${basedir}/../persistence-jpa/src/test/java</source>
+                  </sources>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+      
+          <plugin>
+            <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>
+              <systemProperties>
+                <profileId>${project.activeProfiles[0].id}</profileId>
+                
<CORE_PROPERTIES>classpath:core-ojson.properties,classpath:core-ojson-test.properties</CORE_PROPERTIES>
+                
<DB_CONTAINER_IP>${docker.container.oracle.ip}</DB_CONTAINER_IP>
+              </systemProperties>
+            </configuration>
+          </plugin>
+
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+            <configuration>
+              <images>
+                <image>
+                  <alias>oracle</alias>
+                  <name>gvenzl/oracle-xe:21-slim</name>
+                  <run>
+                    <env>
+                      <ORACLE_PASSWORD>password</ORACLE_PASSWORD>
+                      <APP_USER>syncope</APP_USER>
+                      <APP_USER_PASSWORD>syncope</APP_USER_PASSWORD>
+                    </env>
+                    <wait>
+                      <log>DATABASE IS READY TO USE</log>
+                      <time>120000</time>
+                    </wait>
+                  </run>
+                </image>
+              </images>
+            </configuration>
+            <executions>
+              <execution>
+                <id>start-oracle</id>
+                <phase>pre-integration-test</phase>
+                <goals>
+                  <goal>start</goal>
+                </goals>
+              </execution>
+              <execution>
+                <id>stop-oracle</id>
+                <phase>post-integration-test</phase>
+                <goals>
+                  <goal>stop</goal>
+                  <goal>remove</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+        
+        <testResources>
+          <testResource>
+            <directory>src/test/resources</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/MyJPAJSONPersistenceContext.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java
index b638bb1051..71805a969a 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/MyJPAJSONPersistenceContext.java
@@ -42,7 +42,7 @@ import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Lazy;
 
-@ConditionalOnExpression("#{!('${provisioning.quartz.delegate}' matches 
'.*PostgreSQLDelegate.*')}")
+@ConditionalOnExpression("#{'${provisioning.quartz.sql}' matches '.*mysql.*'}")
 public class MyJPAJSONPersistenceContext extends JPAJSONPersistenceContext {
 
     @ConditionalOnMissingBean(name = "myJPAJSONEntityFactory")
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/OJPAJSONPersistenceContext.java
similarity index 74%
copy from 
core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
copy to 
core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/OJPAJSONPersistenceContext.java
index 551b2c859d..4b945e9c72 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/OJPAJSONPersistenceContext.java
@@ -32,32 +32,32 @@ import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONAnyDAO;
-import org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONAnySearchDAO;
-import org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONAuditConfDAO;
-import org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONPlainSchemaDAO;
-import org.apache.syncope.core.persistence.jpa.entity.PGJPAJSONEntityFactory;
+import org.apache.syncope.core.persistence.jpa.dao.OJPAJSONAnyDAO;
+import org.apache.syncope.core.persistence.jpa.dao.OJPAJSONAnySearchDAO;
+import org.apache.syncope.core.persistence.jpa.dao.OJPAJSONAuditConfDAO;
+import org.apache.syncope.core.persistence.jpa.dao.OJPAJSONPlainSchemaDAO;
+import org.apache.syncope.core.persistence.jpa.entity.OJPAJSONEntityFactory;
 import 
org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
 import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Lazy;
 
-@ConditionalOnExpression("#{'${provisioning.quartz.delegate}' matches 
'.*PostgreSQLDelegate.*'}")
-public class PGJPAJSONPersistenceContext extends JPAJSONPersistenceContext {
+@ConditionalOnExpression("#{'${provisioning.quartz.sql}' matches 
'.*oracle.*'}")
+public class OJPAJSONPersistenceContext extends JPAJSONPersistenceContext {
 
-    @ConditionalOnMissingBean(name = "pgJPAJSONEntityFactory")
+    @ConditionalOnMissingBean(name = "oJPAJSONEntityFactory")
     @Bean
     public EntityFactory entityFactory() {
-        return new PGJPAJSONEntityFactory();
+        return new OJPAJSONEntityFactory();
     }
 
-    @ConditionalOnMissingBean(name = "pgJPAJSONAnyDAO")
+    @ConditionalOnMissingBean(name = "oJPAJSONAnyDAO")
     @Bean
     public JPAJSONAnyDAO anyDAO(final @Lazy PlainSchemaDAO plainSchemaDAO) {
-        return new PGJPAJSONAnyDAO(plainSchemaDAO);
+        return new OJPAJSONAnyDAO(plainSchemaDAO);
     }
 
-    @ConditionalOnMissingBean(name = "pgJPAJSONAnySearchDAO")
+    @ConditionalOnMissingBean(name = "oJPAJSONAnySearchDAO")
     @Bean
     public AnySearchDAO anySearchDAO(
             final @Lazy RealmDAO realmDAO,
@@ -70,7 +70,7 @@ public class PGJPAJSONPersistenceContext extends 
JPAJSONPersistenceContext {
             final AnyUtilsFactory anyUtilsFactory,
             final PlainAttrValidationManager validator) {
 
-        return new PGJPAJSONAnySearchDAO(
+        return new OJPAJSONAnySearchDAO(
                 realmDAO,
                 dynRealmDAO,
                 userDAO,
@@ -82,19 +82,19 @@ public class PGJPAJSONPersistenceContext extends 
JPAJSONPersistenceContext {
                 validator);
     }
 
-    @ConditionalOnMissingBean(name = "pgJPAJSONAuditConfDAO")
+    @ConditionalOnMissingBean(name = "oJPAJSONAuditConfDAO")
     @Bean
     public AuditConfDAO auditConfDAO() {
-        return new PGJPAJSONAuditConfDAO();
+        return new OJPAJSONAuditConfDAO();
     }
 
-    @ConditionalOnMissingBean(name = "pgJPAJSONPlainSchemaDAO")
+    @ConditionalOnMissingBean(name = "oJPAJSONPlainSchemaDAO")
     @Bean
     public PlainSchemaDAO plainSchemaDAO(
             final AnyUtilsFactory anyUtilsFactory,
             final @Lazy PlainAttrDAO plainAttrDAO,
             final @Lazy ExternalResourceDAO resourceDAO) {
 
-        return new PGJPAJSONPlainSchemaDAO(anyUtilsFactory, plainAttrDAO, 
resourceDAO);
+        return new OJPAJSONPlainSchemaDAO(anyUtilsFactory, plainAttrDAO, 
resourceDAO);
     }
 }
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
index 551b2c859d..1de2c8d9e8 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/PGJPAJSONPersistenceContext.java
@@ -42,7 +42,7 @@ import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Lazy;
 
-@ConditionalOnExpression("#{'${provisioning.quartz.delegate}' matches 
'.*PostgreSQLDelegate.*'}")
+@ConditionalOnExpression("#{'${provisioning.quartz.sql}' matches 
'.*postgres.*'}")
 public class PGJPAJSONPersistenceContext extends JPAJSONPersistenceContext {
 
     @ConditionalOnMissingBean(name = "pgJPAJSONEntityFactory")
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java
index 827729c1dc..1101148d7c 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAnyDAO.java
@@ -34,6 +34,7 @@ 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.AnyTypeKind;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.core.persistence.api.dao.DuplicateException;
 import org.apache.syncope.core.persistence.api.dao.JPAJSONAnyDAO;
@@ -58,13 +59,15 @@ abstract class AbstractJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> impleme
         this.plainSchemaDAO = plainSchemaDAO;
     }
 
-    protected abstract String queryBegin(String table);
+    protected String view(final String table) {
+        return StringUtils.containsIgnoreCase(table, AnyTypeKind.USER.name())
+                ? "user_search"
+                : StringUtils.containsIgnoreCase(table, 
AnyTypeKind.GROUP.name())
+                ? "group_search"
+                : "anyObject_search";
+    }
 
-    protected abstract String attrValueMatch(
-            AnyUtils anyUtils,
-            PlainSchema schema,
-            PlainAttrValue attrValue,
-            boolean ignoreCaseMatch);
+    protected abstract String queryBegin(String table);
 
     protected Pair<String, Boolean> schemaInfo(final AttrSchemaType 
schemaType, final boolean ignoreCaseMatch) {
         String key;
@@ -99,6 +102,20 @@ abstract class AbstractJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> impleme
         return Pair.of(key, lower);
     }
 
+    protected abstract String attrValueMatch(
+            AnyUtils anyUtils,
+            PlainSchema schema,
+            PlainAttrValue attrValue,
+            boolean ignoreCaseMatch);
+
+    protected Object getAttrValue(
+            final PlainSchema schema,
+            final PlainAttrValue attrValue,
+            final boolean ignoreCaseMatch) {
+
+        return attrValue.getValue();
+    }
+
     protected <A extends Any<?>> List<A> buildResult(final AnyUtils anyUtils, 
final List<Object> queryResult) {
         List<A> result = new ArrayList<>();
         queryResult.forEach(anyKey -> {
@@ -131,7 +148,7 @@ abstract class AbstractJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> impleme
                 queryBegin(table)
                 + "WHERE " + attrValueMatch(anyUtils, schema, attrValue, 
ignoreCaseMatch));
         query.setParameter(1, schema.getKey());
-        query.setParameter(2, attrValue.getValue());
+        query.setParameter(2, getAttrValue(schema, attrValue, 
ignoreCaseMatch));
 
         return buildResult(anyUtils, query.getResultList());
     }
@@ -167,8 +184,8 @@ abstract class AbstractJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> impleme
      * @param literals literals/tokens
      * @return split value
      */
-    private static List<String> split(final String attrValue, final 
List<String> literals) {
-        final List<String> attrValues = new ArrayList<>();
+    protected List<String> split(final String attrValue, final List<String> 
literals) {
+        List<String> attrValues = new ArrayList<>();
 
         if (literals.isEmpty()) {
             attrValues.add(attrValue);
@@ -303,7 +320,7 @@ abstract class AbstractJPAJSONAnyDAO extends 
AbstractDAO<AbstractEntity> impleme
 
                     List<Object> queryParams = new ArrayList<>();
                     queryParams.add(schema.getKey());
-                    queryParams.add(attrValues.get(i));
+                    queryParams.add(getAttrValue(schema, attrValue, 
ignoreCaseMatch));
 
                     clauses.put(bld.toString(), queryParams);
                 }
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
index c26f7ea307..06ad3692c1 100644
--- 
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
@@ -19,9 +19,7 @@
 package org.apache.syncope.core.persistence.jpa.dao;
 
 import java.util.List;
-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.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
@@ -39,12 +37,7 @@ 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 + ' ';
+        return "SELECT DISTINCT id FROM " + view(table) + ' ';
     }
 
     @Override
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
index a76fe02804..40f4c1cf91 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
@@ -86,7 +86,9 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO {
                 StringBuilder nullAttrWhere = new StringBuilder();
 
                 if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) {
-                    where.append(", (SELECT * FROM ").append(searchView.name);
+                    where.append(", (SELECT 
").append(SELECT_COLS_FROM_VIEW).append(",plainSchema,"
+                            + 
"binaryValue,booleanValue,dateValue,doubleValue,longValue,stringValue,attrUniqueValue
 "
+                            + "FROM ").append(searchView.name);
                     searchViewAddedToWhere = true;
 
                     attrs.forEach(field -> {
@@ -97,22 +99,20 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO {
                         }
                         attrWhere.append("JSON_CONTAINS(plainAttrs, 
'[{\"schema\":\"").append(field).append("\"}]')");
 
-                        nullAttrWhere.append(" UNION SELECT DISTINCT 
any_id,").append(svs.table().alias).append(".*, ").
-                                append('"').append(field).append('"').append(" 
AS plainSchema, ").
+                        nullAttrWhere.append(" UNION SELECT DISTINCT 
").append(SELECT_COLS_FROM_VIEW).append(", ").
+                                append("'").append(field).append("'").append(" 
AS plainSchema, ").
                                 append("null AS binaryValue, ").
                                 append("null AS booleanValue, ").
                                 append("null AS dateValue, ").
                                 append("null AS doubleValue, ").
                                 append("null AS longValue, ").
                                 append("null AS stringValue, ").
-                                append("null AS attrUniqueValue").
-                                append(" FROM 
").append(svs.table().name).append(' ').append(svs.table().alias).
-                                append(", ").append(svs.field().name).
-                                append(" WHERE 
any_id=").append(svs.table().alias).append(".id").
-                                append(" AND any_id NOT IN ").
-                                append("(SELECT distinct any_id FROM ").
+                                append("null AS attrUniqueValue ").
+                                append("FROM ").append(svs.field().name).
+                                append(" WHERE any_id NOT IN ").
+                                append("(SELECT DISTINCT any_id FROM ").
                                 append(svs.field().name).
-                                append(" WHERE 
").append(svs.table().alias).append(".id=any_id AND ").
+                                append(" WHERE ").
                                 append("JSON_CONTAINS(plainAttrs, 
'[{\"schema\":\"").append(field).append("\"}]'))");
                     });
                     where.append(attrWhere).append(nullAttrWhere).append(')');
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditConfDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditConfDAO.java
index 4b64c8c5f1..453fc152e1 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditConfDAO.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditConfDAO.java
@@ -25,7 +25,7 @@ import 
org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 
 public class MyJPAJSONAuditConfDAO extends AbstractJPAJSONLoggerDAO {
 
-    private static class MyMessageCriteriaBuilder extends 
JSONMessageCriteriaBuilder {
+    protected static class MyMessageCriteriaBuilder extends 
JSONMessageCriteriaBuilder {
 
         @Override
         protected String doBuild(final List<ObjectNode> containers) {
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnyDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnyDAO.java
new file mode 100644
index 0000000000..184860caa5
--- /dev/null
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnyDAO.java
@@ -0,0 +1,79 @@
+/*
+ * 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.BooleanUtils;
+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.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+
+public class OJPAJSONAnyDAO extends AbstractJPAJSONAnyDAO {
+
+    public OJPAJSONAnyDAO(final PlainSchemaDAO plainSchemaDAO) {
+        super(plainSchemaDAO);
+    }
+
+    @Override
+    protected String queryBegin(final String table) {
+        return "SELECT DISTINCT id FROM " + view(table) + ' ';
+    }
+
+    @Override
+    protected Object getAttrValue(
+            final PlainSchema schema,
+            final PlainAttrValue attrValue,
+            final boolean ignoreCaseMatch) {
+
+        return schema.getType() == AttrSchemaType.Boolean
+                ? BooleanUtils.toStringTrueFalse(attrValue.getBooleanValue())
+                : schema.getType() == AttrSchemaType.String && ignoreCaseMatch
+                ? StringUtils.lowerCase(attrValue.getStringValue())
+                : attrValue.getValue();
+    }
+
+    @Override
+    protected String attrValueMatch(
+            final AnyUtils anyUtils,
+            final PlainSchema schema,
+            final PlainAttrValue attrValue,
+            final boolean ignoreCaseMatch) {
+
+        StringBuilder query = new StringBuilder("plainSchema = ? AND ");
+
+        Pair<String, Boolean> schemaInfo = schemaInfo(schema.getType(), 
ignoreCaseMatch);
+        query.append(schemaInfo.getRight() ? "LOWER(" : "");
+
+        if (schema.isUniqueConstraint()) {
+            query.append("u").append(schemaInfo.getLeft());
+        } else {
+            query.append("JSON_VALUE(").append(schemaInfo.getLeft()).append(", 
'$[*]')");
+        }
+
+        query.append(schemaInfo.getRight() ? ")" : "").
+                append(" = ").
+                append(schemaInfo.getRight() ? "LOWER(" : "").
+                append('?').append(schemaInfo.getRight() ? ")" : "");
+
+        return query.toString();
+    }
+}
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnySearchDAO.java
similarity index 60%
copy from 
core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
copy to 
core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnySearchDAO.java
index a76fe02804..ad4aaa9434 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAnySearchDAO.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAnySearchDAO.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
 import 
org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
@@ -38,16 +39,12 @@ import 
org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.api.entity.JSONPlainAttr;
-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;
 
-public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO {
+public class OJPAJSONAnySearchDAO extends JPAAnySearchDAO {
 
-    public MyJPAJSONAnySearchDAO(
+    public OJPAJSONAnySearchDAO(
             final RealmDAO realmDAO,
             final DynRealmDAO dynRealmDAO,
             final UserDAO userDAO,
@@ -86,7 +83,10 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO {
                 StringBuilder nullAttrWhere = new StringBuilder();
 
                 if (svs.nonMandatorySchemas || obs.nonMandatorySchemas) {
-                    where.append(", (SELECT * FROM ").append(searchView.name);
+                    where.append(", (SELECT 
").append(SELECT_COLS_FROM_VIEW).append(",plainSchema,"
+                            + 
"ubinaryValue,ubooleanValue,udateValue,udoubleValue,ulongValue,ustringValue,"
+                            + 
"binaryValue,booleanValue,dateValue,doubleValue,longValue,stringValue FROM ").
+                            append(searchView.name);
                     searchViewAddedToWhere = true;
 
                     attrs.forEach(field -> {
@@ -95,25 +95,28 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO {
                         } else {
                             attrWhere.append(" OR ");
                         }
-                        attrWhere.append("JSON_CONTAINS(plainAttrs, 
'[{\"schema\":\"").append(field).append("\"}]')");
-
-                        nullAttrWhere.append(" UNION SELECT DISTINCT 
any_id,").append(svs.table().alias).append(".*, ").
-                                append('"').append(field).append('"').append(" 
AS plainSchema, ").
+                        attrWhere.append("JSON_EXISTS(plainAttrs, 
'$[*]?(@.schema == \"").append(field).append("\")')");
+
+                        nullAttrWhere.append(" UNION SELECT DISTINCT 
").append(SELECT_COLS_FROM_VIEW).append(",").
+                                append("'").append(field).append("'").append(" 
AS plainSchema, ").
+                                append("null AS ubinaryValue, ").
+                                append("null AS ubooleanValue, ").
+                                append("null AS udateValue, ").
+                                append("null AS udoubleValue, ").
+                                append("null AS ulongValue, ").
+                                append("null AS ustringValue, ").
                                 append("null AS binaryValue, ").
                                 append("null AS booleanValue, ").
                                 append("null AS dateValue, ").
                                 append("null AS doubleValue, ").
                                 append("null AS longValue, ").
-                                append("null AS stringValue, ").
-                                append("null AS attrUniqueValue").
-                                append(" FROM 
").append(svs.table().name).append(' ').append(svs.table().alias).
-                                append(", ").append(svs.field().name).
-                                append(" WHERE 
any_id=").append(svs.table().alias).append(".id").
-                                append(" AND any_id NOT IN ").
-                                append("(SELECT distinct any_id FROM ").
+                                append("null AS stringValue ").
+                                append("FROM ").append(svs.field().name).
+                                append(" WHERE any_id NOT IN ").
+                                append("(SELECT DISTINCT any_id FROM ").
                                 append(svs.field().name).
-                                append(" WHERE 
").append(svs.table().alias).append(".id=any_id AND ").
-                                append("JSON_CONTAINS(plainAttrs, 
'[{\"schema\":\"").append(field).append("\"}]'))");
+                                append(" WHERE ").
+                                append("JSON_EXISTS(plainAttrs, 
'$[*]?(@.schema == \"").append(field).append("\")'))");
                     });
                     where.append(attrWhere).append(nullAttrWhere).append(')');
                 }
@@ -141,7 +144,7 @@ public class MyJPAJSONAnySearchDAO extends JPAAnySearchDAO {
         obs.views.add(svs.field());
 
         item.select = svs.field().alias + '.'
-                + (schema.isUniqueConstraint() ? "attrUniqueValue" : 
key(schema.getType()))
+                + (schema.isUniqueConstraint() ? "u" : "") + 
key(schema.getType())
                 + " AS " + fieldName;
         item.where = "plainSchema = '" + fieldName + '\'';
         item.orderBy = fieldName + ' ' + clause.getDirection().name();
@@ -167,90 +170,80 @@ public class MyJPAJSONAnySearchDAO extends 
JPAAnySearchDAO {
             fillAttrQuery(anyUtils, query, attrValue, schema, cond, false, 
parameters, svs);
             query.append(')');
         } else {
-            if (!not && cond.getType() == AttrCond.Type.EQ) {
-                PlainAttr<?> container = anyUtils.newPlainAttr();
-                container.setSchema(schema);
-                if (attrValue instanceof PlainAttrUniqueValue) {
-                    container.setUniqueValue((PlainAttrUniqueValue) attrValue);
-                } else {
-                    ((JSONPlainAttr) container).add(attrValue);
-                }
-
-                query.append("JSON_CONTAINS(plainAttrs, '").
-                        
append(POJOHelper.serialize(List.of(container)).replace("'", "''")).
-                        append("')");
+            String key = key(schema.getType());
+
+            String value = Optional.ofNullable(attrValue.getDateValue()).
+                    map(DateTimeFormatter.ISO_OFFSET_DATE_TIME::format).
+                    orElseGet(() -> schema.getType() == AttrSchemaType.Boolean
+                    ? 
BooleanUtils.toStringTrueFalse(attrValue.getBooleanValue())
+                    : cond.getExpression());
+
+            boolean lower = (schema.getType() == AttrSchemaType.String || 
schema.getType() == AttrSchemaType.Enum)
+                    && (cond.getType() == AttrCond.Type.IEQ || cond.getType() 
== AttrCond.Type.ILIKE);
+
+            query.append("plainSchema=?").append(setParameter(parameters, 
cond.getSchema())).
+                    append(" AND ").
+                    append(lower ? "LOWER(" : "");
+            if (schema.isUniqueConstraint()) {
+                query.append("u").append(key);
             } else {
-                String key = key(schema.getType());
-
-                String value = Optional.ofNullable(attrValue.getDateValue()).
-                        map(DateTimeFormatter.ISO_OFFSET_DATE_TIME::format).
-                        orElse(cond.getExpression());
-
-                boolean lower = (schema.getType() == AttrSchemaType.String || 
schema.getType() == AttrSchemaType.Enum)
-                        && (cond.getType() == AttrCond.Type.IEQ || 
cond.getType() == AttrCond.Type.ILIKE);
-
-                query.append("plainSchema=?").append(setParameter(parameters, 
cond.getSchema())).
-                        append(" AND ").
-                        append(lower ? "LOWER(" : "").
-                        append(schema.isUniqueConstraint()
-                                ? "attrUniqueValue ->> '$." + key + '\''
-                                : key).
-                        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('=');
-                }
-
-                query.append(lower ? "LOWER(" : "").
-                        append('?').append(setParameter(parameters, value)).
-                        append(lower ? ")" : "");
+                query.append("JSON_VALUE(").append(key).append(", '$[*]')");
             }
+            query.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('=');
+            }
+
+            query.append(lower ? "LOWER(" : "").
+                    append('?').append(setParameter(parameters, value)).
+                    append(lower ? ")" : "");
         }
     }
 
@@ -276,15 +269,13 @@ public class MyJPAJSONAnySearchDAO extends 
JPAAnySearchDAO {
                 new StringBuilder("SELECT DISTINCT any_id FROM 
").append(svs.field().name).append(" WHERE ");
         switch (cond.getType()) {
             case ISNOTNULL:
-                query.append("JSON_SEARCH(plainAttrs, 'one', '").
-                        append(checked.getLeft().getKey()).
-                        append("', NULL, '$[*].schema') IS NOT NULL");
+                query.append("JSON_EXISTS(plainAttrs, '$[*]?(@.schema == \"").
+                        append(checked.getLeft().getKey()).append("\")')");
                 break;
 
             case ISNULL:
-                query.append("JSON_SEARCH(plainAttrs, 'one', '").
-                        append(checked.getLeft().getKey()).
-                        append("', NULL, '$[*].schema') IS NULL");
+                query.append("NOT JSON_EXISTS(plainAttrs, '$[*]?(@.schema == 
\"").
+                        append(checked.getLeft().getKey()).append("\")')");
                 break;
 
             default:
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAuditConfDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAuditConfDAO.java
new file mode 100644
index 0000000000..6afc9a9ed8
--- /dev/null
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONAuditConfDAO.java
@@ -0,0 +1,83 @@
+/*
+ * 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 com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class OJPAJSONAuditConfDAO extends AbstractJPAJSONLoggerDAO {
+
+    protected static class OMessageCriteriaBuilder extends 
JSONMessageCriteriaBuilder {
+
+        protected Optional<String> jsonExprItem(final JsonNode logger, final 
String field) {
+            return logger.has(field)
+                    ? Optional.of("@.logger." + field + " == \"" + 
logger.get(field).asText() + "\"")
+                    : Optional.empty();
+        }
+
+        @Override
+        protected String doBuild(final List<ObjectNode> containers) {
+            if (entityKey != null) {
+                query.append('(').
+                        
append("JSON_VALUE(").append(AUDIT_ENTRY_MESSAGE_COLUMN).
+                        append(", '$.before' RETURNING VARCHAR2(32767)) LIKE 
'%").
+                        append(entityKey).append("%' OR ").
+                        
append("JSON_VALUE(").append(AUDIT_ENTRY_MESSAGE_COLUMN).
+                        append(", '$.input' RETURNING VARCHAR2(32767)) LIKE 
'%").
+                        append(entityKey).append("%' OR ").
+                        
append("JSON_VALUE(").append(AUDIT_ENTRY_MESSAGE_COLUMN).
+                        append(", '$.output' RETURNING VARCHAR2(32767)) LIKE 
'%").
+                        append(entityKey).append("%')");
+            }
+
+            if (!containers.isEmpty()) {
+                if (entityKey != null) {
+                    query.append(" AND (");
+                }
+                query.append(containers.stream().filter(container -> 
container.has("logger")).map(container -> {
+                    JsonNode logger = container.get("logger");
+
+                    List<String> clauses = new ArrayList<>();
+                    jsonExprItem(logger, "type").ifPresent(clauses::add);
+                    jsonExprItem(logger, "category").ifPresent(clauses::add);
+                    jsonExprItem(logger, 
"subcategory").ifPresent(clauses::add);
+                    jsonExprItem(logger, "result").ifPresent(clauses::add);
+                    jsonExprItem(logger, "event").ifPresent(clauses::add);
+
+                    return "JSON_EXISTS(MESSAGE, '$[*]?(" + String.join(" && 
", clauses) + ")')";
+                }).filter(Objects::nonNull).collect(Collectors.joining(" OR 
")));
+                if (entityKey != null) {
+                    query.append(')');
+                }
+            }
+
+            return query.toString();
+        }
+    }
+
+    @Override
+    protected MessageCriteriaBuilder messageCriteriaBuilder(final String 
entityKey) {
+        return new OMessageCriteriaBuilder().entityKey(entityKey);
+    }
+}
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONPlainSchemaDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONPlainSchemaDAO.java
new file mode 100644
index 0000000000..b317243fd4
--- /dev/null
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OJPAJSONPlainSchemaDAO.java
@@ -0,0 +1,48 @@
+/*
+ * 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 javax.persistence.Query;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+
+public class OJPAJSONPlainSchemaDAO extends AbstractJPAJSONPlainSchemaDAO {
+
+    public OJPAJSONPlainSchemaDAO(
+            final AnyUtilsFactory anyUtilsFactory,
+            final PlainAttrDAO plainAttrDAO,
+            final ExternalResourceDAO resourceDAO) {
+
+        super(anyUtilsFactory, plainAttrDAO, resourceDAO);
+    }
+
+    @Override
+    public <T extends PlainAttr<?>> boolean hasAttrs(final PlainSchema schema, 
final Class<T> reference) {
+        Query query = entityManager().createNativeQuery(
+                "SELECT COUNT(id) FROM "
+                + new SearchSupport(getAnyTypeKind(reference)).field().name
+                + " WHERE plainSchema = ?");
+        query.setParameter(1, schema.getKey());
+
+        return ((Number) query.getSingleResult()).intValue() > 0;
+    }
+}
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 d356a8783c..2bc9ad4e2a 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
@@ -61,15 +61,15 @@ public class PGJPAJSONAnyDAO extends AbstractJPAJSONAnyDAO {
                     + (schemaInfo.getRight() ? "LOWER(" : "")
                     + '?'
                     + (schemaInfo.getRight() ? ")" : "");
+        }
+
+        PlainAttr<?> container = anyUtils.newPlainAttr();
+        container.setSchema(schema);
+        if (attrValue instanceof PlainAttrUniqueValue) {
+            container.setUniqueValue((PlainAttrUniqueValue) attrValue);
         } else {
-            PlainAttr<?> container = anyUtils.newPlainAttr();
-            container.setSchema(schema);
-            if (attrValue instanceof PlainAttrUniqueValue) {
-                container.setUniqueValue((PlainAttrUniqueValue) attrValue);
-            } else {
-                ((JSONPlainAttr) container).add(attrValue);
-            }
-            return "plainAttrs::jsonb @> '" + 
POJOHelper.serialize(List.of(container)).replace("'", "''") + "'::jsonb";
+            ((JSONPlainAttr) container).add(attrValue);
         }
+        return "plainAttrs::jsonb @> '" + 
POJOHelper.serialize(List.of(container)).replace("'", "''") + "'::jsonb";
     }
 }
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 88553bd260..e2c4c71f0f 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
@@ -170,11 +170,11 @@ public class PGJPAJSONAnySearchDAO extends 
JPAAnySearchDAO {
                 try {
                     switch (schema.getType()) {
                         case Long:
-                            Long.parseLong(value);
+                            Long.valueOf(value);
                             break;
 
                         case Double:
-                            Double.parseDouble(value);
+                            Double.valueOf(value);
                             break;
 
                         case Boolean:
@@ -193,7 +193,6 @@ public class PGJPAJSONAnySearchDAO extends JPAAnySearchDAO {
             }
 
             switch (cond.getType()) {
-
                 case ISNULL:
                     // shouldn't occour: processed before
                     break;
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditConfDAO.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditConfDAO.java
index 4e9acf5d11..c797b7d052 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditConfDAO.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditConfDAO.java
@@ -26,7 +26,7 @@ import 
org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 
 public class PGJPAJSONAuditConfDAO extends AbstractJPAJSONLoggerDAO {
 
-    private static class PGMessageCriteriaBuilder extends 
JSONMessageCriteriaBuilder {
+    protected static class PGMessageCriteriaBuilder extends 
JSONMessageCriteriaBuilder {
 
         @Override
         protected String doBuild(final List<ObjectNode> containers) {
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/OJPAJSONEntityFactory.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/OJPAJSONEntityFactory.java
new file mode 100644
index 0000000000..0b35c11932
--- /dev/null
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/OJPAJSONEntityFactory.java
@@ -0,0 +1,30 @@
+/*
+ * 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.jpa.dao.OJPAJSONAnySearchDAO;
+
+public class OJPAJSONEntityFactory extends JPAJSONEntityFactory {
+
+    @Override
+    public Class<? extends AnySearchDAO> anySearchDAOClass() {
+        return OJPAJSONAnySearchDAO.class;
+    }
+}
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAJSONAnyObject.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAJSONAnyObject.java
index 5fc6eeb596..3415c44414 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAJSONAnyObject.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAJSONAnyObject.java
@@ -25,7 +25,6 @@ import java.util.Optional;
 import java.util.stream.Collectors;
 import javax.persistence.Entity;
 import javax.persistence.EntityListeners;
-import javax.persistence.Lob;
 import javax.persistence.Table;
 import javax.persistence.Transient;
 import org.apache.syncope.core.persistence.api.entity.JSONAttributable;
@@ -44,7 +43,6 @@ public class JPAJSONAnyObject extends JPAAnyObject implements 
JSONAttributable<A
 
     private static final long serialVersionUID = -8543654943709531885L;
 
-    @Lob
     private String plainAttrs;
 
     @Transient
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAJSONGroup.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAJSONGroup.java
index 1366cb94e5..0ba77ff612 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAJSONGroup.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAJSONGroup.java
@@ -22,7 +22,6 @@ import java.util.ArrayList;
 import java.util.List;
 import javax.persistence.Entity;
 import javax.persistence.EntityListeners;
-import javax.persistence.Lob;
 import javax.persistence.Table;
 import javax.persistence.Transient;
 import org.apache.syncope.core.persistence.api.entity.JSONAttributable;
@@ -39,7 +38,6 @@ public class JPAJSONGroup extends JPAGroup implements 
JSONAttributable<Group>, G
 
     private static final long serialVersionUID = -8543654943709531885L;
 
-    @Lob
     private String plainAttrs;
 
     @Transient
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONLinkedAccount.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONLinkedAccount.java
index 3864fb9eb1..ef5c3617ce 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONLinkedAccount.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONLinkedAccount.java
@@ -24,7 +24,6 @@ import java.util.Optional;
 import java.util.stream.Collectors;
 import javax.persistence.Entity;
 import javax.persistence.EntityListeners;
-import javax.persistence.Lob;
 import javax.persistence.Table;
 import javax.persistence.Transient;
 import org.apache.syncope.core.persistence.api.entity.JSONAttributable;
@@ -42,7 +41,6 @@ public class JPAJSONLinkedAccount extends JPALinkedAccount 
implements JSONAttrib
 
     private static final long serialVersionUID = 7495284980208765032L;
 
-    @Lob
     private String plainAttrs;
 
     @Transient
diff --git 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONUser.java
 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONUser.java
index 4eb99cfbbb..a145bab4d3 100644
--- 
a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONUser.java
+++ 
b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAJSONUser.java
@@ -26,7 +26,6 @@ import java.util.stream.Collectors;
 import javax.persistence.CascadeType;
 import javax.persistence.Entity;
 import javax.persistence.EntityListeners;
-import javax.persistence.Lob;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.persistence.Transient;
@@ -48,7 +47,6 @@ public class JPAJSONUser extends JPAUser implements 
JSONAttributable<User>, User
 
     private static final long serialVersionUID = -8543654943709531885L;
 
-    @Lob
     private String plainAttrs;
 
     @Transient
diff --git 
a/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-ojson.xml 
b/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-ojson.xml
new file mode 100644
index 0000000000..427948f540
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/resources/META-INF/spring-orm-ojson.xml
@@ -0,0 +1,136 @@
+<?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="CLOB CHECK (plainAttrs IS JSON)"/>
+        <lob/>
+      </basic>
+    </attributes>
+  </entity>
+    
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.group.JPAJSONGroup">
+    <attributes>
+      <basic name="plainAttrs">
+        <column column-definition="CLOB CHECK (plainAttrs IS JSON)"/>
+        <lob/>
+      </basic>
+    </attributes>
+  </entity>
+
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONUser">
+    <attributes>
+      <basic name="plainAttrs">
+        <column column-definition="CLOB CHECK (plainAttrs IS JSON)"/>
+        <lob/>
+      </basic>
+    </attributes>
+  </entity>
+
+  <entity 
class="org.apache.syncope.core.persistence.jpa.entity.user.JPAJSONLinkedAccount">
+    <attributes>
+      <basic name="plainAttrs">
+        <column column-definition="CLOB CHECK (plainAttrs IS 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/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories 
b/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories
index c43e216ec2..3eea832444 100644
--- a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories
+++ b/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories
@@ -17,4 +17,5 @@
 
 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
   org.apache.syncope.core.persistence.jpa.PGJPAJSONPersistenceContext,\
-  org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext
+  org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext,\
+  org.apache.syncope.core.persistence.jpa.OJPAJSONPersistenceContext
diff --git a/core/persistence-jpa-json/src/main/resources/audit/audit_ojson.sql 
b/core/persistence-jpa-json/src/main/resources/audit/audit_ojson.sql
new file mode 100644
index 0000000000..d4e39395f5
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/resources/audit/audit_ojson.sql
@@ -0,0 +1,24 @@
+-- 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.
+
+CREATE TABLE AuditEntry (
+  EVENT_DATE TIMESTAMP,
+  LOGGER_LEVEL VARCHAR(255) NOT NULL,
+  LOGGER VARCHAR(255) NOT NULL,
+  MESSAGE CLOB CHECK (MESSAGE IS JSON) NOT NULL,
+  THROWABLE CLOB
+);
diff --git 
a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories 
b/core/persistence-jpa-json/src/main/resources/core-ojson.properties
similarity index 50%
copy from core/persistence-jpa-json/src/main/resources/META-INF/spring.factories
copy to core/persistence-jpa-json/src/main/resources/core-ojson.properties
index c43e216ec2..aecedde8e5 100644
--- a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories
+++ b/core/persistence-jpa-json/src/main/resources/core-ojson.properties
@@ -15,6 +15,20 @@
 # specific language governing permissions and limitations
 # under the License.
 
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-  org.apache.syncope.core.persistence.jpa.PGJPAJSONPersistenceContext,\
-  org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext
+persistence.indexesXML=classpath:ojson/indexes.xml
+persistence.viewsXML=classpath:ojson/views.xml
+
+persistence.domain[0].key=Master
+persistence.domain[0].jdbcDriver=oracle.jdbc.OracleDriver
+persistence.domain[0].jdbcURL=jdbc:oracle:thin:@localhost:1521/XEPDB1
+persistence.domain[0].schema=SYNCOPE
+persistence.domain[0].dbUsername=syncope
+persistence.domain[0].dbPassword=syncope
+persistence.domain[0].databasePlatform=org.apache.openjpa.jdbc.sql.OracleDictionary
+persistence.domain[0].orm=META-INF/spring-orm-ojson.xml
+persistence.domain[0].auditSql=audit_ojson.sql
+persistence.domain[0].poolMaxActive=10
+persistence.domain[0].poolMinIdle=2
+
+provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
+provisioning.quartz.sql=tables_oracle.sql
diff --git a/core/persistence-jpa-json/src/main/resources/myjson/views.xml 
b/core/persistence-jpa-json/src/main/resources/myjson/views.xml
index 1744dc06d9..7c351412a7 100644
--- a/core/persistence-jpa-json/src/main/resources/myjson/views.xml
+++ b/core/persistence-jpa-json/src/main/resources/myjson/views.xml
@@ -51,7 +51,7 @@ under the License.
     CREATE VIEW user_search AS
 
     SELECT u.id as any_id, u.*, attrs.*
-    FROM SyncopeUser u, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' 
COLUMNS (
+    FROM SyncopeUser u LEFT OUTER JOIN JSON_TABLE(COALESCE(plainAttrs, 
'[{}]'), '$[*]' COLUMNS (
     plainSchema VARCHAR(255) PATH '$.schema',
     NESTED PATH '$.values[*]' COLUMNS (
     binaryValue LONGBLOB PATH '$.binaryValue',
@@ -61,7 +61,7 @@ under the License.
     longValue BIGINT(20) PATH '$.longValue',
     stringValue VARCHAR(255) PATH '$.stringValue'),
     attrUniqueValue JSON PATH '$.uniqueValue')
-    ) AS attrs
+    ) AS attrs ON 1=1
   </entry>
   <entry key="user_search_urelationship">
     CREATE VIEW user_search_urelationship AS
@@ -121,7 +121,7 @@ under the License.
     CREATE VIEW anyObject_search AS
  
     SELECT a.id as any_id, a.*, attrs.*
-    FROM AnyObject a, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' COLUMNS (
+    FROM AnyObject a LEFT OUTER JOIN JSON_TABLE(COALESCE(plainAttrs, '[{}]'), 
'$[*]' COLUMNS (
     plainSchema VARCHAR(255) PATH '$.schema',
     NESTED PATH '$.values[*]' COLUMNS (
     binaryValue LONGBLOB PATH '$.binaryValue',
@@ -131,7 +131,7 @@ under the License.
     longValue BIGINT(20) PATH '$.longValue',
     stringValue VARCHAR(255) PATH '$.stringValue'),
     attrUniqueValue JSON PATH '$.uniqueValue')
-    ) AS attrs
+    ) AS attrs ON 1=1
   </entry>
   <entry key="anyObject_search_arelationship">
     CREATE VIEW anyObject_search_arelationship AS
@@ -171,7 +171,7 @@ under the License.
     CREATE VIEW group_search AS
  
     SELECT g.id as any_id, g.*, attrs.*
-    FROM SyncopeGroup g, JSON_TABLE(COALESCE(plainAttrs, '[{}]'), '$[*]' 
COLUMNS (
+    FROM SyncopeGroup g LEFT OUTER JOIN JSON_TABLE(COALESCE(plainAttrs, 
'[{}]'), '$[*]' COLUMNS (
     plainSchema VARCHAR(255) PATH '$.schema',
     NESTED PATH '$.values[*]' COLUMNS (
     binaryValue LONGBLOB PATH '$.binaryValue',
@@ -181,7 +181,7 @@ under the License.
     longValue BIGINT(20) PATH '$.longValue',
     stringValue VARCHAR(255) PATH '$.stringValue'),
     attrUniqueValue JSON PATH '$.uniqueValue')
-    ) AS attrs
+    ) AS attrs ON 1=1
   </entry>
   <entry key="group_search_auxClass">
     CREATE VIEW group_search_auxClass AS
diff --git a/core/persistence-jpa-json/src/main/resources/ojson/indexes.xml 
b/core/persistence-jpa-json/src/main/resources/ojson/indexes.xml
new file mode 100644
index 0000000000..4d203d762b
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/resources/ojson/indexes.xml
@@ -0,0 +1,59 @@
+<?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>
+
+  <!-- The following indexes require Oracle TEXT to be installed on the given 
Oracle database:
+       
http://dbaflavours.blogspot.com/2012/09/ora-29833-indextype-does-not-exist_18.html
 -->
+  <entry key="AnyObject_plainAttrs_Index">CREATE SEARCH INDEX 
AnyObject_plainAttrs_Index ON AnyObject(plainAttrs) FOR JSON</entry>  
+  <entry key="SyncopeGroup_plainAttrs_Index">CREATE SEARCH INDEX 
SyncopeGroup_plainAttrs_Index ON SyncopeGroup(plainAttrs) FOR JSON</entry>
+  <entry key="SyncopeUser_plainAttrs_Index">CREATE SEARCH INDEX 
SyncopeUser_plainAttrs_Index ON SyncopeUser(plainAttrs) FOR JSON</entry>
+  <entry key="LinkedAccount_plainAttrs_Index">CREATE SEARCH INDEX 
LinkedAccount_plainAttrs_Index ON LinkedAccount(plainAttrs) FOR JSON</entry>
+
+  <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="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="Task_executedIndex">CREATE INDEX Task_executedIndex ON 
NotificationTask(executed)</entry>
+  <entry key="TaskExec1_TaskIdIndex">CREATE INDEX TaskExec1_TaskIdIndex ON 
PropagationTaskExec(task_id)</entry>
+  <entry key="TaskExec2_TaskIdIndex">CREATE INDEX TaskExec2_TaskIdIndex ON 
PullTaskExec(task_id)</entry>
+  <entry key="TaskExec3_TaskIdIndex">CREATE INDEX TaskExec3_TaskIdIndex ON 
PushTaskExec(task_id)</entry>
+  <entry key="TaskExec4_TaskIdIndex">CREATE INDEX TaskExec4_TaskIdIndex ON 
NotificationTaskExec(task_id)</entry>
+  <entry key="TaskExec5_TaskIdIndex">CREATE INDEX TaskExec5_TaskIdIndex ON 
SchedTaskExec(task_id)</entry>
+  <entry key="ATPullTask_PullTaskIndex">CREATE INDEX ATPullTask_PullTaskIndex 
ON AnyTemplatePullTask(pullTask_id)</entry>
+</properties>
diff --git a/core/persistence-jpa-json/src/main/resources/myjson/views.xml 
b/core/persistence-jpa-json/src/main/resources/ojson/views.xml
similarity index 68%
copy from core/persistence-jpa-json/src/main/resources/myjson/views.xml
copy to core/persistence-jpa-json/src/main/resources/ojson/views.xml
index 1744dc06d9..0bc2c43286 100644
--- a/core/persistence-jpa-json/src/main/resources/myjson/views.xml
+++ b/core/persistence-jpa-json/src/main/resources/ojson/views.xml
@@ -51,17 +51,23 @@ under the License.
     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 VARCHAR(32) PATH '$.dateValue',
-    doubleValue DOUBLE PATH '$.doubleValue',
-    longValue BIGINT(20) PATH '$.longValue',
-    stringValue VARCHAR(255) PATH '$.stringValue'),
-    attrUniqueValue JSON PATH '$.uniqueValue')
-    ) AS attrs
+    FROM SyncopeUser u LEFT OUTER JOIN JSON_TABLE(u.plainAttrs, '$[*]' COLUMNS 
(
+    plainSchema PATH '$.schema', 
+    NESTED PATH '$.uniqueValue' COLUMNS(
+    ubinaryValue PATH '$.binaryValue', 
+    ubooleanValue PATH '$.booleanValue',
+    udateValue PATH '$.dateValue',
+    ulongValue PATH '$.longValue',
+    udoubleValue PATH '$.doubleValue',
+    ustringValue PATH '$.stringValue'),
+    NESTED PATH '$.values[*]' COLUMNS(
+    binaryValue FORMAT JSON WITH WRAPPER PATH '$.binaryValue',
+    booleanValue FORMAT JSON WITH WRAPPER PATH '$.booleanValue',
+    dateValue FORMAT JSON WITH WRAPPER PATH '$.dateValue',
+    longValue FORMAT JSON WITH WRAPPER PATH '$.longValue',
+    doubleValue FORMAT JSON WITH WRAPPER PATH '$.doubleValue',
+    stringValue FORMAT JSON WITH WRAPPER PATH '$.stringValue')
+    )) AS attrs ON 1=1
   </entry>
   <entry key="user_search_urelationship">
     CREATE VIEW user_search_urelationship AS
@@ -121,17 +127,23 @@ under the License.
     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 VARCHAR(32) PATH '$.dateValue',
-    doubleValue DOUBLE PATH '$.doubleValue',
-    longValue BIGINT(20) PATH '$.longValue',
-    stringValue VARCHAR(255) PATH '$.stringValue'),
-    attrUniqueValue JSON PATH '$.uniqueValue')
-    ) AS attrs
+    FROM AnyObject a LEFT OUTER JOIN JSON_TABLE(a.plainAttrs, '$[*]' COLUMNS (
+    plainSchema PATH '$.schema', 
+    NESTED PATH '$.uniqueValue' COLUMNS(
+    ubinaryValue PATH '$.binaryValue', 
+    ubooleanValue PATH '$.booleanValue',
+    udateValue PATH '$.dateValue',
+    ulongValue PATH '$.longValue',
+    udoubleValue PATH '$.doubleValue',
+    ustringValue PATH '$.stringValue'),
+    NESTED PATH '$.values[*]' COLUMNS(
+    binaryValue FORMAT JSON WITH WRAPPER PATH '$.binaryValue',
+    booleanValue FORMAT JSON WITH WRAPPER PATH '$.booleanValue',
+    dateValue FORMAT JSON WITH WRAPPER PATH '$.dateValue',
+    longValue FORMAT JSON WITH WRAPPER PATH '$.longValue',
+    doubleValue FORMAT JSON WITH WRAPPER PATH '$.doubleValue',
+    stringValue FORMAT JSON WITH WRAPPER PATH '$.stringValue')
+    )) AS attrs ON 1=1
   </entry>
   <entry key="anyObject_search_arelationship">
     CREATE VIEW anyObject_search_arelationship AS
@@ -171,17 +183,23 @@ under the License.
     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 VARCHAR(32) PATH '$.dateValue',
-    doubleValue DOUBLE PATH '$.doubleValue',
-    longValue BIGINT(20) PATH '$.longValue',
-    stringValue VARCHAR(255) PATH '$.stringValue'),
-    attrUniqueValue JSON PATH '$.uniqueValue')
-    ) AS attrs
+    FROM SyncopeGroup g LEFT OUTER JOIN JSON_TABLE(g.plainAttrs, '$[*]' 
COLUMNS (
+    plainSchema PATH '$.schema', 
+    NESTED PATH '$.uniqueValue' COLUMNS(
+    ubinaryValue PATH '$.binaryValue', 
+    ubooleanValue PATH '$.booleanValue',
+    udateValue PATH '$.dateValue',
+    ulongValue PATH '$.longValue',
+    udoubleValue PATH '$.doubleValue',
+    ustringValue PATH '$.stringValue'),
+    NESTED PATH '$.values[*]' COLUMNS(
+    binaryValue FORMAT JSON WITH WRAPPER PATH '$.binaryValue',
+    booleanValue FORMAT JSON WITH WRAPPER PATH '$.booleanValue',
+    dateValue FORMAT JSON WITH WRAPPER PATH '$.dateValue',
+    longValue FORMAT JSON WITH WRAPPER PATH '$.longValue',
+    doubleValue FORMAT JSON WITH WRAPPER PATH '$.doubleValue',
+    stringValue FORMAT JSON WITH WRAPPER PATH '$.stringValue')
+    )) AS attrs ON 1=1
   </entry>
   <entry key="group_search_auxClass">
     CREATE VIEW group_search_auxClass AS
diff --git 
a/core/persistence-jpa-json/src/main/resources/persistence-enhance.xml 
b/core/persistence-jpa-json/src/main/resources/persistence-enhance.xml
index 718f22953e..0c6e795b93 100644
--- a/core/persistence-jpa-json/src/main/resources/persistence-enhance.xml
+++ b/core/persistence-jpa-json/src/main/resources/persistence-enhance.xml
@@ -24,7 +24,7 @@ under the License.
              version="2.0">
   
   <persistence-unit name="Master">
-    <mapping-file>META-INF/spring-orm-pgjsonb.xml</mapping-file>
+    <mapping-file>META-INF/spring-orm-${orm}.xml</mapping-file>
     <validation-mode>NONE</validation-mode>
   </persistence-unit>
   
diff --git 
a/core/persistence-jpa-json/src/test/java/org/apache/syncope/core/persistence/jpa/JPAJSONTestContextCustomizer.java
 
b/core/persistence-jpa-json/src/test/java/org/apache/syncope/core/persistence/jpa/JPAJSONTestContextCustomizer.java
index 8700e318bc..8a73334730 100644
--- 
a/core/persistence-jpa-json/src/test/java/org/apache/syncope/core/persistence/jpa/JPAJSONTestContextCustomizer.java
+++ 
b/core/persistence-jpa-json/src/test/java/org/apache/syncope/core/persistence/jpa/JPAJSONTestContextCustomizer.java
@@ -22,7 +22,6 @@ import 
org.springframework.beans.factory.support.BeanDefinitionRegistry;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
-import org.springframework.context.support.AbstractApplicationContext;
 import org.springframework.test.context.ContextCustomizer;
 import org.springframework.test.context.MergedContextConfiguration;
 import org.springframework.test.context.support.TestPropertySourceUtils;
@@ -33,26 +32,39 @@ public class JPAJSONTestContextCustomizer implements 
ContextCustomizer {
         if (ctx instanceof BeanDefinitionRegistry) {
             return (BeanDefinitionRegistry) ctx;
         }
-        if (ctx instanceof AbstractApplicationContext) {
-            return (BeanDefinitionRegistry) ((AbstractApplicationContext) 
ctx).getBeanFactory();
+        if (ctx instanceof ConfigurableApplicationContext) {
+            return (BeanDefinitionRegistry) ((ConfigurableApplicationContext) 
ctx).getBeanFactory();
         }
         throw new IllegalStateException("Could not locate 
BeanDefinitionRegistry");
     }
 
     @Override
     public void customizeContext(final ConfigurableApplicationContext ctx, 
final MergedContextConfiguration cfg) {
-        if ("pgjsonb".equals(System.getProperty("profileId"))) {
-            TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
-                    ctx,
-                    
"provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
-        } else if ("myjson".equals(System.getProperty("profileId"))) {
-            TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
-                    ctx,
-                    
"provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
+        switch (System.getProperty("profileId")) {
+            case "pgjsonb":
+                TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
+                        ctx,
+                        "provisioning.quartz.sql=tables_postgres.sql");
+                break;
+
+            case "myjson":
+                TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
+                        ctx,
+                        "provisioning.quartz.sql=tables_mysql_innodb.sql");
+                break;
+
+            case "ojson":
+                TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
+                        ctx,
+                        "provisioning.quartz.sql=tables_oracle.sql");
+                break;
+
+            default:
         }
 
         AnnotatedBeanDefinitionReader reader = new 
AnnotatedBeanDefinitionReader(getBeanDefinitionRegistry(ctx));
         reader.registerBean(PGJPAJSONPersistenceContext.class, 
"PGJPAJSONPersistenceContext");
         reader.registerBean(MyJPAJSONPersistenceContext.class, 
"MyJPAJSONPersistenceContext");
+        reader.registerBean(OJPAJSONPersistenceContext.class, 
"OJPAJSONPersistenceContext");
     }
 }
diff --git 
a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories 
b/core/persistence-jpa-json/src/test/resources/core-ojson-test.properties
similarity index 70%
copy from core/persistence-jpa-json/src/main/resources/META-INF/spring.factories
copy to core/persistence-jpa-json/src/test/resources/core-ojson-test.properties
index c43e216ec2..972a4bfd52 100644
--- a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories
+++ b/core/persistence-jpa-json/src/test/resources/core-ojson-test.properties
@@ -15,6 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-  org.apache.syncope.core.persistence.jpa.PGJPAJSONPersistenceContext,\
-  org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext
+security.adminUser=${adminUser}
+security.anonymousUser=${anonymousUser}
+security.jwsKey=${jwsKey}
+security.secretKey=${secretKey}
+
+persistence.domain[0].jdbcURL=jdbc:oracle:thin:@${DB_CONTAINER_IP}:1521/XEPDB1
+#persistence.domain[0].jdbcURL=jdbc:oracle:thin:@192.168.0.176:1521/orcl
+
+provisioning.connIdLocation=${connid.location}
diff --git 
a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml 
b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
index bed2f381a2..942bf5e987 100644
--- a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
@@ -273,8 +273,9 @@ under the License.
   <AnyObject id="9e1d130c-d6a3-48b1-98b3-182477ed0688" name="Epson Stylus 
Color"
              realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c" type_id="PRINTER"
              creator="admin" lastModifier="admin" 
-             creationDate="2021-04-15 12:45:00" lastChangeDate="2010-10-20 
11:00:00"/>
-  
+             creationDate="2021-04-15 12:45:00" lastChangeDate="2010-10-20 
11:00:00"
+             plainAttrs="[]"/>
+
   <ARelationship id="11a0ec66-b59b-428a-af3d-f856950ff1c5" 
type_id="neighborhood"
                  left_anyObject_id="fc6dbc3a-6c07-4965-8781-921e7401a4a5"
                  right_anyObject_id="8559d14d-58c2-46eb-a2d4-a7d35161e8f8"/>
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 3328a8f9e0..023b370876 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
@@ -72,6 +72,11 @@ import 
org.apache.syncope.core.provisioning.api.utils.RealmUtils;
  */
 public class JPAAnySearchDAO extends AbstractAnySearchDAO {
 
+    protected static final String SELECT_COLS_FROM_VIEW =
+            "any_id,creationContext,creationDate,creator,lastChangeContext,"
+            + 
"lastChangeDate,lastModifier,status,changePwdDate,cipherAlgorithm,failedLogins,"
+            + "lastLoginDate,mustChangePassword,suspended,username";
+
     public JPAAnySearchDAO(
             final RealmDAO realmDAO,
             final DynRealmDAO dynRealmDAO,
diff --git 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
index f0463a8d31..bb9a7919cd 100644
--- 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
+++ 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
@@ -171,10 +171,10 @@ public class UserTest extends AbstractTest {
 
     @Test
     public void findByPlainAttrBooleanValue() {
-        final UPlainAttrValue coolValue = 
entityFactory.newEntity(UPlainAttrValue.class);
+        UPlainAttrValue coolValue = 
entityFactory.newEntity(UPlainAttrValue.class);
         coolValue.setBooleanValue(true);
 
-        final List<User> list = 
userDAO.findByPlainAttrValue(plainSchemaDAO.find("cool"), coolValue, false);
+        List<User> list = 
userDAO.findByPlainAttrValue(plainSchemaDAO.find("cool"), coolValue, false);
         assertEquals(1, list.size());
     }
 
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index f67e2b6eb4..571a6f2f93 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -1133,17 +1133,23 @@ under the License.
     </profile>
 
     <profile>
-      <id>oracle-it</id>
+      <id>ojson-it</id>
 
       <properties>
         <jdbcdriver.groupId>com.oracle.database.jdbc</jdbcdriver.groupId>
         <jdbcdriver.artifactId>ojdbc11</jdbcdriver.artifactId>
         <cargo.deployable.ping.timeout>120000</cargo.deployable.ping.timeout>
 
-        <spring.profiles.active>embedded,oracle</spring.profiles.active>
+        <spring.profiles.active>embedded,ojson</spring.profiles.active>
       </properties>
 
       <dependencies>
+        <dependency>
+          <groupId>org.apache.syncope.core</groupId>
+          <artifactId>syncope-core-persistence-jpa-json</artifactId>
+          <version>${project.version}</version>
+        </dependency>
+
         <dependency>
           <groupId>com.oracle.database.jdbc</groupId>
           <artifactId>ojdbc11</artifactId>
@@ -1174,7 +1180,7 @@ under the License.
               <images>
                 <image>
                   <alias>oracle</alias>
-                  <name>gvenzl/oracle-xe:18-slim</name>
+                  <name>gvenzl/oracle-xe:21-slim</name>
                   <run>
                     <env>
                       <ORACLE_PASSWORD>password</ORACLE_PASSWORD>
@@ -1231,10 +1237,110 @@ under the License.
 
         <resources>
           <resource>
-            <directory>src/main/resources/oracle</directory>
+            
<directory>${basedir}/../../core/persistence-jpa-json/src/test/resources/domains</directory>
+            <targetPath>${project.build.outputDirectory}/domains</targetPath>
             <filtering>true</filtering>
           </resource>
         </resources>
+      </build>      
+    </profile>
+
+    <profile>
+      <id>oracle-it</id>
+
+      <properties>
+        <jdbcdriver.groupId>com.oracle.database.jdbc</jdbcdriver.groupId>
+        <jdbcdriver.artifactId>ojdbc11</jdbcdriver.artifactId>
+        <cargo.deployable.ping.timeout>120000</cargo.deployable.ping.timeout>
+
+        <spring.profiles.active>embedded,oracle</spring.profiles.active>
+      </properties>
+
+      <dependencies>
+        <dependency>
+          <groupId>com.oracle.database.jdbc</groupId>
+          <artifactId>ojdbc11</artifactId>
+          <version>${jdbc.oracle.version}</version>
+          <scope>test</scope>
+        </dependency>
+      </dependencies>
+
+      <build>
+        <defaultGoal>clean verify</defaultGoal>
+
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-failsafe-plugin</artifactId>
+            <inherited>true</inherited>
+            <configuration>
+              <includes>
+                <include>**/org/apache/syncope/fit/core/*ITCase.java</include>
+              </includes>
+            </configuration>
+          </plugin>
+
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+            <configuration>
+              <images>
+                <image>
+                  <alias>oracle</alias>
+                  <name>gvenzl/oracle-xe:21-slim</name>
+                  <run>
+                    <env>
+                      <ORACLE_PASSWORD>password</ORACLE_PASSWORD>
+                      <APP_USER>syncope</APP_USER>
+                      <APP_USER_PASSWORD>syncope</APP_USER_PASSWORD>
+                    </env>
+                    <wait>
+                      <log>DATABASE IS READY TO USE</log>
+                      <time>120000</time>
+                    </wait>
+                  </run>
+                </image>
+              </images>
+            </configuration>
+            <executions>
+              <execution>
+                <id>buid-oracle</id>
+                <phase>initialize</phase>
+                <goals>
+                  <goal>build</goal>
+                </goals>
+              </execution>
+              <execution>
+                <id>start-oracle</id>
+                <phase>pre-integration-test</phase>
+                <goals>
+                  <goal>start</goal>
+                </goals>
+              </execution>
+              <execution>
+                <id>stop-oracle</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-maven3-plugin</artifactId>
+            <inherited>true</inherited>
+            <configuration>
+              <container>
+                <systemProperties>
+                  
<DB_CONTAINER_IP>${docker.container.oracle.ip}</DB_CONTAINER_IP>
+                </systemProperties>
+              </container>
+            </configuration>
+          </plugin>
+        </plugins>
       </build>
     </profile>
 
diff --git 
a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
 
b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
index 3e09473641..a63671f3f9 100644
--- 
a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
+++ 
b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
@@ -41,6 +41,7 @@ import 
org.apache.syncope.common.lib.report.StaticReportletConf;
 import org.apache.syncope.common.lib.report.UserReportletConf;
 import org.apache.syncope.common.lib.types.IdMImplementationType;
 import org.apache.syncope.common.lib.types.IdRepoImplementationType;
+import org.apache.syncope.core.logic.job.MacroRunJobDelegate;
 import org.apache.syncope.core.persistence.api.ImplementationLookup;
 import org.apache.syncope.core.persistence.api.dao.AccountRule;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
@@ -54,6 +55,8 @@ import 
org.apache.syncope.core.persistence.jpa.attrvalue.validation.BinaryValida
 import 
org.apache.syncope.core.persistence.jpa.attrvalue.validation.EmailAddressValidator;
 import org.apache.syncope.core.persistence.jpa.dao.DefaultPullCorrelationRule;
 import org.apache.syncope.core.persistence.jpa.dao.DefaultPushCorrelationRule;
+import org.apache.syncope.core.provisioning.java.job.ExpiredAccessTokenCleanup;
+import org.apache.syncope.core.provisioning.java.job.ExpiredBatchCleanup;
 import org.apache.syncope.core.provisioning.java.job.report.AuditReportlet;
 import org.apache.syncope.core.provisioning.java.job.report.GroupReportlet;
 import 
org.apache.syncope.core.provisioning.java.job.report.ReconciliationReportlet;
@@ -68,6 +71,8 @@ import 
org.apache.syncope.core.provisioning.java.pushpull.DBPasswordPullActions;
 import 
org.apache.syncope.core.provisioning.java.pushpull.DefaultProvisionSorter;
 import 
org.apache.syncope.core.provisioning.java.pushpull.LDAPMembershipPullActions;
 import 
org.apache.syncope.core.provisioning.java.pushpull.LDAPPasswordPullActions;
+import org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate;
+import org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate;
 import org.apache.syncope.core.spring.policy.DefaultAccountRule;
 import org.apache.syncope.core.spring.policy.DefaultPasswordRule;
 import org.apache.syncope.core.spring.policy.HaveIBeenPwnedPasswordRule;
@@ -160,6 +165,11 @@ public class ITImplementationLookup implements 
ImplementationLookup {
             put(IdRepoImplementationType.ITEM_TRANSFORMER, classNames);
 
             classNames = new HashSet<>();
+            classNames.add(MacroRunJobDelegate.class.getName());
+            classNames.add(PullJobDelegate.class.getName());
+            classNames.add(PushJobDelegate.class.getName());
+            classNames.add(ExpiredAccessTokenCleanup.class.getName());
+            classNames.add(ExpiredBatchCleanup.class.getName());
             classNames.add(TestSampleJobDelegate.class.getName());
             put(IdRepoImplementationType.TASKJOB_DELEGATE, classNames);
 
diff --git 
a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories 
b/fit/core-reference/src/main/resources/core-ojson.properties
similarity index 50%
copy from core/persistence-jpa-json/src/main/resources/META-INF/spring.factories
copy to fit/core-reference/src/main/resources/core-ojson.properties
index c43e216ec2..e621a63a37 100644
--- a/core/persistence-jpa-json/src/main/resources/META-INF/spring.factories
+++ b/fit/core-reference/src/main/resources/core-ojson.properties
@@ -15,6 +15,20 @@
 # specific language governing permissions and limitations
 # under the License.
 
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-  org.apache.syncope.core.persistence.jpa.PGJPAJSONPersistenceContext,\
-  org.apache.syncope.core.persistence.jpa.MyJPAJSONPersistenceContext
+persistence.indexesXML=classpath:ojson/indexes.xml
+persistence.viewsXML=classpath:ojson/views.xml
+
+persistence.domain[0].key=Master
+persistence.domain[0].jdbcDriver=oracle.jdbc.OracleDriver
+persistence.domain[0].jdbcURL=jdbc:oracle:thin:@${DB_CONTAINER_IP}:1521/XEPDB1
+persistence.domain[0].schema=SYNCOPE
+persistence.domain[0].dbUsername=syncope
+persistence.domain[0].dbPassword=syncope
+persistence.domain[0].databasePlatform=org.apache.openjpa.jdbc.sql.OracleDictionary
+persistence.domain[0].orm=META-INF/spring-orm-ojson.xml
+persistence.domain[0].auditSql=audit_ojson.sql
+persistence.domain[0].poolMaxActive=10
+persistence.domain[0].poolMinIdle=2
+
+provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
+provisioning.quartz.sql=tables_oracle.sql
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
index 5a6c17d32b..c7ddf8fca2 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
@@ -216,28 +216,28 @@ public class AnyObjectITCase extends AbstractITCase {
     @Test
     public void issueSYNCOPE1472() {
         // 1. assign resource-db-scripted again to Canon MF 8030cn and update 
twice
-        AnyObjectUR anyObjectPatch = new AnyObjectUR();
-        anyObjectPatch.setKey("8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
-        anyObjectPatch.getResources().add(new 
StringPatchItem.Builder().value(RESOURCE_NAME_DBSCRIPTED).build());
-        anyObjectPatch.getAuxClasses().add(new 
StringPatchItem.Builder().value("csv").build());
+        AnyObjectUR updateReq = new AnyObjectUR();
+        updateReq.setKey("8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
+        updateReq.getResources().add(new 
StringPatchItem.Builder().value(RESOURCE_NAME_DBSCRIPTED).build());
+        updateReq.getAuxClasses().add(new 
StringPatchItem.Builder().value("csv").build());
 
         for (int i = 0; i < 2; i++) {
-            updateAnyObject(anyObjectPatch);
+            updateAnyObject(updateReq);
         }
 
         // 2. remove resources and auxiliary classes
-        anyObjectPatch.getResources().clear();
-        anyObjectPatch.getResources().add(new StringPatchItem.Builder()
+        updateReq.getResources().clear();
+        updateReq.getResources().add(new StringPatchItem.Builder()
                 .value(RESOURCE_NAME_DBSCRIPTED)
                 .operation(PatchOperation.DELETE)
                 .build());
-        anyObjectPatch.getAuxClasses().clear();
-        anyObjectPatch.getAuxClasses().add(new StringPatchItem.Builder()
+        updateReq.getAuxClasses().clear();
+        updateReq.getAuxClasses().add(new StringPatchItem.Builder()
                 .value("csv")
                 .operation(PatchOperation.DELETE)
                 .build());
 
-        updateAnyObject(anyObjectPatch);
+        updateAnyObject(updateReq);
 
         AnyObjectTO printer = 
ANY_OBJECT_SERVICE.read("8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
         assertFalse(printer.getResources().contains(RESOURCE_NAME_DBSCRIPTED), 
"Should not contain removed resources");
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java
index d7a990f6aa..03dfcaee69 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java
@@ -598,7 +598,8 @@ public class AuditITCase extends AbstractITCase {
                             .entityKey(pullFromLDAP.getKey())
                             .page(1)
                             .size(10)
-                            .events(List.of("create", "update", 
"matchingrule_update", "unmatchingrule_assign",
+                            .events(List.of(
+                                    "create", "update", "matchingrule_update", 
"unmatchingrule_assign",
                                     "unmatchingrule_provision"))
                             .result(AuditElements.Result.SUCCESS)
                             .build()).getTotalCount());
diff --git a/pom.xml b/pom.xml
index e6b3162d39..93081efb1f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2380,6 +2380,7 @@ under the License.
                 <postgresqlJDBC>${jdbc.postgresql.version}</postgresqlJDBC>
                 <mysqlJDBC>${jdbc.mysql.version}</mysqlJDBC>
                 <mariadbJDBC>${jdbc.mariadb.version}</mariadbJDBC>
+                <oracleJDBC>${jdbc.oracle.version}</oracleJDBC>
                 <sqlserverJDBC>${jdbc.mssql.version}</sqlserverJDBC>
                 <year>${year}</year>
                 <numbered>true</numbered>
diff --git a/src/main/asciidoc/getting-started/systemRequirements.adoc 
b/src/main/asciidoc/getting-started/systemRequirements.adoc
index ee4d38c6d5..6dfcaebe65 100644
--- a/src/main/asciidoc/getting-started/systemRequirements.adoc
+++ b/src/main/asciidoc/getting-started/systemRequirements.adoc
@@ -47,5 +47,5 @@ Apache Syncope {docVersion} is verified with the recent 
versions of the followin
  . http://www.postgresql.org/[PostgreSQL^] (>= {postgresql}, JDBC driver >= 
{postgresqlJDBC})
  . https://mariadb.org/[MariaDB^] (>= {mariadb}, JDBC driver >= {mariadbJDBC})
  . http://www.mysql.com/[MySQL^] (>= {mysql}, JDBC driver >= {mysqlJDBC})
- . https://www.oracle.com/database/index.html[Oracle Database^] (>= 11g, JDBC 
driver >= ojdbc8 12.2.0.1)
- . http://www.microsoft.com/en-us/server-cloud/products/sql-server/[MS SQL 
Server^] (>= 2017, JDBC driver >= {sqlserverJDBC}8)
+ . https://www.oracle.com/database/index.html[Oracle Database^] (>= 19c, JDBC 
driver >= ojdbc11 {oracleJDBC})
+ . http://www.microsoft.com/en-us/server-cloud/products/sql-server/[MS SQL 
Server^] (>= 2017, JDBC driver >= {sqlserverJDBC}11)
diff --git a/src/main/asciidoc/reference-guide/configuration/dbms.adoc 
b/src/main/asciidoc/reference-guide/configuration/dbms.adoc
index 5638a47a66..0f91d2ffc3 100644
--- a/src/main/asciidoc/reference-guide/configuration/dbms.adoc
+++ b/src/main/asciidoc/reference-guide/configuration/dbms.adoc
@@ -240,7 +240,7 @@ This assumes that you have a MariaDB instance running on 
localhost, listening on
 ==== Oracle Database
 
 [NOTE]
-Apache Syncope {docVersion} is verified with Oracle database >= 11g and JDBC 
driver >= ojdbc8 12.2.0.1.
+Apache Syncope {docVersion} is verified with Oracle database >= 19c and JDBC 
driver >= ojdbc11 {oracleJDBC}.
 
 Create
 
@@ -274,6 +274,59 @@ for the Core application.
 This assumes that you have an Oracle instance running on localhost, listening 
on its default port 1521 with a database
 `syncope` under tablespace `SYNCOPE`, fully accessible by user `syncope` with 
password `syncope`.
 
+==== Oracle Database (JSON)
+
+[NOTE]
+With the configurations reported below, Apache Syncope will leverage the
+https://docs.oracle.com/en/database/oracle/oracle-database/19/adjsn/[JSON^] 
features.
+
+[NOTE]
+Apache Syncope {docVersion} is verified with Oracle database >= 19c and JDBC 
driver >= ojdbc11 {oracleJDBC}.
+
+Add the following dependency to `core/pom.xml`:
+
+[source,xml,subs="verbatim,attributes"]
+----
+<dependency>
+  <groupId>org.apache.syncope.core</groupId>
+  <artifactId>syncope-core-persistence-jpa-json</artifactId>
+  <version>${syncope.version}</version>
+</dependency>
+----
+
+Create
+
+[source]
+....
+persistence.indexesXML=classpath:ojson/indexes.xml
+persistence.viewsXML=classpath:ojson/views.xml
+
+persistence.domain[0].key=Master
+persistence.domain[0].jdbcDriver=oracle.jdbc.OracleDriver
+persistence.domain[0].jdbcURL=jdbc:postgresql://${DB_CONTAINER_IP}:5432/syncope?stringtype=unspecified
+persistence.domain[0].schema=SYNCOPE
+persistence.domain[0].dbUsername=syncope
+persistence.domain[0].dbPassword=syncope
+persistence.domain[0].databasePlatform=org.apache.openjpa.jdbc.sql.OracleDictionary
+persistence.domain[0].orm=META-INF/spring-orm-ojson.xml
+persistence.domain[0].auditSql=audit_ojson.sql
+persistence.domain[0].poolMaxActive=10
+persistence.domain[0].poolMinIdle=2
+
+provisioning.quartz.delegate=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
+provisioning.quartz.sql=tables_oracle.sql
+....
+
+as `core/src/main/resources/core-ojson.properties`.
+
+Do not forget to include `ojson` as 
+https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.profiles.adding-active-profiles[Spring
 Boot profile^]
+for the Core application.
+
+[WARNING]
+This assumes that you have an Oracle instance running on localhost, listening 
on its default port 1521 with a database
+`syncope` under tablespace `SYNCOPE`, fully accessible by user `syncope` with 
password `syncope`.
+
 ==== MS SQL Server
 
 [NOTE]

Reply via email to