class ObjectBuilder {

    @SuppressWarnings("unchecked")
    public static <T extends Collection<?>> T createCollection(Class<T> collectionClass, Type genericType, JsonValue jsonArray)
            throws JsonException {
        if (jsonArray == null || jsonArray.isNull()) {
            return null;
        }
        Class elementClass;
        Type elementType;
        if (genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType)genericType;
            elementType = parameterizedType.getActualTypeArguments()[0];
            if (elementType instanceof Class) {
                elementClass = (Class)elementType;
            } else if (elementType instanceof ParameterizedType) {
                elementClass = (Class)((ParameterizedType)elementType).getRawType();
            } else {
                throw new JsonException(String.format(
                        "This type of Collection can't be restored from JSON source.\nCollection is parameterized by wrong Type: %s",
                        parameterizedType));
            }
        } else {
            throw new JsonException("Collection is not parameterized. Collection<?> is not supported");
        }

        Constructor<? extends T> constructor;
        if (collectionClass.isInterface() || Modifier.isAbstract(collectionClass.getModifiers())) {
            constructor = getConstructor(findAcceptableCollectionImplementation(collectionClass), Collection.class);
        } else {
            constructor = getConstructor(collectionClass, Collection.class);
        }

        ArrayList<Object> sourceCollection = new ArrayList<>(jsonArray.size());
        Iterator<JsonValue> values = jsonArray.getElements();
        Types jsonElementType = getType(elementClass);
        while (values.hasNext()) {
            JsonValue value = values.next();
            if (jsonElementType == null) {
                sourceCollection.add(createObject(elementClass, value));
            } else {
                switch (jsonElementType) {
                    case BYTE:
                    case SHORT:
                    case INT:
                    case LONG:
                    case FLOAT:
                    case DOUBLE:
                    case BOOLEAN:
                    case CHAR:
                    case STRING:
                    case NULL:
                    case ARRAY_BYTE:
                    case ARRAY_SHORT:
                    case ARRAY_INT:
                    case ARRAY_LONG:
                    case ARRAY_FLOAT:
                    case ARRAY_DOUBLE:
                    case ARRAY_BOOLEAN:
                    case ARRAY_CHAR:
                    case ARRAY_STRING:
                    case CLASS:
                        sourceCollection.add(createObjectKnownTypes(elementClass, value));
                        break;
                    case ARRAY_OBJECT:
                        sourceCollection.add(createArray(elementClass, value));
                        break;
                    case COLLECTION:
                        sourceCollection.add(createCollection(elementClass, elementType, value));
                        break;
                    case MAP:
                        sourceCollection.add(createObject(elementClass, elementType, value));
                        break;
                    case ENUM:
                        sourceCollection.add(createEnum(elementClass, value));
                        break;
                }
            }
        }
        try {
            return constructor.newInstance(sourceCollection);
        } catch (Exception e) {
            throw new JsonException(e.getMessage(), e);
        }
    }

    private  ObjectBuilder();

}