. . , , .
Map<String, Function<MovieDTO, String>>, - field, - mapper movie -> field:
Map<String, Function<MovieDTO, String>> extractors = ImmutableMap.of(
"id", MovieDTO::getId,
"name", MovieDTO::getName
);
:
Function<MovieDTO, String> extractor = extractors.getOrDefault(
field.trim().toLowerCase(),
MovieDTO::getId
);
collection.sort(Comparator.comparing(extractor));
, , . , , . .
2 .
( , <get + FieldName> - ):
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@interface FieldExtractor {
String getterName();
}
:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@interface SortingFields {
String[] fields();
}
MovieDTO :
@SortingFields(fields = {"id", "name"})
class MovieDTO implements Comparable<MovieDTO> {
@FieldExtractor(getterName = "getIdentifier")
private Long id;
private String name;
public Long getIdentifier() {
return id;
}
public String getName() {
return name;
}
...
}
sort ( ):
public static <T> void sort(List<T> collection, String field) throws NoSuchMethodException, NoSuchFieldException {
if (collection == null || collection.isEmpty() || field == null || field.isEmpty()) {
return;
}
Class<?> genericType = ActualGenericTypeExtractor.extractFromType(collection.getClass().getGenericSuperclass());
Function<T, Comparable<? super Object>> extractor = SortingKeyExtractor.extractFromClassByFieldName(genericType, field);
collection.sort(Comparator.comparing(extractor));
}
, 2 :
class ActualGenericTypeExtractor {
public static Class<?> extractFromType(Type type) {
if (!(type instanceof ParameterizedType)) {
throw new IllegalArgumentException("Raw type has been found! Specify a generic type for further scanning.");
}
return (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0];
}
}
class SortingKeyExtractor {
@SuppressWarnings("unchecked")
public static <T> Function<T, Comparable<? super Object>> extractFromClassByFieldName(Class<?> type, String fieldName) throws NoSuchFieldException, NoSuchMethodException {
validateFieldName(type, fieldName);
Method method = findExtractorForField(type, type.getDeclaredField(fieldName));
return (T instance) -> {
try {
return (Comparable<? super Object>) method.invoke(instance);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
};
}
private static Method findExtractorForField(Class<?> type, Field field) throws NoSuchMethodException {
String fieldName = "get" + StringUtil.capitalize(field.getName());
if (field.isAnnotationPresent(FieldExtractor.class)) {
fieldName = field.getAnnotation(FieldExtractor.class).getterName();
}
System.out.println("> Fetching a method with the name [" + fieldName + "]...");
return type.getDeclaredMethod(fieldName);
}
private static void validateFieldName(Class<?> type, String fieldName) {
if (!type.isAnnotationPresent(SortingFields.class)) {
throw new IllegalArgumentException("A list of sorting fields hasn't been specified!");
}
SortingFields annotation = type.getAnnotation(SortingFields.class);
for (String field : annotation.fields()) {
if (field.equals(fieldName)) {
System.out.println("> The given field name [" + fieldName + "] is allowed!");
return;
}
}
throw new IllegalArgumentException("The given field is not allowed to be a sorting key!");
}
}
, . , , , .