From 934bab363ca2e05e0b5416823153f175644e6dd8 Mon Sep 17 00:00:00 2001
From: pkupczyk <pkupczyk>
Date: Sun, 10 Jun 2012 17:04:08 +0000
Subject: [PATCH] SP-116 / BIS-14 Query Plugins in JSON-RPC - fix for nested
 arrays

SVN: 25622
---
 .../JsonContainerDeserializer.java            | 372 ------------------
 .../deserializer/JsonDeserializerFactory.java | 200 ++++++++++
 .../JsonDeserializerProvider.java             |  36 +-
 .../JsonTypeAndClassDeserializer.java         |  17 +-
 .../IJsonTypeValueToClassObjectMapping.java   |  27 --
 ...nReflectionsBaseTypeToSubTypesMapping.java |  26 +-
 ...lectionsTypeValueToClassObjectMapping.java |  82 ----
 .../serializer/JsonSerializerFactory.java     | 142 +++++++
 .../server/json/JsonDeserializationTest.java  |  57 ++-
 .../api/server/json/JsonTestObjectMapper.java |  10 +-
 .../json/object/ObjectWithContainerTypes.java |  24 +-
 .../shared/api/json/GenericObjectMapper.java  |  10 +-
 .../api/json/ScreeningObjectMapper.java       |  10 +-
 13 files changed, 458 insertions(+), 555 deletions(-)
 delete mode 100644 openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonContainerDeserializer.java
 create mode 100644 openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonDeserializerFactory.java
 delete mode 100644 openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/IJsonTypeValueToClassObjectMapping.java
 delete mode 100644 openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/JsonReflectionsTypeValueToClassObjectMapping.java
 create mode 100644 openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/serializer/JsonSerializerFactory.java

diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonContainerDeserializer.java b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonContainerDeserializer.java
deleted file mode 100644
index 4f524d118e0..00000000000
--- a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonContainerDeserializer.java
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright 2012 ETH Zuerich, CISD
- *
- * Licensed 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 ch.systemsx.cisd.common.api.server.json.deserializer;
-
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.Set;
-
-import org.codehaus.jackson.JsonParser;
-import org.codehaus.jackson.map.DeserializationContext;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.JsonMappingException;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.map.deser.BeanDeserializer;
-import org.codehaus.jackson.map.deser.BeanDeserializerFactory;
-import org.codehaus.jackson.map.deser.SettableBeanProperty;
-import org.codehaus.jackson.map.introspect.BasicBeanDescription;
-import org.codehaus.jackson.map.util.ClassUtil;
-import org.codehaus.jackson.type.JavaType;
-
-import ch.systemsx.cisd.common.api.server.json.common.JsonConstants;
-import ch.systemsx.cisd.common.api.server.json.mapping.IJsonClassValueToClassObjectsMapping;
-import ch.systemsx.cisd.common.api.server.json.mapping.IJsonTypeValueToClassObjectMapping;
-
-/**
- * @author pkupczyk
- */
-
-@SuppressWarnings(
-    { "rawtypes", "unchecked" })
-public class JsonContainerDeserializer extends JsonDeserializer<Object>
-{
-
-    private JsonDeserializer<Object> originalDeserializer;
-
-    private IJsonTypeValueToClassObjectMapping typeValueToClassObjectMapping;
-
-    private IJsonClassValueToClassObjectsMapping classValueToClassObjectsMapping;
-
-    public JsonContainerDeserializer(JsonDeserializer<Object> originalDeserializer,
-            IJsonTypeValueToClassObjectMapping typeValueToClassObjectMapping,
-            IJsonClassValueToClassObjectsMapping classValueToClassObjectsMapping)
-    {
-        this.originalDeserializer = originalDeserializer;
-        this.typeValueToClassObjectMapping = typeValueToClassObjectMapping;
-        this.classValueToClassObjectsMapping = classValueToClassObjectsMapping;
-    }
-
-    public static boolean canDeserialize(JavaType type)
-    {
-        Class<?> clazz = type.getRawClass();
-        return Map.class.isAssignableFrom(clazz) || Collection.class.isAssignableFrom(clazz);
-    }
-
-    @Override
-    public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException
-    {
-        Object object = getOriginalDeserializer().deserialize(jp, ctxt);
-        return tryConvertNestedMaps(object, ctxt);
-    }
-
-    private Object tryConvertNestedMaps(Object object, DeserializationContext ctxt)
-    {
-        if (object instanceof EnumMap || object instanceof EnumSet)
-        {
-            return object;
-        }
-        if (object instanceof Map)
-        {
-            return tryConvertNestedMapsInMap((Map) object, ctxt);
-        } else if (object instanceof List)
-        {
-            return tryConvertNestedMapsInList((List) object, ctxt);
-        } else if (object instanceof Set)
-        {
-            return tryConvertNestedMapsInCollection((Set) object, new HashSet(), ctxt);
-        } else if (object instanceof Collection)
-        {
-            return tryConvertNestedMapsInCollection((Collection) object, new ArrayList(), ctxt);
-        } else
-        {
-            return object;
-        }
-    }
-
-    private Object tryConvertNestedMapsInMap(Map map, DeserializationContext ctxt)
-    {
-        if (map == null || map.isEmpty())
-        {
-            return map;
-        }
-
-        Iterator<Map.Entry> iterator = map.entrySet().iterator();
-
-        String typeValue = null;
-        String classValue = null;
-        Map changedValues = null;
-
-        while (iterator.hasNext())
-        {
-            Map.Entry entry = iterator.next();
-            Object key = entry.getKey();
-            Object value = entry.getValue();
-
-            if (value instanceof String)
-            {
-                if (JsonConstants.getTypeField().equals(key))
-                {
-                    typeValue = (String) entry.getValue();
-                } else if (JsonConstants.getLegacyClassField().equals(key))
-                {
-                    classValue = (String) entry.getValue();
-                }
-            } else
-            {
-                Object newValue = tryConvertNestedMaps(value, ctxt);
-
-                if (newValue != value)
-                {
-                    if (changedValues == null)
-                    {
-                        changedValues = new HashMap();
-                    }
-                    changedValues.put(key, newValue);
-                }
-            }
-        }
-
-        if (changedValues != null)
-        {
-            map.putAll(changedValues);
-        }
-
-        if (typeValue == null && classValue == null)
-        {
-            return map;
-        } else
-        {
-            return tryConvertMap(map, typeValue, classValue, ctxt);
-        }
-    }
-
-    private Object tryConvertNestedMapsInList(List list, DeserializationContext ctxt)
-    {
-        if (list == null || list.isEmpty())
-        {
-            return list;
-        }
-
-        ListIterator iterator = list.listIterator();
-
-        while (iterator.hasNext())
-        {
-            Object item = iterator.next();
-            Object newItem = tryConvertNestedMaps(item, ctxt);
-
-            if (newItem != item)
-            {
-                iterator.set(newItem);
-            }
-        }
-        return list;
-    }
-
-    private Object tryConvertNestedMapsInCollection(Collection collection,
-            Collection newCollection, DeserializationContext ctxt)
-    {
-        if (collection == null || collection.isEmpty())
-        {
-            return collection;
-        }
-
-        Iterator iterator = collection.iterator();
-        boolean changed = false;
-
-        while (iterator.hasNext())
-        {
-            Object item = iterator.next();
-            Object newItem = tryConvertNestedMaps(item, ctxt);
-
-            if (newItem != item)
-            {
-                changed = true;
-            }
-            newCollection.add(newItem);
-        }
-
-        if (changed)
-        {
-            return newCollection;
-        } else
-        {
-            return collection;
-        }
-    }
-
-    private Object tryConvertMap(Map map, String typeValue, String classValue,
-            DeserializationContext ctxt)
-    {
-        Class<?> clazz = tryGetClass(typeValue, classValue);
-
-        if (clazz != null)
-        {
-            boolean hadTypeValue = map.containsKey(JsonConstants.getTypeField());
-            boolean hadClassValue = map.containsKey(JsonConstants.getLegacyClassField());
-
-            map.remove(JsonConstants.getTypeField());
-            map.remove(JsonConstants.getLegacyClassField());
-
-            try
-            {
-                Object instance = tryCreateInstance(clazz, ctxt);
-
-                Iterator<SettableBeanProperty> properties = tryGetProperties(clazz, ctxt);
-                if (properties != null)
-                {
-                    trySetProperties(instance, properties, map, ctxt);
-                }
-
-                return instance;
-
-            } catch (IOException e)
-            {
-                if (hadTypeValue)
-                {
-                    map.put(JsonConstants.getTypeField(), typeValue);
-                }
-                if (hadClassValue)
-                {
-                    map.put(JsonConstants.getLegacyClassField(), classValue);
-                }
-                return map;
-            }
-        } else
-        {
-            return map;
-        }
-    }
-
-    private Class tryGetClass(String typeValue, String classValue)
-    {
-        Class<?> clazz = null;
-
-        if (typeValue != null)
-        {
-            clazz = getTypeValueToClassObjectMapping().getClass(typeValue);
-        } else if (classValue != null)
-        {
-            List<Class<?>> clazzList = getClassValueToClassObjectsMapping().getClasses(classValue);
-            if (clazzList != null && clazzList.size() == 1)
-            {
-                clazz = clazzList.get(0);
-            }
-        }
-
-        return clazz;
-    }
-
-    private Object tryCreateInstance(Class<?> clazz, DeserializationContext ctxt)
-            throws IOException
-    {
-        try
-        {
-            JavaType type = ctxt.getConfig().getTypeFactory().constructType(clazz);
-            BasicBeanDescription beanDesc = ctxt.getConfig().introspect(type);
-            Constructor<?> defaultConstructor = beanDesc.findDefaultConstructor();
-            ClassUtil.checkAndFixAccess(defaultConstructor);
-            return defaultConstructor.newInstance();
-
-        } catch (InstantiationException e)
-        {
-            throw new JsonMappingException("Couldn't create an instance of class: " + clazz, e);
-        } catch (IllegalAccessException e)
-        {
-            throw new JsonMappingException("Couldn't create an instance of class: " + clazz, e);
-        } catch (IllegalArgumentException e)
-        {
-            throw new JsonMappingException("Couldn't create an instance of class: " + clazz, e);
-        } catch (InvocationTargetException e)
-        {
-            throw new JsonMappingException("Couldn't create an instance of class: " + clazz, e);
-        }
-    }
-
-    private Iterator<SettableBeanProperty> tryGetProperties(Class<?> clazz,
-            DeserializationContext ctxt) throws IOException
-    {
-        JavaType type = ctxt.getConfig().getTypeFactory().constructType(clazz);
-        JsonDeserializer deserializer =
-                getBeanDeserializerFactory().createBeanDeserializer(ctxt.getConfig(),
-                        ctxt.getDeserializerProvider(), type, null);
-
-        if (deserializer instanceof BeanDeserializer)
-        {
-            return ((BeanDeserializer) deserializer).properties();
-        } else
-        {
-            return null;
-        }
-    }
-
-    private void trySetProperties(Object instance, Iterator<SettableBeanProperty> properties,
-            Map values, DeserializationContext ctxt) throws IOException
-    {
-        while (properties.hasNext())
-        {
-            SettableBeanProperty property = properties.next();
-            Object value = values.get(property.getName());
-
-            if (value != null)
-            {
-                if (property.getType().getRawClass().isAssignableFrom(value.getClass()))
-                {
-                    property.set(instance, value);
-                } else
-                {
-                    ObjectMapper mapper = new ObjectMapper();
-                    String json = mapper.writeValueAsString(value);
-                    Object newValue = mapper.readValue(json, property.getType());
-                    property.set(instance, newValue);
-                }
-            }
-
-        }
-    }
-
-    private BeanDeserializerFactory getBeanDeserializerFactory()
-    {
-        return BeanDeserializerFactory.instance;
-    }
-
-    private JsonDeserializer<Object> getOriginalDeserializer()
-    {
-        return originalDeserializer;
-    }
-
-    private IJsonTypeValueToClassObjectMapping getTypeValueToClassObjectMapping()
-    {
-        return typeValueToClassObjectMapping;
-    }
-
-    private IJsonClassValueToClassObjectsMapping getClassValueToClassObjectsMapping()
-    {
-        return classValueToClassObjectsMapping;
-    }
-
-}
diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonDeserializerFactory.java b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonDeserializerFactory.java
new file mode 100644
index 00000000000..683565ab836
--- /dev/null
+++ b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonDeserializerFactory.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed 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 ch.systemsx.cisd.common.api.server.json.deserializer;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Collection;
+
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.map.AnnotationIntrospector;
+import org.codehaus.jackson.map.BeanProperty;
+import org.codehaus.jackson.map.DeserializationConfig;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.DeserializerProvider;
+import org.codehaus.jackson.map.JsonDeserializer;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.TypeDeserializer;
+import org.codehaus.jackson.map.deser.BeanDeserializerFactory;
+import org.codehaus.jackson.map.introspect.AnnotatedClass;
+import org.codehaus.jackson.map.introspect.BasicBeanDescription;
+import org.codehaus.jackson.map.jsontype.NamedType;
+import org.codehaus.jackson.map.jsontype.TypeIdResolver;
+import org.codehaus.jackson.map.jsontype.impl.TypeNameIdResolver;
+import org.codehaus.jackson.map.type.ArrayType;
+import org.codehaus.jackson.map.type.CollectionLikeType;
+import org.codehaus.jackson.map.type.CollectionType;
+import org.codehaus.jackson.map.type.MapLikeType;
+import org.codehaus.jackson.map.type.MapType;
+import org.codehaus.jackson.type.JavaType;
+
+import ch.systemsx.cisd.base.annotation.JsonObject;
+import ch.systemsx.cisd.common.api.server.json.common.JsonConstants;
+import ch.systemsx.cisd.common.api.server.json.mapping.IJsonClassValueToClassObjectsMapping;
+import ch.systemsx.cisd.common.api.server.json.mapping.JsonStaticClassValueToClassObjectsMapping;
+
+/**
+ * @author pkupczyk
+ */
+public class JsonDeserializerFactory extends BeanDeserializerFactory
+{
+
+    private IJsonClassValueToClassObjectsMapping classValueToClassObjectsMapping =
+            new JsonStaticClassValueToClassObjectsMapping();
+
+    public JsonDeserializerFactory(
+            IJsonClassValueToClassObjectsMapping classValueToClassObjectsMapping)
+    {
+        super(null);
+        this.classValueToClassObjectsMapping = classValueToClassObjectsMapping;
+    }
+
+    @Override
+    public JsonDeserializer<?> createArrayDeserializer(DeserializationConfig config,
+            DeserializerProvider p, ArrayType type, BeanProperty property)
+            throws JsonMappingException
+    {
+        ArrayType newType =
+                type.withContentTypeHandler(createContentTypeDeserializer(config, type, property));
+        return super.createArrayDeserializer(config, p, newType, property);
+    }
+
+    @Override
+    public JsonDeserializer<?> createCollectionDeserializer(DeserializationConfig config,
+            DeserializerProvider p, CollectionType type, BeanProperty property)
+            throws JsonMappingException
+    {
+        CollectionType newType =
+                type.withContentTypeHandler(createContentTypeDeserializer(config, type, property));
+        return super.createCollectionDeserializer(config, p, newType, property);
+    }
+
+    @Override
+    public JsonDeserializer<?> createCollectionLikeDeserializer(DeserializationConfig config,
+            DeserializerProvider p, CollectionLikeType type, BeanProperty property)
+            throws JsonMappingException
+    {
+        CollectionLikeType newType =
+                type.withContentTypeHandler(createContentTypeDeserializer(config, type, property));
+        return super.createCollectionLikeDeserializer(config, p, newType, property);
+    }
+
+    @Override
+    public JsonDeserializer<?> createMapDeserializer(DeserializationConfig config,
+            DeserializerProvider p, MapType type, BeanProperty property)
+            throws JsonMappingException
+    {
+        MapType newType =
+                type.withContentTypeHandler(createContentTypeDeserializer(config, type, property));
+        return super.createMapDeserializer(config, p, newType, property);
+    }
+
+    @Override
+    public JsonDeserializer<?> createMapLikeDeserializer(DeserializationConfig config,
+            DeserializerProvider p, MapLikeType type, BeanProperty property)
+            throws JsonMappingException
+    {
+        MapLikeType newType =
+                type.withContentTypeHandler(createContentTypeDeserializer(config, type, property));
+        return super.createMapLikeDeserializer(config, p, newType, property);
+    }
+
+    private TypeDeserializer createContentTypeDeserializer(DeserializationConfig config,
+            JavaType containerType, BeanProperty property)
+    {
+        JavaType contentType = containerType.getContentType();
+
+        if (contentType == null || contentType.getRawClass() == null)
+        {
+            return null;
+        }
+
+        Class<?> contentClass = contentType.getRawClass();
+
+        if (contentClass.equals(Object.class) || contentClass.isAnnotationPresent(JsonObject.class))
+        {
+            BasicBeanDescription bean =
+                    config.introspectClassAnnotations(contentType.getRawClass());
+            AnnotatedClass ac = bean.getClassInfo();
+            AnnotationIntrospector ai = config.getAnnotationIntrospector();
+            Collection<NamedType> subtypes =
+                    config.getSubtypeResolver().collectAndResolveSubtypes(ac, config, ai);
+            TypeIdResolver resolver =
+                    TypeNameIdResolver.construct(config, contentType, subtypes, false, true);
+            JsonTypeAndClassWithFallbackDeserializer deserializer =
+                    new JsonTypeAndClassWithFallbackDeserializer(contentType, subtypes, resolver,
+                            property, JsonConstants.getTypeField());
+            deserializer.setClassValueToClassObjectsMapping(this.classValueToClassObjectsMapping);
+            return deserializer;
+        } else
+        {
+            return null;
+        }
+    }
+
+    private class JsonTypeAndClassWithFallbackDeserializer extends JsonTypeAndClassDeserializer
+    {
+
+        public JsonTypeAndClassWithFallbackDeserializer(JavaType type,
+                Collection<NamedType> subtypes, TypeIdResolver idRes, BeanProperty property,
+                String typePropName)
+        {
+            super(type, subtypes, idRes, property, typePropName);
+        }
+
+        @Override
+        public Object deserializeTypedFromObject(JsonParser parser, DeserializationContext ctxt)
+                throws IOException
+        {
+            String json = parserToString(parser);
+            JsonFactory factory = new JsonFactory(parser.getCodec());
+
+            try
+            {
+                JsonParser jp1 = factory.createJsonParser(json);
+                jp1.nextToken();
+                return super.deserializeTypedFromObject(jp1, ctxt);
+            } catch (IOException e)
+            {
+                JsonParser jp2 = factory.createJsonParser(json);
+                jp2.nextToken();
+                return super.deserializeWithoutType(jp2, ctxt, null);
+            }
+        }
+
+        private String parserToString(JsonParser parser)
+        {
+            try
+            {
+                JsonFactory factory = new JsonFactory(parser.getCodec());
+                StringWriter writer = new StringWriter();
+                JsonGenerator generator = factory.createJsonGenerator(writer);
+                generator.setCodec(parser.getCodec());
+                JsonNode node = parser.readValueAs(JsonNode.class);
+                generator.writeTree(node);
+                return writer.toString();
+            } catch (IOException e)
+            {
+                throw new IllegalArgumentException(e);
+            }
+        }
+    }
+
+}
diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonDeserializerProvider.java b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonDeserializerProvider.java
index a8f00125e29..a649d11e4d1 100644
--- a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonDeserializerProvider.java
+++ b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonDeserializerProvider.java
@@ -16,15 +16,8 @@
 
 package ch.systemsx.cisd.common.api.server.json.deserializer;
 
-import org.codehaus.jackson.map.BeanProperty;
-import org.codehaus.jackson.map.DeserializationConfig;
-import org.codehaus.jackson.map.JsonDeserializer;
-import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.DeserializerFactory;
 import org.codehaus.jackson.map.deser.StdDeserializerProvider;
-import org.codehaus.jackson.type.JavaType;
-
-import ch.systemsx.cisd.common.api.server.json.mapping.IJsonClassValueToClassObjectsMapping;
-import ch.systemsx.cisd.common.api.server.json.mapping.IJsonTypeValueToClassObjectMapping;
 
 /**
  * @author pkupczyk
@@ -32,32 +25,9 @@ import ch.systemsx.cisd.common.api.server.json.mapping.IJsonTypeValueToClassObje
 public class JsonDeserializerProvider extends StdDeserializerProvider
 {
 
-    private IJsonTypeValueToClassObjectMapping typeValueToClassObjectMapping;
-
-    private IJsonClassValueToClassObjectsMapping classValueToClassObjectsMapping;
-
-    public JsonDeserializerProvider(
-            IJsonTypeValueToClassObjectMapping typeValueToClassObjectMapping,
-            IJsonClassValueToClassObjectsMapping classValueToClassObjectsMapping)
+    public JsonDeserializerProvider(DeserializerFactory f)
     {
-        this.typeValueToClassObjectMapping = typeValueToClassObjectMapping;
-        this.classValueToClassObjectsMapping = classValueToClassObjectsMapping;
-    }
-
-    @Override
-    protected JsonDeserializer<Object> _createDeserializer(DeserializationConfig config,
-            JavaType type, BeanProperty property) throws JsonMappingException
-    {
-        JsonDeserializer<Object> deserializer = super._createDeserializer(config, type, property);
-
-        if (JsonContainerDeserializer.canDeserialize(type))
-        {
-            return new JsonContainerDeserializer(deserializer, typeValueToClassObjectMapping,
-                    classValueToClassObjectsMapping);
-        } else
-        {
-            return deserializer;
-        }
+        super(f);
     }
 
 }
diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonTypeAndClassDeserializer.java b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonTypeAndClassDeserializer.java
index de2c0841a8e..4f704616c03 100644
--- a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonTypeAndClassDeserializer.java
+++ b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/deserializer/JsonTypeAndClassDeserializer.java
@@ -108,7 +108,14 @@ public class JsonTypeAndClassDeserializer extends AsPropertyTypeDeserializer
             tb.copyCurrentStructure(jp);
         }
 
-        return deserializeWithoutType(jp, ctxt, tb);
+        if (hasSubtypes)
+        {
+            throw new JsonMappingException(
+                    "Cannot deserialize a polymorphic type without type information");
+        } else
+        {
+            return deserializeWithoutType(jp, ctxt, tb);
+        }
     }
 
     private Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, TokenBuffer tb,
@@ -177,15 +184,9 @@ public class JsonTypeAndClassDeserializer extends AsPropertyTypeDeserializer
         throw new NoMatchingLegacyClassesException(classValue);
     }
 
-    private Object deserializeWithoutType(JsonParser jp, DeserializationContext ctxt, TokenBuffer tb)
+    public Object deserializeWithoutType(JsonParser jp, DeserializationContext ctxt, TokenBuffer tb)
             throws IOException, JsonProcessingException
     {
-        if (hasSubtypes)
-        {
-            throw new JsonMappingException(
-                    "Cannot deserialize a polymorphic type without type information");
-        }
-
         final JsonParser actualJp;
         final JsonDeserializer<Object> deserializer =
                 ctxt.getDeserializerProvider().findValueDeserializer(ctxt.getConfig(), _baseType,
diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/IJsonTypeValueToClassObjectMapping.java b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/IJsonTypeValueToClassObjectMapping.java
deleted file mode 100644
index c763377cd51..00000000000
--- a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/IJsonTypeValueToClassObjectMapping.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2012 ETH Zuerich, CISD
- *
- * Licensed 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 ch.systemsx.cisd.common.api.server.json.mapping;
-
-/**
- * @author pkupczyk
- */
-public interface IJsonTypeValueToClassObjectMapping
-{
-
-    public Class<?> getClass(String typeValue);
-
-}
diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/JsonReflectionsBaseTypeToSubTypesMapping.java b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/JsonReflectionsBaseTypeToSubTypesMapping.java
index 6eb2a4c0f90..f31feba089c 100644
--- a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/JsonReflectionsBaseTypeToSubTypesMapping.java
+++ b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/JsonReflectionsBaseTypeToSubTypesMapping.java
@@ -37,15 +37,24 @@ public class JsonReflectionsBaseTypeToSubTypesMapping implements IJsonBaseTypeTo
 
     private Map<Class<?>, Set<NamedType>> baseTypeToSubTypesMap;
 
