Merge pull request #1497 from mposolda/master

Mongo model fix
This commit is contained in:
Marek Posolda 2015-07-24 12:47:47 +02:00
commit 58ad6b1a40
6 changed files with 54 additions and 12 deletions

View file

@ -249,7 +249,7 @@ public class Update1_2_0_Beta1 extends Update {
dbMapper.put("protocolMapper", protocolMapper.getProtocolMapper()); dbMapper.put("protocolMapper", protocolMapper.getProtocolMapper());
Map<String, String> config = protocolMapper.getConfig(); Map<String, String> config = protocolMapper.getConfig();
BasicDBObject dbConfig = MapMapper.convertMap(config); BasicDBObject dbConfig = MapMapper.convertMap(config, null);
dbMapper.put("config", dbConfig); dbMapper.put("config", dbConfig);
dbProtocolMappers.add(dbMapper); dbProtocolMappers.add(dbMapper);

View file

@ -47,6 +47,10 @@ public class MapperRegistry {
public <S> S convertDBObjectToApplicationObject(MapperContext<Object, S> context) { public <S> S convertDBObjectToApplicationObject(MapperContext<Object, S> context) {
if (context.getObjectToConvert() == null) {
return null;
}
Object dbObject = context.getObjectToConvert(); Object dbObject = context.getObjectToConvert();
Class<?> expectedApplicationObjectType = context.getExpectedReturnType(); Class<?> expectedApplicationObjectType = context.getExpectedReturnType();
@ -74,6 +78,10 @@ public class MapperRegistry {
public <S> S convertApplicationObjectToDBObject(Object applicationObject, Class<S> expectedDBObjectType) { public <S> S convertApplicationObjectToDBObject(Object applicationObject, Class<S> expectedDBObjectType) {
if (applicationObject == null) {
return null;
}
Class<?> appObjectType = applicationObject.getClass(); Class<?> appObjectType = applicationObject.getClass();
Mapper<Object, S> mapper = (Mapper<Object, S>)getAppConverterForType(appObjectType, appObjectMappers); Mapper<Object, S> mapper = (Mapper<Object, S>)getAppConverterForType(appObjectType, appObjectMappers);
if (mapper == null) { if (mapper == null) {

View file

@ -79,9 +79,9 @@ public class MongoStoreImpl implements MongoStore {
mapperRegistry.addAppObjectMapper(new ListMapper(mapperRegistry, Set.class)); mapperRegistry.addAppObjectMapper(new ListMapper(mapperRegistry, Set.class));
mapperRegistry.addDBObjectMapper(new BasicDBListToSetMapper(mapperRegistry)); mapperRegistry.addDBObjectMapper(new BasicDBListToSetMapper(mapperRegistry));
mapperRegistry.addAppObjectMapper(new MapMapper(HashMap.class)); mapperRegistry.addAppObjectMapper(new MapMapper(mapperRegistry, HashMap.class));
mapperRegistry.addAppObjectMapper(new MapMapper(Map.class)); mapperRegistry.addAppObjectMapper(new MapMapper(mapperRegistry, Map.class));
mapperRegistry.addDBObjectMapper(new BasicDBObjectToMapMapper()); mapperRegistry.addDBObjectMapper(new BasicDBObjectToMapMapper(mapperRegistry));
// Enum converters // Enum converters
mapperRegistry.addAppObjectMapper(new EnumToStringMapper()); mapperRegistry.addAppObjectMapper(new EnumToStringMapper());

View file

@ -3,31 +3,44 @@ package org.keycloak.connections.mongo.impl.types;
import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObject;
import org.keycloak.connections.mongo.api.types.Mapper; import org.keycloak.connections.mongo.api.types.Mapper;
import org.keycloak.connections.mongo.api.types.MapperContext; 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.HashMap;
import java.util.Map; 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> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public class BasicDBObjectToMapMapper implements Mapper<BasicDBObject, Map> { public class BasicDBObjectToMapMapper implements Mapper<BasicDBObject, Map> {
private final MapperRegistry mapperRegistry;
public BasicDBObjectToMapMapper(MapperRegistry mapperRegistry) {
this.mapperRegistry = mapperRegistry;
}
@Override @Override
public Map convertObject(MapperContext<BasicDBObject, Map> context) { public Map convertObject(MapperContext<BasicDBObject, Map> context) {
BasicDBObject dbObjectToConvert = context.getObjectToConvert(); BasicDBObject dbObjectToConvert = context.getObjectToConvert();
Type expectedElementValueType = context.getGenericTypes().get(1);
HashMap<String, Object> result = new HashMap<String, Object>(); HashMap<String, Object> result = new HashMap<String, Object>();
for (Map.Entry<String, Object> entry : dbObjectToConvert.entrySet()) { for (Map.Entry<String, Object> entry : dbObjectToConvert.entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
Object value = entry.getValue(); Object dbValue = entry.getValue();
// Workaround as manually inserted numbers into mongo may be treated as "Double" // Workaround as manually inserted numbers into mongo may be treated as "Double"
if (value instanceof Double && context.getGenericTypes().get(1) == Integer.class) { if (dbValue instanceof Double && expectedElementValueType == Integer.class) {
value = ((Double)value).intValue(); dbValue = ((Double)dbValue).intValue();
} }
MapperContext<Object, Object> newContext = getMapperContext(dbValue, expectedElementValueType);
Object value = mapperRegistry.convertDBObjectToApplicationObject(newContext);
if (key.contains(MapMapper.DOT_PLACEHOLDER)) { if (key.contains(MapMapper.DOT_PLACEHOLDER)) {
key = key.replaceAll(MapMapper.DOT_PLACEHOLDER, "."); key = key.replaceAll(MapMapper.DOT_PLACEHOLDER, ".");
} }
@ -46,4 +59,19 @@ public class BasicDBObjectToMapMapper implements Mapper<BasicDBObject, Map> {
public Class<Map> getExpectedReturnType() { public Class<Map> getExpectedReturnType() {
return Map.class; 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);
}
}
} }

View file

@ -3,6 +3,7 @@ package org.keycloak.connections.mongo.impl.types;
import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObject;
import org.keycloak.connections.mongo.api.types.Mapper; import org.keycloak.connections.mongo.api.types.Mapper;
import org.keycloak.connections.mongo.api.types.MapperContext; import org.keycloak.connections.mongo.api.types.MapperContext;
import org.keycloak.connections.mongo.api.types.MapperRegistry;
import java.util.Map; import java.util.Map;
import java.util.Set; 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 // Just some dummy way of encoding . character as it's not allowed by mongo in key fields
static final String DOT_PLACEHOLDER = "###"; static final String DOT_PLACEHOLDER = "###";
private final MapperRegistry mapperRegistry;
private final Class<T> mapType; private final Class<T> mapType;
public MapMapper(Class<T> mapType) { public MapMapper(MapperRegistry mapperRegistry, Class<T> mapType) {
this.mapperRegistry = mapperRegistry;
this.mapType = mapType; this.mapType = mapType;
} }
@Override @Override
public BasicDBObject convertObject(MapperContext<T, BasicDBObject> context) { public BasicDBObject convertObject(MapperContext<T, BasicDBObject> context) {
T mapToConvert = context.getObjectToConvert(); 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(); BasicDBObject dbObject = new BasicDBObject();
Set<Map.Entry> entries = mapToConvert.entrySet(); Set<Map.Entry> entries = mapToConvert.entrySet();
for (Map.Entry entry : entries) { for (Map.Entry entry : entries) {
String key = (String)entry.getKey(); String key = (String)entry.getKey();
Object value = entry.getValue(); Object value = entry.getValue();
Object dbValue = mapperRegistry==null ? entry.getValue() : mapperRegistry.convertApplicationObjectToDBObject(value, Object.class);
if (key.contains(".")) { if (key.contains(".")) {
key = key.replaceAll("\\.", DOT_PLACEHOLDER); key = key.replaceAll("\\.", DOT_PLACEHOLDER);
} }
dbObject.put(key, value); dbObject.put(key, dbValue);
} }
return dbObject; return dbObject;
} }

View file

@ -1310,6 +1310,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
model.setDescription(entity.getDescription()); model.setDescription(entity.getDescription());
model.setBuiltIn(entity.isBuiltIn()); model.setBuiltIn(entity.isBuiltIn());
model.setTopLevel(entity.isTopLevel()); model.setTopLevel(entity.isTopLevel());
model.setProviderId(entity.getProviderId());
return model; return model;
} }