View Javadoc
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 }