1 package org.oxerr.spring.cache.redis.scored.score.resolver.annotated; 2 3 import java.lang.annotation.Annotation; 4 import java.lang.reflect.Field; 5 import java.lang.reflect.InvocationTargetException; 6 import java.lang.reflect.Method; 7 import java.sql.Date; 8 import java.sql.Timestamp; 9 import java.time.Instant; 10 import java.util.List; 11 import java.util.Optional; 12 13 import org.apache.commons.lang3.reflect.FieldUtils; 14 import org.apache.commons.lang3.reflect.MethodUtils; 15 import org.oxerr.spring.cache.redis.scored.ScoreResolver; 16 import org.slf4j.Logger; 17 import org.slf4j.LoggerFactory; 18 import org.springframework.lang.NonNull; 19 import org.springframework.lang.Nullable; 20 21 public class AnnotatedScoreResolver implements ScoreResolver { 22 23 private final Logger log = LoggerFactory.getLogger(AnnotatedScoreResolver.class); 24 25 private final Class<? extends Annotation> annotationType; 26 27 public AnnotatedScoreResolver(Class<? extends Annotation> annotationType) { 28 this.annotationType = annotationType; 29 } 30 31 @Override 32 public Optional<Double> resolveScore(@Nullable Object value) { 33 if (value == null) { 34 return Optional.empty(); 35 } else { 36 return getScore(value); 37 } 38 } 39 40 private Optional<Double> getScore(@NonNull Object value) { 41 Optional<Double> score = Optional.empty(); 42 43 try { 44 score = this.getVersion(value); 45 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 46 log.debug(e.getMessage()); 47 } 48 49 return score; 50 } 51 52 private Optional<Double> getVersion(@NonNull Object value) 53 throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 54 final Class<?> valueType = value.getClass(); 55 56 Object version = null; 57 58 final List<Method> methods = MethodUtils.getMethodsListWithAnnotation(valueType, annotationType, true, true); 59 for (final Method method : methods) { 60 method.setAccessible(true); 61 version = method.invoke(value); 62 if (version != null) { 63 break; 64 } 65 } 66 67 if (version == null) { 68 final List<Field> fields = FieldUtils.getFieldsListWithAnnotation(valueType, annotationType); 69 for (final Field field : fields) { 70 field.setAccessible(true); 71 version = field.get(value); 72 73 if (version != null) { 74 break; 75 } 76 } 77 } 78 79 return Optional.ofNullable(extractScore(version)); 80 } 81 82 private Double extractScore(Object version) { 83 final Double score; 84 85 if (version == null) { 86 score = null; 87 } else if (version instanceof Number) { 88 Number number = (Number) version; 89 score = number.doubleValue(); 90 } else if (version instanceof Date) { 91 Timestamp timestamp = (Timestamp) version; 92 long millis = timestamp.getTime(); 93 int nanos = timestamp.getNanos(); 94 score = Double.parseDouble(String.format("%d.%d", millis, nanos)); 95 } else if (version instanceof Instant) { 96 Instant instant = (Instant) version; 97 long millis = instant.toEpochMilli(); 98 int nanos = instant.getNano(); 99 score = Double.parseDouble(String.format("%d.%d", millis, nanos)); 100 } else { 101 throw new IllegalArgumentException("Unsupported type: " + version.getClass()); 102 } 103 104 return score; 105 } 106 107 }