+    private Set<NamedType> allSubTypesSet;
+
     public JsonReflectionsBaseTypeToSubTypesMapping(String prefix)
     {
         baseTypeToSubTypesMap = createBaseTypeToSubTypesMap(prefix);
+        allSubTypesSet = createAllSubTypesSet(baseTypeToSubTypesMap);
     }
 
     @Override
     public Set<NamedType> getSubTypes(Class<?> baseType)
     {
-        return baseTypeToSubTypesMap.get(baseType);
+        if (Object.class.equals(baseType))
+        {
+            return allSubTypesSet;
+        } else
+        {
+            return baseTypeToSubTypesMap.get(baseType);
+        }
     }
 
     private static Map<Class<?>, Set<NamedType>> createBaseTypeToSubTypesMap(String prefix)
@@ -80,13 +89,26 @@ public class JsonReflectionsBaseTypeToSubTypesMapping implements IJsonBaseTypeTo
         return subTypesMap;
     }
 
+    private static Set<NamedType> createAllSubTypesSet(
+            Map<Class<?>, Set<NamedType>> baseTypeToSubTypesMap)
+    {
+        Set<NamedType> allSubTypes = new HashSet<NamedType>();
+        for (Set<NamedType> subTypes : baseTypeToSubTypesMap.values())
+        {
+            allSubTypes.addAll(subTypes);
+        }
+        return allSubTypes;
+    }
+
     public static final JsonReflectionsBaseTypeToSubTypesMapping getInstance()
     {
         synchronized (JsonReflectionsBaseTypeToSubTypesMapping.class)
         {
             if (instance == null)
             {
-                instance = new JsonReflectionsBaseTypeToSubTypesMapping(JsonConstants.getClassesPrefix());
+                instance =
+                        new JsonReflectionsBaseTypeToSubTypesMapping(
+                                JsonConstants.getClassesPrefix());
             }
             return instance;
         }
diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/JsonReflectionsTypeValueToClassObjectMapping.java b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/JsonReflectionsTypeValueToClassObjectMapping.java
deleted file mode 100644
index 67a1b3d601f..00000000000
--- a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/mapping/JsonReflectionsTypeValueToClassObjectMapping.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2012 ETH Zuerich, CISD
- *
- * Licensed 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 ch.systemsx.cisd.common.api.server.json.mapping;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import org.reflections.Reflections;
-
-import ch.systemsx.cisd.base.annotation.JsonObject;
-import ch.systemsx.cisd.common.api.server.json.common.JsonConstants;
-
-/**
- * @author pkupczyk
- */
-public class JsonReflectionsTypeValueToClassObjectMapping implements
-        IJsonTypeValueToClassObjectMapping
-{
-
-    private static JsonReflectionsTypeValueToClassObjectMapping instance;
-
-    private Map<String, Class<?>> typeToClassMap;
-
-    public JsonReflectionsTypeValueToClassObjectMapping(String prefix)
-    {
-        typeToClassMap = createTypeToClassMap(prefix);
-    }
-
-    @Override
-    public Class<?> getClass(String type)
-    {
-        return typeToClassMap.get(type);
-    }
-
-    private static Map<String, Class<?>> createTypeToClassMap(String prefix)
-    {
-        Reflections reflections = new Reflections(prefix);
-
-        Set<Class<?>> types = reflections.getTypesAnnotatedWith(JsonObject.class);
-        Map<String, Class<?>> typesMap = new HashMap<String, Class<?>>();
-
-        if (types != null)
-        {
-            for (Class<?> type : types)
-            {
-                JsonObject typeAnnotation = type.getAnnotation(JsonObject.class);
-                typesMap.put(typeAnnotation.value(), type);
-            }
-        }
-
-        return typesMap;
-    }
-
-    public static final JsonReflectionsTypeValueToClassObjectMapping getInstance()
-    {
-        synchronized (JsonReflectionsTypeValueToClassObjectMapping.class)
-        {
-            if (instance == null)
-            {
-                instance =
-                        new JsonReflectionsTypeValueToClassObjectMapping(
-                                JsonConstants.getClassesPrefix());
-            }
-            return instance;
-        }
-    }
-}
diff --git a/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/serializer/JsonSerializerFactory.java b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/serializer/JsonSerializerFactory.java
new file mode 100644
index 00000000000..667ee4e99c6
--- /dev/null
+++ b/openbis-common/source/java/ch/systemsx/cisd/common/api/server/json/serializer/JsonSerializerFactory.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed 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 ch.systemsx.cisd.common.api.server.json.serializer;
+
+import java.util.Collection;
+
+import org.codehaus.jackson.map.AnnotationIntrospector;
+import org.codehaus.jackson.map.BeanProperty;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.codehaus.jackson.map.TypeSerializer;
+import org.codehaus.jackson.map.introspect.AnnotatedClass;
+import org.codehaus.jackson.map.introspect.BasicBeanDescription;
+import org.codehaus.jackson.map.jsontype.NamedType;
+import org.codehaus.jackson.map.jsontype.TypeIdResolver;
+import org.codehaus.jackson.map.jsontype.impl.AsPropertyTypeSerializer;
+import org.codehaus.jackson.map.jsontype.impl.TypeNameIdResolver;
+import org.codehaus.jackson.map.ser.BeanSerializerFactory;
+import org.codehaus.jackson.map.type.ArrayType;
+import org.codehaus.jackson.map.type.CollectionLikeType;
+import org.codehaus.jackson.map.type.CollectionType;
+import org.codehaus.jackson.map.type.MapLikeType;
+import org.codehaus.jackson.map.type.MapType;
+import org.codehaus.jackson.type.JavaType;
+
+import ch.systemsx.cisd.base.annotation.JsonObject;
+import ch.systemsx.cisd.common.api.server.json.common.JsonConstants;
+
+/**
+ * @author pkupczyk
+ */
+public class JsonSerializerFactory extends BeanSerializerFactory
+{
+
+    public JsonSerializerFactory()
+    {
+        super(null);
+    }
+
+    @Override
+    protected JsonSerializer<?> buildArraySerializer(SerializationConfig config, ArrayType type,
+            BasicBeanDescription beanDesc, BeanProperty property, boolean staticTyping,
+            TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)
+    {
+        ArrayType newType =
+                type.withContentTypeHandler(createContentTypeSerializer(config, type, property));
+        return super.buildArraySerializer(config, newType, beanDesc, property, staticTyping,
+                elementTypeSerializer, elementValueSerializer);
+    }
+
+    @Override
+    protected JsonSerializer<?> buildCollectionSerializer(SerializationConfig config,
+            CollectionType type, BasicBeanDescription beanDesc, BeanProperty property,
+            boolean staticTyping, TypeSerializer elementTypeSerializer,
+            JsonSerializer<Object> elementValueSerializer)
+    {
+        CollectionType newType =
+                type.withContentTypeHandler(createContentTypeSerializer(config, type, property));
+        return super.buildCollectionSerializer(config, newType, beanDesc, property, staticTyping,
+                elementTypeSerializer, elementValueSerializer);
+    }
+
+    @Override
+    protected JsonSerializer<?> buildCollectionLikeSerializer(SerializationConfig config,
+            CollectionLikeType type, BasicBeanDescription beanDesc, BeanProperty property,
+            boolean staticTyping, TypeSerializer elementTypeSerializer,
+            JsonSerializer<Object> elementValueSerializer)
+    {
+        CollectionLikeType newType =
+                type.withContentTypeHandler(createContentTypeSerializer(config, type, property));
+        return super.buildCollectionLikeSerializer(config, newType, beanDesc, property,
+                staticTyping, elementTypeSerializer, elementValueSerializer);
+    }
+
+    @Override
+    protected JsonSerializer<?> buildMapSerializer(SerializationConfig config, MapType type,
+            BasicBeanDescription beanDesc, BeanProperty property, boolean staticTyping,
+            JsonSerializer<Object> keySerializer, TypeSerializer elementTypeSerializer,
+            JsonSerializer<Object> elementValueSerializer)
+    {
+        MapType newType =
+                type.withContentTypeHandler(createContentTypeSerializer(config, type, property));
+        return super.buildMapSerializer(config, newType, beanDesc, property, staticTyping,
+                keySerializer, elementTypeSerializer, elementValueSerializer);
+    }
+
+    @Override
+    protected JsonSerializer<?> buildMapLikeSerializer(SerializationConfig config,
+            MapLikeType type, BasicBeanDescription beanDesc, BeanProperty property,
+            boolean staticTyping, JsonSerializer<Object> keySerializer,
+            TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)
+    {
+        MapLikeType newType =
+                type.withContentTypeHandler(createContentTypeSerializer(config, type, property));
+        return super.buildMapLikeSerializer(config, newType, beanDesc, property, staticTyping,
+                keySerializer, elementTypeSerializer, elementValueSerializer);
+    }
+
+    private TypeSerializer createContentTypeSerializer(SerializationConfig config,
+            JavaType containerType, BeanProperty property)
+    {
+        JavaType contentType = containerType.getContentType();
+
+        if (contentType == null || contentType.getRawClass() == null)
+        {
+            return null;
+        }
+
+        Class<?> contentClass = contentType.getRawClass();
+
+        if (contentClass.equals(Object.class) || contentClass.isAnnotationPresent(JsonObject.class))
+        {
+            BasicBeanDescription bean =
+                    config.introspectClassAnnotations(contentType.getRawClass());
+            AnnotatedClass ac = bean.getClassInfo();
+            AnnotationIntrospector ai = config.getAnnotationIntrospector();
+            Collection<NamedType> subtypes =
+                    config.getSubtypeResolver().collectAndResolveSubtypes(ac, config, ai);
+            TypeIdResolver resolver =
+                    TypeNameIdResolver.construct(config, contentType, subtypes, true, false);
+            return new AsPropertyTypeSerializer(resolver, property, JsonConstants.getTypeField());
+        } else
+        {
+            return null;
+        }
+    }
+
+}
diff --git a/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/JsonDeserializationTest.java b/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/JsonDeserializationTest.java
index 134eec9c6b2..b9327ad5294 100644
--- a/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/JsonDeserializationTest.java
+++ b/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/JsonDeserializationTest.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.common.api.server.json;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumMap;
@@ -1063,7 +1064,7 @@ public class JsonDeserializationTest
 
         Collection collection = new ArrayList(map.values());
         List list = new ArrayList(map.values());
-        // Object[] array = map.values().toArray(new Object[map.size()]);
+        Object[] array = map.values().toArray(new Object[map.size()]);
 
         Map specificMap = new LinkedHashMap();
         specificMap.put("itemWithKnownType", createObjectWithKnownType());
@@ -1071,7 +1072,7 @@ public class JsonDeserializationTest
 
         Collection specificCollection = new ArrayList(specificMap.values());
         List specificList = new ArrayList(specificMap.values());
-        // Object[] specificArray = specificMap.values().toArray(new Object[specificMap.size()]);
+        Object[] specificArray = specificMap.values().toArray(new Object[specificMap.size()]);
 
         Map<String, Object> object = new HashMap<String, Object>();
 
@@ -1080,16 +1081,28 @@ public class JsonDeserializationTest
         object.put("collectionWithObjectType", collection);
         object.put("collectionWithSpecificType", specificCollection);
 
+        object.put("linkedHashSetWithoutType", collection);
+        object.put("linkedHashSetWithObjectType", collection);
+        object.put("linkedHashSetWithSpecificType", specificCollection);
+
         object.put("mapWithoutType", map);
         object.put("mapWithObjectType", map);
         object.put("mapWithSpecificType", specificMap);
 
+        object.put("linkedHashMapWithoutType", map);
+        object.put("linkedHashMapWithObjectType", map);
+        object.put("linkedHashMapWithSpecificType", specificMap);
+
         object.put("listWithoutType", list);
         object.put("listWithObjectType", list);
         object.put("listWithSpecificType", specificList);
 
-        // object.put("arrayWithObjectType", array);
-        // object.put("arrayWithSpecificType", specificArray);
+        object.put("linkedListWithoutType", list);
+        object.put("linkedListWithObjectType", list);
+        object.put("linkedListWithSpecificType", specificList);
+
+        object.put("arrayWithObjectType", array);
+        object.put("arrayWithSpecificType", specificArray);
 
         return object;
     }
@@ -1098,17 +1111,33 @@ public class JsonDeserializationTest
     {
         Assert.assertEquals(object.getClass(), ObjectWithContainerTypes.class);
         ObjectWithContainerTypes objectWithContainers = (ObjectWithContainerTypes) object;
+
         assertObjectsCollection(objectWithContainers.collectionWithObjectType);
         assertObjectsCollection(objectWithContainers.collectionWithoutType);
         assertObjectsSpecificCollection(objectWithContainers.collectionWithSpecificType);
+
+        assertObjectsCollection(objectWithContainers.linkedHashSetWithObjectType);
+        assertObjectsCollection(objectWithContainers.linkedHashSetWithoutType);
+        assertObjectsSpecificCollection(objectWithContainers.linkedHashSetWithSpecificType);
+
         assertObjectsMap(objectWithContainers.mapWithObjectType);
         assertObjectsMap(objectWithContainers.mapWithoutType);
         assertObjectsSpecificMap(objectWithContainers.mapWithSpecificType);
+
+        assertObjectsMap(objectWithContainers.linkedHashMapWithObjectType);
+        assertObjectsMap(objectWithContainers.linkedHashMapWithoutType);
+        assertObjectsSpecificMap(objectWithContainers.linkedHashMapWithSpecificType);
+
         assertObjectsCollection(objectWithContainers.listWithObjectType);
         assertObjectsCollection(objectWithContainers.listWithoutType);
         assertObjectsSpecificCollection(objectWithContainers.listWithSpecificType);
-        // assertObjectsArray(objectWithContainers.arrayWithObjectType);
-        // assertObjectsSpecificArray(objectWithContainers.arrayWithSpecificType);
+
+        assertObjectsCollection(objectWithContainers.linkedListWithObjectType);
+        assertObjectsCollection(objectWithContainers.linkedListWithoutType);
+        assertObjectsSpecificCollection(objectWithContainers.linkedListWithSpecificType);
+
+        assertObjectsArray(objectWithContainers.arrayWithObjectType);
+        assertObjectsSpecificArray(objectWithContainers.arrayWithSpecificType);
     }
 
     @SuppressWarnings(
@@ -1169,15 +1198,15 @@ public class JsonDeserializationTest
         assertObjectWithKnownUniqueClass(map.get("itemWithKnownUniqueClass"));
     }
 
