Java - recursivamente modificar valores de objetos com reflexão

Stanos:

Eu gostaria de transformar cada propriedade String de um Objeto (junto com seus objetos aninhados) e estou usando o seguinte método recursivo para conseguir isso com reflexão API:

    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);

Até este ponto todos os fina funciona e se eu executar este, em seguida, todos os valores de cadeia de caracteres são acrescentados com "blabla" no final. Problema vem se PrintObject tem outras estruturas de dados, como Lista ou Mapa. Por exemplo, se há um outro campo na classe PrintObject:

private List<String> field5;

então esta execução de código jogaria 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);

Qualquer ideia sobre como fazer este trabalho com essas estruturas também? Desde já, obrigado.

Field5 também poderia ser, por exemplo:

 Map<String,String>

ou mesmo

 List<List<String>>
Matt Campeão:

ArrayListcontém um long serialVersionUIDcampo para ajudar com a serialização. Quando você começa o valor que ele retorna um boxed Long. Chamar getDeclaredFieldsem Longretornos uma matriz que contém o domínio Long.MIN_VALUEque é uma Long. É aí que o loop infinito vem.

Para resolver isso eu acrescentaria um tratamento especial caso para Longcomo você faz para Integer. Você também deve considerar todos os outros primitivos encaixotados como Floate Byte.

Colecções será suportado quer por estruturas que se referem a cada outra ligação LinkedListou através de matrizes. Para estruturas ligadas o código seria atravessá-los. Para variedade apoio backed coletadas você precisa identificar quais campos são matrizes e interagir sobre eles.

O tipo de um campo e ser obtido com Field.getType . Arrays podem ser identificados por Class.isArray . Arrays de tipos diferentes têm tipos diferentes, eles não são não-reificada como genéricos Java. Matrizes de valores não-primitivos pode ser convertido para Object[]que seja útil, neste caso, mas é não tipo seguro . Para obter o tipo de objeto na matriz Class.getComponentType pode ser usado.

Algo como o seguinte seria necessário para recurse nas entradas de uma matriz.

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

O outro problema é referências cíclicas que poderiam causar ainda mais StackOverflowException. Se uma lista foi adicionado como um membro para si seria recorrerá infinitamente. É necessário rastrear objeto visitado anteriormente e não visitá-los duas vezes. Idealmente, isso seria usar um IdentityHashMapcomo você se preocupa com instâncias de objetos não sua igualdade.

Acho que você gosta

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