jDu*_*ub9 8 java sorting reflection comparator java-8
我有一个REST端点和我想的UI来传递他们希望通过自己的排序结果中的字段名称"id","name"等我想出了下面,但真的想使用反射/泛型所以这可能是扩大到包括每我的项目中的对象.
如果我想为100个不同的类提供相同的功能,我觉得这个解决方案不易维护.
public static void sort(List<MovieDTO> collection, String field) {
if(collection == null || collection.size() < 1 || field == null || field.isEmpty()) {
return;
}
switch(field.trim().toLowerCase()) {
case "id":
collection.sort(Comparator.comparing(MovieDTO::getId));
break;
case "name":
collection.sort(Comparator.comparing(MovieDTO::getName));
break;
case "year":
collection.sort(Comparator.comparing(MovieDTO::getYear));
break;
case "rating":
collection.sort(Comparator.comparing(MovieDTO::getRating));
break;
default:
collection.sort(Comparator.comparing(MovieDTO::getId));
break;
}
}
Run Code Online (Sandbox Code Playgroud)
关于如何更好地实现这一点的任何想法,以便它可以扩展到几乎没有维护的企业应用程序?
我不会重复评论中所说的一切.那里有很好的想法.我希望你明白反思不是这里的最佳选择.
我建议保留一个Map<String, Function<MovieDTO, String>>,其中键是一个field名称,值是一个映射器movie -> field:
Map<String, Function<MovieDTO, String>> extractors = ImmutableMap.of(
"id", MovieDTO::getId,
"name", MovieDTO::getName
);
Run Code Online (Sandbox Code Playgroud)
然后,集合可以像:
Function<MovieDTO, String> extractor = extractors.getOrDefault(
field.trim().toLowerCase(),
MovieDTO::getId
);
collection.sort(Comparator.comparing(extractor));
Run Code Online (Sandbox Code Playgroud)
正如我所承诺的,我正在添加我的注释处理愿景来帮助你.请注意,这不是一个你必须牢牢坚持的版本.这是一个很好的开始.
我宣布了2个注释.
澄清getter名称(如果未指定,<get + FieldName>则为模式):
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@interface FieldExtractor {
String getterName();
}
Run Code Online (Sandbox Code Playgroud)要为类定义所有可能的排序键:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@interface SortingFields {
String[] fields();
}
Run Code Online (Sandbox Code Playgroud)该课程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;
}
...
}
Run Code Online (Sandbox Code Playgroud)
我没有更改sort方法签名(但是,它会简化任务):
public static <T> void sort(List<T> collection, String field) throws NoSuchMethodException, NoSuchFieldException {
if (collection == null || collection.isEmpty() || field == null || field.isEmpty()) {
return;
}
// get a generic type of the collection
Class<?> genericType = ActualGenericTypeExtractor.extractFromType(collection.getClass().getGenericSuperclass());
// get a key-extractor function
Function<T, Comparable<? super Object>> extractor = SortingKeyExtractor.extractFromClassByFieldName(genericType, field);
// sort
collection.sort(Comparator.comparing(extractor));
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我需要介绍两个类来完成:
class ActualGenericTypeExtractor {
public static Class<?> extractFromType(Type type) {
// check if it is a waw type
if (!(type instanceof ParameterizedType)) {
throw new IllegalArgumentException("Raw type has been found! Specify a generic type for further scanning.");
}
// return the first generic type
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 {
// check if the fieldName is in allowed fields
validateFieldName(type, fieldName);
// fetch a key-extractor method
Method method = findExtractorForField(type, type.getDeclaredField(fieldName));
// form a Function with a method invocation inside
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 {
// generate the default name for a getter
String fieldName = "get" + StringUtil.capitalize(field.getName());
// override it if specified by the annotation
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!");
}
}
Run Code Online (Sandbox Code Playgroud)
它看起来有点复杂,但这是推广的代价.当然,还有改进的余地,如果你指出它们,我很乐意回顾一下.
| 归档时间: |
|
| 查看次数: |
1283 次 |
| 最近记录: |