-    // private void assertObjectsArray(Object[] array)
-    // {
-    // assertObjectsCollection(Arrays.asList(array));
-    // }
+    private void assertObjectsArray(Object[] array)
+    {
+        assertObjectsCollection(Arrays.asList(array));
+    }
 
-    // private void assertObjectsSpecificArray(Object[] array)
-    // {
-    // assertObjectsSpecificCollection(Arrays.asList(array));
-    // }
+    private void assertObjectsSpecificArray(Object[] array)
+    {
+        assertObjectsSpecificCollection(Arrays.asList(array));
+    }
 
     @SuppressWarnings("unchecked")
     private <T> T deserialize(Object object, Class<?> rootClass) throws Exception
diff --git a/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/JsonTestObjectMapper.java b/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/JsonTestObjectMapper.java
index 4aaec7ed0fb..80beb5f5873 100644
--- a/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/JsonTestObjectMapper.java
+++ b/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/JsonTestObjectMapper.java
@@ -18,10 +18,10 @@ package ch.systemsx.cisd.common.api.server.json;
 
 import org.codehaus.jackson.map.ObjectMapper;
 
+import ch.systemsx.cisd.common.api.server.json.deserializer.JsonDeserializerFactory;
 import ch.systemsx.cisd.common.api.server.json.deserializer.JsonDeserializerProvider;
 import ch.systemsx.cisd.common.api.server.json.introspector.JsonTypeAndClassAnnotationIntrospector;
 import ch.systemsx.cisd.common.api.server.json.mapping.JsonReflectionsBaseTypeToSubTypesMapping;
