keycloak-memoizeit

Details

diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/api/types/MapperRegistry.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/api/types/MapperRegistry.java
index bafda1e..90c9355 100755
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/api/types/MapperRegistry.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/api/types/MapperRegistry.java
@@ -47,6 +47,10 @@ public class MapperRegistry {
 
 
     public <S> S convertDBObjectToApplicationObject(MapperContext<Object, S> context) {
+        if (context.getObjectToConvert() == null) {
+            return null;
+        }
+
         Object dbObject = context.getObjectToConvert();
         Class<?> expectedApplicationObjectType = context.getExpectedReturnType();
 
@@ -74,6 +78,10 @@ public class MapperRegistry {
 
 
     public <S> S convertApplicationObjectToDBObject(Object applicationObject, Class<S> expectedDBObjectType) {
+        if (applicationObject == null) {
+            return null;
+        }
+
         Class<?> appObjectType = applicationObject.getClass();
         Mapper<Object, S> mapper = (Mapper<Object, S>)getAppConverterForType(appObjectType, appObjectMappers);
         if (mapper == null) {
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/MongoStoreImpl.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/MongoStoreImpl.java
index a496c0b..94049f5 100755
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/MongoStoreImpl.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/MongoStoreImpl.java
@@ -79,9 +79,9 @@ public class MongoStoreImpl implements MongoStore {
         mapperRegistry.addAppObjectMapper(new ListMapper(mapperRegistry, Set.class));
         mapperRegistry.addDBObjectMapper(new BasicDBListToSetMapper(mapperRegistry));
 
-        mapperRegistry.addAppObjectMapper(new MapMapper(HashMap.class));
-        mapperRegistry.addAppObjectMapper(new MapMapper(Map.class));
-        mapperRegistry.addDBObjectMapper(new BasicDBObjectToMapMapper());
+        mapperRegistry.addAppObjectMapper(new MapMapper(mapperRegistry, HashMap.class));
+        mapperRegistry.addAppObjectMapper(new MapMapper(mapperRegistry, Map.class));
+        mapperRegistry.addDBObjectMapper(new BasicDBObjectToMapMapper(mapperRegistry));
 
         // Enum converters
         mapperRegistry.addAppObjectMapper(new EnumToStringMapper());
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/BasicDBObjectToMapMapper.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/BasicDBObjectToMapMapper.java
index 14ada88..316d771 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/BasicDBObjectToMapMapper.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/BasicDBObjectToMapMapper.java
@@ -3,31 +3,44 @@ package org.keycloak.connections.mongo.impl.types;
 import com.mongodb.BasicDBObject;
 import org.keycloak.connections.mongo.api.types.Mapper;
 import org.keycloak.connections.mongo.api.types.MapperContext;
+import org.keycloak.connections.mongo.api.types.MapperRegistry;
 
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
 /**
- * For now, there is support just for convert to Map<String, simpleType>
  *
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
 public class BasicDBObjectToMapMapper implements Mapper<BasicDBObject, Map> {
 
+    private final MapperRegistry mapperRegistry;
+
+    public BasicDBObjectToMapMapper(MapperRegistry mapperRegistry) {
+        this.mapperRegistry = mapperRegistry;
+    }
+
     @Override
     public Map convertObject(MapperContext<BasicDBObject, Map> context) {
         BasicDBObject dbObjectToConvert = context.getObjectToConvert();
+        Type expectedElementValueType = context.getGenericTypes().get(1);
 
         HashMap<String, Object> result = new HashMap<String, Object>();
         for (Map.Entry<String, Object> entry : dbObjectToConvert.entrySet()) {
             String key = entry.getKey();
-            Object value = entry.getValue();
+            Object dbValue = entry.getValue();
 
             // Workaround as manually inserted numbers into mongo may be treated as "Double"
-            if (value instanceof Double && context.getGenericTypes().get(1) == Integer.class) {
-                value = ((Double)value).intValue();
+            if (dbValue instanceof Double && expectedElementValueType == Integer.class) {
+                dbValue = ((Double)dbValue).intValue();
             }
 
+            MapperContext<Object, Object> newContext = getMapperContext(dbValue, expectedElementValueType);
+            Object value = mapperRegistry.convertDBObjectToApplicationObject(newContext);
+
             if (key.contains(MapMapper.DOT_PLACEHOLDER)) {
                 key = key.replaceAll(MapMapper.DOT_PLACEHOLDER, ".");
             }
@@ -46,4 +59,19 @@ public class BasicDBObjectToMapMapper implements Mapper<BasicDBObject, Map> {
     public Class<Map> getExpectedReturnType() {
         return Map.class;
     }
+
+    private MapperContext<Object, Object> getMapperContext(Object dbValue, Type expectedElementValueType) {
+        if (expectedElementValueType instanceof Class) {
+            Class<?> clazz = (Class<?>) expectedElementValueType;
+            return new MapperContext<>(dbValue, clazz, null);
+        } else if (expectedElementValueType instanceof ParameterizedType) {
+            ParameterizedType parameterized = (ParameterizedType) expectedElementValueType;
+            Class<?> expectedClazz = (Class<?>) parameterized.getRawType();
+            Type[] generics = parameterized.getActualTypeArguments();
+
+            return new MapperContext<>(dbValue, expectedClazz, Arrays.asList(generics));
+        } else {
+            throw new IllegalArgumentException("Unexpected type: '" + expectedElementValueType + "' for converting " + dbValue);
+        }
+    }
 }
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/MapMapper.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/MapMapper.java
index d4f0d29..5ec174b 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/MapMapper.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/MapMapper.java
@@ -3,6 +3,7 @@ package org.keycloak.connections.mongo.impl.types;
 import com.mongodb.BasicDBObject;
 import org.keycloak.connections.mongo.api.types.Mapper;
 import org.keycloak.connections.mongo.api.types.MapperContext;
+import org.keycloak.connections.mongo.api.types.MapperRegistry;
 
 import java.util.Map;
 import java.util.Set;
@@ -17,30 +18,34 @@ public class MapMapper<T extends Map> implements Mapper<T, BasicDBObject> {
     // Just some dummy way of encoding . character as it's not allowed by mongo in key fields
     static final String DOT_PLACEHOLDER = "###";
 
+    private final MapperRegistry mapperRegistry;
     private final Class<T> mapType;
 
-    public MapMapper(Class<T> mapType) {
+    public MapMapper(MapperRegistry mapperRegistry, Class<T> mapType) {
+        this.mapperRegistry = mapperRegistry;
         this.mapType = mapType;
     }
 
     @Override
     public BasicDBObject convertObject(MapperContext<T, BasicDBObject> context) {
         T mapToConvert = context.getObjectToConvert();
-        return convertMap(mapToConvert);
+        return convertMap(mapToConvert, mapperRegistry);
     }
 
-    public static BasicDBObject convertMap(Map mapToConvert) {
+    public static BasicDBObject convertMap(Map mapToConvert, MapperRegistry mapperRegistry) {
         BasicDBObject dbObject = new BasicDBObject();
         Set<Map.Entry> entries = mapToConvert.entrySet();
         for (Map.Entry entry : entries) {
             String key = (String)entry.getKey();
             Object value = entry.getValue();
 
+            Object dbValue = mapperRegistry==null ? entry.getValue() : mapperRegistry.convertApplicationObjectToDBObject(value, Object.class);
+
             if (key.contains(".")) {
                 key = key.replaceAll("\\.", DOT_PLACEHOLDER);
             }
 
-            dbObject.put(key, value);
+            dbObject.put(key, dbValue);
         }
         return dbObject;
     }
diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_2_0_Beta1.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_2_0_Beta1.java
index abaae4c..aedd9f9 100644
--- a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_2_0_Beta1.java
+++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_2_0_Beta1.java
@@ -249,7 +249,7 @@ public class Update1_2_0_Beta1 extends Update {
                     dbMapper.put("protocolMapper", protocolMapper.getProtocolMapper());
 
                     Map<String, String> config = protocolMapper.getConfig();
-                    BasicDBObject dbConfig = MapMapper.convertMap(config);
+                    BasicDBObject dbConfig = MapMapper.convertMap(config, null);
                     dbMapper.put("config", dbConfig);
 
                     dbProtocolMappers.add(dbMapper);
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index 3a63687..823a51b 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -1310,6 +1310,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         model.setDescription(entity.getDescription());
         model.setBuiltIn(entity.isBuiltIn());
         model.setTopLevel(entity.isTopLevel());
+        model.setProviderId(entity.getProviderId());
         return model;
     }