Java - recursiva modificar valores de los objetos con la reflexión

Stanos:

Me gustaría transformar cada propiedad String de un objeto (junto con sus objetos anidados) y estoy usando el siguiente método recursivo para lograr que con la API de reflexión:

    public static void reflect(Object obj) {
        if (obj == null) {
            return;
        }
        Class klazz = obj.getClass();
        if (klazz.isPrimitive()
                || obj instanceof Integer
                || obj instanceof Double
                || obj instanceof Boolean)
            return;
        else {
            try {
                for (Field field : klazz.getDeclaredFields()) {
                    field.setAccessible(true);
                    Object f = field.get(obj);
                    if(f instanceof String) {
                        f = transform(f);
                        field.set(obj, f);
                    }
                    else {
                        reflect(f);
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
        }
    }

    private static Object transform(Object f) {
        f = f + "blabla";
        return f;
    }


@Data
@Builder
public class PrintObject {
    private String field1;
    private String field2;
    private String field3;
    private NestedObject field4;
}

@Data
@Builder
public class NestedObject {
    private String field1;
    private String field2;
    private Integer field3;
}

NestedObject nestedObject = NestedObject
                .builder()
                .field1("test")
                .field2("test2")
                .field3(1)
                .build();

PrintObject printObject = PrintObject
      .builder()
      .field1("test")
      .field2("Test")
      .field3("test")
      .field4(nestedObject)
      .build();

Utils.reflect(printObject);

Hasta este punto, todos los trabajos muy bien y si yo haga esto, entonces todos los valores de cadena se añade "blabla" al final. El problema viene si PrintObject tiene otras estructuras de datos como lista o mapa. Por ejemplo, si hay otro campo en la clase PrintObject:

private List<String> field5;

entonces esto ejecución de código tiraría StackOverflowError.

List<String> list = new ArrayList<>();
list.add("test");

NestedObject nestedObject = NestedObject
                .builder()
                .field1("test")
                .field2("test2")
                .field3(1)
                .build();

PrintObject printObject = PrintObject
      .builder()
      .field1("test")
      .field2("Test")
      .field3("test")
      .field4(nestedObject)
      .field5(list)
      .build();

Utils.reflect(printObject);

Alguna idea sobre cómo hacer este trabajo con estas estructuras, así? Gracias por adelantado.

Field5 también podría ser por ejemplo:

 Map<String,String>

o incluso

 List<List<String>>
Matt Campeón:

ArrayListcontiene un long serialVersionUIDcampo para ayudar con la serialización. Cuando se obtiene el valor que devuelve una caja Long. Llamada getDeclaredFieldsen Longdevuelve una matriz que contiene el campo Long.MIN_VALUEque es una Long. Ahí es donde el bucle infinito viene.

Para resolverlo yo añadiría un manejo especial para el caso Longcomo lo hace para Integer. También debe considerar todas las otras primitivas como en caja Floaty Byte.

Colecciones serán respaldados, ya sea por las estructuras que se refieren el uno al otro enlace LinkedListo mediante matrices. Para estructuras vinculadas el código atravesaría ellos. Con el respaldo de matriz recoge el apoyo que necesita para identificar qué campos son matrices e iterar sobre ellos.

El tipo de un campo y se obtiene con Field.getType . Las matrices pueden ser identificados por Class.isArray . Las matrices para diferentes tipos tienen diferentes tipos, no son no materializadas como genéricos de Java. Matrices de valores no primitivos se puede convertir a Object[]que es útil en este caso, pero que es no un tipo seguro . Para obtener el tipo de objeto de la matriz Class.getComponentType se puede utilizar.

Se necesitaría algo como lo siguiente a recursiva en las entradas de una matriz.

final Class<?> fieldType = field.getType();
if (fieldType.isArray() && !fieldType.getComponentType().isPrimitive()) {
    Object[] fs = (Object[]) f;
    for (Object fi : fs) {
        reflect(fi);
    }
}

El otro problema es referencias cíclicos que podrían causar aún más StackOverflowException. Si una lista se agrega como miembro a sí mismo sería infinitamente recursiva. Es necesario realizar un seguimiento de objetos visitado previamente y no visitar dos veces. Lo ideal sería utilizar una IdentityHashMapmedida que se preocupan por las instancias de objetos no su igualdad.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=215103&siteId=1
Recomendado
Clasificación