Используя Reflection
, вы можете:
- Вызвать
static
newBuilder
метод для создания построителя. - Найти все
fields
/ setters
для данного POJO
учебный класс. Если во всех случаях setters
в компоновщике и setters
в POJO
имеют одно и то же имя, как в вашем примере, преобразование должно быть простым. - Вызов
build
в экземпляре компоновщика для создания нового POJO
.
При использовании basi c Java
Reflection
и Stream
API
-s это может выглядеть следующим образом:
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Properties;
import java.util.StringJoiner;
import java.util.function.Function;
import java.util.stream.Stream;
public class ReflectionApp {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.put("name", "John");
properties.put("date", "today");
AvroPropertie manualInstance = AvroPropertie.newBuilder()
.setName(properties.getProperty("name"))
.setDate(properties.getProperty("date"))
.build();
Object dynamicInstance = AvroAutoCoder.createAndSet(AvroPropertie.class, properties::getProperty);
System.out.println(manualInstance);
System.out.println(dynamicInstance);
System.out.println("manualInstance == dynamicInstance => " + manualInstance.equals(dynamicInstance));
}
}
class AvroAutoCoder {
public static Object createAndSet(Class clazz, Function<String, String> dataSupplier) throws Exception {
Object builderInstance = findMethod(clazz, "newBuilder")
.invoke(null);
Class<?> builderClass = builderInstance.getClass();
getSetters(clazz).forEach(setter -> {
try {
String fieldName = setter.getName().substring(3).toLowerCase();
findMethod(builderClass, setter.getName())
.invoke(builderInstance, dataSupplier.apply(fieldName));
} catch (Exception e) {
throw new IllegalStateException(e);
}
});
return findMethod(builderClass, "build")
.invoke(builderInstance);
}
private static Method findMethod(Class clazz, String methodName) {
return Arrays.stream(clazz.getDeclaredMethods())
.filter(method -> method.getName().equals(methodName))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}
private static Stream<Method> getSetters(Class clazz) {
return Arrays.stream(clazz.getDeclaredMethods())
.filter(method -> method.getParameterCount() == 1 && method.getReturnType() == Void.TYPE)
.filter(method -> method.getName().startsWith("set"));
}
}
Над отпечатками кода:
AvroPropertie[name='John', date='today']
AvroPropertie[name='John', date='today']
manualInstance == dynamicInstance => true
Комментарий, добавленный автором вопроса:
В этом конкретном c примере класса APropertie
есть внутренний класс c с именем Builder
, который содержит искомый сеттера. В этом случае методы getSetters()
нужно немного изменить:
// Find all setter of class
private static Stream<Method> getSetters2(Class clazz) {
Optional<Class> first = Arrays.stream(clazz.getDeclaredClasses())
.findFirst();
return Arrays.stream(first.get().getDeclaredMethods())
.filter(method -> method.getName().startsWith("set"));
}