-import ch.systemsx.cisd.common.api.server.json.mapping.JsonReflectionsTypeValueToClassObjectMapping;
 import ch.systemsx.cisd.common.api.server.json.mapping.JsonStaticClassValueToClassObjectsMapping;
 import ch.systemsx.cisd.common.api.server.json.object.ObjectWithContainerTypes;
 import ch.systemsx.cisd.common.api.server.json.object.ObjectWithDateTypes;
@@ -41,6 +41,7 @@ import ch.systemsx.cisd.common.api.server.json.object.ObjectWithTypeB;
 import ch.systemsx.cisd.common.api.server.json.object.ObjectWithTypeBIllegalDuplicate;
 import ch.systemsx.cisd.common.api.server.json.object.ObjectWithTypeButNoSubtypes;
 import ch.systemsx.cisd.common.api.server.json.resolver.JsonReflectionsSubTypeResolver;
+import ch.systemsx.cisd.common.api.server.json.serializer.JsonSerializerFactory;
 
 /**
  * @author pkupczyk
@@ -50,9 +51,6 @@ public class JsonTestObjectMapper extends ObjectMapper
 
     public JsonTestObjectMapper()
     {
-        JsonReflectionsTypeValueToClassObjectMapping typeMapping =
-                new JsonReflectionsTypeValueToClassObjectMapping(getClass().getPackage().getName());
-
         JsonReflectionsBaseTypeToSubTypesMapping subTypesMapping =
                 new JsonReflectionsBaseTypeToSubTypesMapping(getClass().getPackage().getName());
 
@@ -82,7 +80,9 @@ public class JsonTestObjectMapper extends ObjectMapper
 
         setAnnotationIntrospector(new JsonTypeAndClassAnnotationIntrospector(classMapping));
         setSubtypeResolver(new JsonReflectionsSubTypeResolver(subTypesMapping));
-        setDeserializerProvider(new JsonDeserializerProvider(typeMapping, classMapping));
+        setDeserializerProvider(new JsonDeserializerProvider(new JsonDeserializerFactory(
+                classMapping)));
+        setSerializerFactory(new JsonSerializerFactory());
     }
 
 }
diff --git a/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/object/ObjectWithContainerTypes.java b/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/object/ObjectWithContainerTypes.java
index 75272f60e3b..76dcd06977c 100644
--- a/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/object/ObjectWithContainerTypes.java
+++ b/openbis-common/sourceTest/java/ch/systemsx/cisd/common/api/server/json/object/ObjectWithContainerTypes.java
@@ -17,6 +17,8 @@
 package ch.systemsx.cisd.common.api.server.json.object;
 
 import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -37,22 +39,38 @@ public class ObjectWithContainerTypes
 
     public Collection<ObjectWithType> collectionWithSpecificType;
 
+    public LinkedHashSet linkedHashSetWithoutType;
+
+    public Collection<Object> linkedHashSetWithObjectType;
+
+    public Collection<ObjectWithType> linkedHashSetWithSpecificType;
+
     public List listWithoutType;
 
     public List<Object> listWithObjectType;
 
     public List<ObjectWithType> listWithSpecificType;
 
+    public LinkedList linkedListWithoutType;
+
+    public LinkedList<Object> linkedListWithObjectType;
+
+    public LinkedList<ObjectWithType> linkedListWithSpecificType;
+
     public Map mapWithoutType;
 
     public Map<String, Object> mapWithObjectType;
 
     public Map<String, ObjectWithType> mapWithSpecificType;
 
-    // TODO: check why it doesn't work properly during both serialization and deserialization
+    public Map linkedHashMapWithoutType;
+
+    public Map<String, Object> linkedHashMapWithObjectType;
+
+    public Map<String, ObjectWithType> linkedHashMapWithSpecificType;
 
-    // public Object[] arrayWithObjectType;
+    public Object[] arrayWithObjectType;
 
-    // public ObjectWithType[] arrayWithSpecificType;
+    public ObjectWithType[] arrayWithSpecificType;
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/json/GenericObjectMapper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/json/GenericObjectMapper.java
index 323927d12c5..b419b9beee4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/json/GenericObjectMapper.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/json/GenericObjectMapper.java
@@ -18,11 +18,12 @@ package ch.systemsx.cisd.openbis.generic.shared.api.json;
 
 import org.codehaus.jackson.map.ObjectMapper;
 
+import ch.systemsx.cisd.common.api.server.json.deserializer.JsonDeserializerFactory;
 import ch.systemsx.cisd.common.api.server.json.deserializer.JsonDeserializerProvider;
 import ch.systemsx.cisd.common.api.server.json.introspector.JsonTypeAndClassAnnotationIntrospector;
 import ch.systemsx.cisd.common.api.server.json.mapping.JsonReflectionsBaseTypeToSubTypesMapping;
-import ch.systemsx.cisd.common.api.server.json.mapping.JsonReflectionsTypeValueToClassObjectMapping;
 import ch.systemsx.cisd.common.api.server.json.resolver.JsonReflectionsSubTypeResolver;
+import ch.systemsx.cisd.common.api.server.json.serializer.JsonSerializerFactory;
 
 /**
  * Jackson library object mapper used in generic OpenBIS.
@@ -38,9 +39,8 @@ public class GenericObjectMapper extends ObjectMapper
                 GenericJsonClassValueToClassObjectsMapping.getInstance()));
         setSubtypeResolver(new JsonReflectionsSubTypeResolver(
                 JsonReflectionsBaseTypeToSubTypesMapping.getInstance()));
-        setDeserializerProvider(new JsonDeserializerProvider(
-                JsonReflectionsTypeValueToClassObjectMapping.getInstance(),
-                GenericJsonClassValueToClassObjectsMapping.getInstance()));
+        setDeserializerProvider(new JsonDeserializerProvider(new JsonDeserializerFactory(
+                GenericJsonClassValueToClassObjectsMapping.getInstance())));
+        setSerializerFactory(new JsonSerializerFactory());
     }
-
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/json/ScreeningObjectMapper.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/json/ScreeningObjectMapper.java
index 8be41e89ed2..13c9b638c3d 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/json/ScreeningObjectMapper.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/json/ScreeningObjectMapper.java
@@ -18,11 +18,13 @@ package ch.systemsx.cisd.openbis.plugin.screening.shared.api.json;
 
 import org.codehaus.jackson.map.ObjectMapper;
 
+import ch.systemsx.cisd.common.api.server.json.deserializer.JsonDeserializerFactory;
 import ch.systemsx.cisd.common.api.server.json.deserializer.JsonDeserializerProvider;
 import ch.systemsx.cisd.common.api.server.json.introspector.JsonTypeAndClassAnnotationIntrospector;
 import ch.systemsx.cisd.common.api.server.json.mapping.JsonReflectionsBaseTypeToSubTypesMapping;
-import ch.systemsx.cisd.common.api.server.json.mapping.JsonReflectionsTypeValueToClassObjectMapping;
 import ch.systemsx.cisd.common.api.server.json.resolver.JsonReflectionsSubTypeResolver;
+import ch.systemsx.cisd.common.api.server.json.serializer.JsonSerializerFactory;
+import ch.systemsx.cisd.openbis.generic.shared.api.json.GenericJsonClassValueToClassObjectsMapping;
 
 /**
  * Jackson library object mapper used in screening OpenBIS.
@@ -38,9 +40,9 @@ public class ScreeningObjectMapper extends ObjectMapper
                 ScreeningJsonClassValueToClassObjectsMapping.getInstance()));
         setSubtypeResolver(new JsonReflectionsSubTypeResolver(
                 JsonReflectionsBaseTypeToSubTypesMapping.getInstance()));
-        setDeserializerProvider(new JsonDeserializerProvider(
-                JsonReflectionsTypeValueToClassObjectMapping.getInstance(),
-                ScreeningJsonClassValueToClassObjectsMapping.getInstance()));
+        setDeserializerProvider(new JsonDeserializerProvider(new JsonDeserializerFactory(
+                GenericJsonClassValueToClassObjectsMapping.getInstance())));
+        setSerializerFactory(new JsonSerializerFactory());
     }
 
 }
-- 
GitLab