1
resposta

Como alterar do uso de Class PersonDTO para Record PersonDTO?

Ao invés de usar uma classe para representar meu PersonDTO, gostaria de usar um record, porém não estou conseguindo fazer isso. Como posso fazer essa alteração?

package br.com.alura.refl;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

public class DTOConverter {

    public <I, O> O transform(I input, Class<O> target) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<?> source = input.getClass();

        O instanceOfTarget = target.getDeclaredConstructor().newInstance();

        Field[] sourceFields = source.getDeclaredFields();
        Field[] targetFields = target.getDeclaredFields();

        Arrays.stream(sourceFields)
                .forEach(sourceField ->
                        Arrays.stream(targetFields)
                                .forEach(targetField -> {
                                            validate(sourceField, targetField);
                                            try {
                                                targetField.set(instanceOfTarget, sourceField.get(input));
                                            } catch (IllegalAccessException e) {
                                                throw new RuntimeException(e);
                                            }
                                        }
                                )
                );

        return instanceOfTarget;
    }

    private void validate(Field sourceField, Field targetField) {
        if (sourceField.getName().equals(targetField.getName()) && sourceField.getType().equals(targetField.getType())) {
            sourceField.setAccessible(true);
            targetField.setAccessible(true);
        }
    }

}

package br.com.alura.model;

public record PersonDTO(String name, String cpf) {

}
1 resposta

Oi Marcelo, tudo joia?

Para fazer isso você precisará ajustar como está instanciando e preenchendo os campos do objeto de destino no seu método transform. Mas, como os records em Java são imutáveis e não possuem um construtor padrão sem argumentos, você precisará usar o construtor completo do record para criar uma nova instância.

Aqui está uma forma de adaptar seu código para trabalhar com records:

package br.com.alura.refl;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class DTOConverter {

    public <I, O> O transform(I input, Class<O> target) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<?> source = input.getClass();

        Field[] sourceFields = source.getDeclaredFields();
        Field[] targetFields = target.getDeclaredFields();

        Map<String, Object> fieldValues = new HashMap<>();

        Arrays.stream(sourceFields)
                .forEach(sourceField -> {
                    Arrays.stream(targetFields)
                            .forEach(targetField -> {
                                        validate(sourceField, targetField);
                                        try {
                                            fieldValues.put(targetField.getName(), sourceField.get(input));
                                        } catch (IllegalAccessException e) {
                                            throw new RuntimeException(e);
                                        }
                                    }
                            );
                });

        Constructor<O> constructor = target.getDeclaredConstructor(
                Arrays.stream(targetFields)
                        .map(Field::getType)
                        .toArray(Class[]::new)
        );

        return constructor.newInstance(
                Arrays.stream(targetFields)
                        .map(field -> fieldValues.get(field.getName()))
                        .toArray()
        );
    }

    private void validate(Field sourceField, Field targetField) {
        if (sourceField.getName().equals(targetField.getName()) && sourceField.getType().equals(targetField.getType())) {
            sourceField.setAccessible(true);
            targetField.setAccessible(true);
        }
    }
}

Com essa abordagem, você está coletando os valores dos campos do objeto de origem em um Map e, em seguida, usando esses valores para chamar o construtor do record.

Aqui está como seu PersonDTO ficaria como um record:

package br.com.alura.model;

public record PersonDTO(String name, String cpf) {
}

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.