Notes:
- It is far from optimal.
- Circular reference problem is not considered.
Given your model it would return a list with this elements:
- title
- author.name
- author.age
Usage:
ClassMetadataService cms = new ClassMetadataService();
List<String> properties = cms.getProperties(Book.class);
Class definition:
package io.metadata;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class ClassMetadataService {
public List<String> getProperties(Class clazz) {
List<String> properties = new ArrayList<>();
this.collectProperties(new ArrayList<>(), clazz, properties);
return properties;
}
private void collectProperties(List<String> pathNodes, Class clazz, List<String> properties) {
for (Field field : clazz.getDeclaredFields()) {
List<String> localPathNodes = new ArrayList<>(pathNodes);
localPathNodes.add(field.getName());
if (clazz.isPrimitive() || isJavaClass(field.getType())) {
properties.add(localPathNodes.stream().collect(Collectors.joining(".")));
} else {
collectProperties(localPathNodes, field.getType(), properties);
}
}
}
private Boolean isJavaClass(Class clazz) {
List<Class> javaClass = Arrays.asList(
// ....
Boolean.class,
Byte.class,
Short.class,
Integer.class,
Long.class,
Float.class,
Double.class,
BigDecimal.class,
BigInteger.class,
Character.class,
String.class,
LocalDate.class,
LocalDateTime.class
// ....
);
return javaClass.stream().anyMatch(jc -> jc.equals(clazz));
}
}