com.alon.spring.crud.api.projection.RepresentationService Maven / Gradle / Ivy
package com.alon.spring.crud.api.projection;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.*;
import static java.util.stream.Collectors.toMap;
@Service
public class RepresentationService {
private static final List FINAL_TYPES = List.of(
Character.class, char.class,
CharSequence.class,
String.class,
Integer.class, int.class,
Short.class, short.class,
Long.class, long.class,
Float.class, float.class,
Double.class, double.class,
BigDecimal.class,
Boolean.class, boolean.class,
Byte.class, byte.class);
private List typeMappers;
public RepresentationService(List typeMappers) {
this.typeMappers = typeMappers;
}
public Map getRepresentationOf(Class clazz) {
List fields = List.of(clazz.getDeclaredFields());
List parents = new ArrayList<>();
parents.add(clazz);
return Map.of(getTypeName(clazz), mapFields(fields, parents));
}
private Map mapFields(List fields, List parents) {
return fields.stream()
.collect(toMap(this::getFieldName, field -> mapField(field, parents)));
}
private Object mapField(Field field, List parents) {
if (isFinalType(field)) {
if (isArray(field))
return field.getType().getComponentType().getSimpleName().toLowerCase();
return field.getType().getSimpleName().toLowerCase();
} else if (hasMapper(field)) {
return getMapper(field).map();
} else if (isCollection(field)) {
return mapCollection(field, parents);
} else if (parents.contains(field.getType())) {
return getTypeName(field.getType());
}
parents.add(field.getType());
List fields;
if (isArray(field))
fields = List.of(field.getType().getComponentType().getDeclaredFields());
else
fields = List.of(field.getType().getDeclaredFields());
return Map.of(getTypeName(field.getType()), mapFields(fields, parents));
}
private Object mapCollection(Field field, List parents) {
ParameterizedType type = (ParameterizedType) field.getGenericType();
Class collectionItemsType = (Class) type.getActualTypeArguments()[0];
if (isFinalType(collectionItemsType))
return collectionItemsType.getSimpleName().toLowerCase();
else if (parents.contains(collectionItemsType))
return getTypeName(collectionItemsType);
parents.add(collectionItemsType);
List fields = List.of(collectionItemsType.getDeclaredFields());
return Map.of(getTypeName(collectionItemsType), mapFields(fields, parents));
}
private String getFieldName(Field field) {
if (isArray(field) || isCollection(field))
return String.format("%s[]", field.getName());
return field.getName();
}
private String getTypeName(Type type) {
String typeName = type.getTypeName();
typeName = typeName.substring(typeName.lastIndexOf(".") + 1);
if (typeName.endsWith("DTO"))
return typeName.substring(0, typeName.length() - 3);
return typeName;
}
private boolean isFinalType(Field field) {
return isFinalType(field.getType());
}
private boolean isFinalType(Class clazz) {
if (clazz.isArray())
return FINAL_TYPES.contains(clazz.getComponentType());
return FINAL_TYPES.contains(clazz);
}
private boolean isCollection(Field field) {
return Collection.class.isAssignableFrom(field.getType());
}
private boolean isArray(Field field) {
return field.getType().isArray();
}
private boolean hasMapper(Field field) {
return typeMappers.stream()
.filter(mapper -> mapper.getMappedType().equals(field.getType()))
.findFirst()
.isPresent();
}
private RepresentationTypeMapper getMapper(Field field) {
return typeMappers.stream()
.filter(mapper -> mapper.getMappedType().equals(field.getType()))
.findFirst()
.get();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy