mercredi 1 juillet 2020

How can i deserialize complex List like List

I don't know if it clear for you, i want to implement a method that like SpringMVC @RequestBody() do, this method can deserialize input json string to object, and this method should support complex object type(like List<List>)

Now using Java reflection and Jackson, we can easily deserialize List, such as "[1,100]" to List, but if the input is "[[1,100]]", there is nested list in another list.

Show my code:

// there is a class and method's parameter has annotation @Param
class Code{
    public void getName(@Param("fooList") List<List<Long>> fooList) {
        System.out.println("getName run");
    }
}


// reflection Code#getName and deserialize method
public Object inject(Parameter param) {
    Object object = null;
    try {
        Class<?> paramType = param.getType();
        Param paramAnnotation = param.getAnnotation(Param.class);
        // for unit test purpose, hard code json string here
        object = "[[1,3]]";
        if (object != null) {
            if (Collection.class == paramType || List.class.isAssignableFrom(paramType)) {
                // basic type

                if (clazz != null) {
                    // todo: string to list, need support complex List
                    try {
                        ObjectMapper objectMapper = new ObjectMapper();
                        return objectMapper.readValue(text,
                                objectMapper.getTypeFactory().constructCollectionType(List.class,
                                        clazz));
                    } catch (Exception e) {
                        throw new SDKException("");
                    }
                    List list = JSONs.toList(object.toString(), clazz);
                    List converterArgs = new ArrayList<>(list.size());
                    for (Object arg : list) {
                        try {
                            arg = Casts.cast(clazz, arg);
                        } catch (Exception e) {
                            throw new InvalidParametersException("type error");
                        }
                        converterArgs.add(arg);
                    }
                    object = converterArgs;
                }
            }
            if (String.class.isAssignableFrom(paramType)) {
                object = JSONs.string(object);
            } else {
                if (!object.getClass().equals(paramType)) {
                    try {
                        object = Casts.cast(paramType, object);
                    } catch (Exception e) {
                        throw new InvalidParametersException("type error");
                    }
                }
            }
        }
    } catch (Exception e) {
        throw new SDKException("", e);
    }
    return object;
}




@Test
public void testReflection() {
    try {
        Method getName = Code.class.getMethod("getName", List.class);
        Parameter[] parameters = getName.getParameters();
        AnnotationParamInjector injector = new AnnotationParamInjector();
        Object inject = injector.inject(parameters[0]);
        System.out.println("inject = " + inject);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
}

Backgroud: i want to implement method like SpringMVC controller, so we need to deserialize method parameter to object, now we only support normal class and List but don't support complex List.

Questions: Java reflection can parse generic class, even complex List, we can get reflect List from outer to inner, but how can i parse json string "[[1, 100]]", this is what i'm solving.

Show my pseudocode as below, recursive call constructClass to get it's generic row type, after call constructClass(), the json string should be parse, such as "[[1,100]]" change to "[1,100]", and good solution to do this?

public void constructClass(String text, Class<?> clazz) {
    Type type = clazz.getGenericSuperclass();
    if (Collection.class == clazz || List.class.isAssignableFrom(clazz)) {
        if (type instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) type;
            Type genericType = pType.getActualTypeArguments()[0];
            this.constructClass(text, genericType.getClass());
        }
    } else if (Map.class == clazz) {

    } else {

    }
    if (type instanceof ParameterizedType) {
        ParameterizedType pType = (ParameterizedType) type;
        pType.getActualTypeArguments()[0]
    }
}




Aucun commentaire:

Enregistrer un commentaire