Skip to content

Commit 4d8be9e

Browse files
bdonlanrschmitt
authored andcommitted
Improve test coverage and fix some bugs around Cached annotations
Closes #5. Signed-off-by: Ryan Schmitt <[email protected]>
1 parent eecebc8 commit 4d8be9e

File tree

2 files changed

+69
-9
lines changed

2 files changed

+69
-9
lines changed

src/main/java/com/github/rschmitt/dynamicobject/internal/Reflection.java

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88

99
import java.lang.annotation.Annotation;
1010
import java.lang.reflect.Method;
11+
import java.lang.reflect.Modifier;
1112
import java.lang.reflect.ParameterizedType;
1213
import java.lang.reflect.Type;
1314
import java.util.Arrays;
1415
import java.util.Collection;
1516
import java.util.LinkedHashSet;
1617
import java.util.List;
1718
import java.util.Set;
19+
import java.util.stream.Stream;
1820

1921
import static com.github.rschmitt.dynamicobject.internal.ClojureStuff.cachedRead;
2022
import static java.util.stream.Collectors.toSet;
@@ -27,24 +29,51 @@ static <D extends DynamicObject<D>> Collection<Method> requiredFields(Class<D> t
2729

2830
static <D extends DynamicObject<D>> Set<Object> cachedKeys(Class<D> type) {
2931
return Arrays.stream(type.getMethods())
30-
.filter(method -> method.getAnnotation(Cached.class) != null)
31-
.map(method -> method.getAnnotation(Key.class))
32-
.filter(key -> key != null)
33-
.map(Key::value)
34-
.map(Reflection::stringToKey)
32+
.flatMap(Reflection::getCachedKeysForMethod)
3533
.collect(toSet());
3634
}
3735

36+
private static Stream<Object> getCachedKeysForMethod(Method method) {
37+
if (isGetter(method)) {
38+
if (method.getAnnotation(Cached.class) != null) {
39+
return Stream.of(getKeyForGetter(method));
40+
} else {
41+
return Stream.empty();
42+
}
43+
} else if (isBuilder(method)) {
44+
if (method.getAnnotation(Cached.class) != null) {
45+
return Stream.of(getKeyForBuilder(method));
46+
} else {
47+
// If the getter has an annotation it'll contribute it directly
48+
return Stream.empty();
49+
}
50+
} else {
51+
return Stream.empty();
52+
}
53+
}
54+
3855
static <D extends DynamicObject<D>> Collection<Method> fieldGetters(Class<D> type) {
3956
Collection<Method> ret = new LinkedHashSet<>();
4057
for (Method method : type.getDeclaredMethods())
41-
if (method.getParameterCount() == 0 && !method.isDefault() && !method.isSynthetic() && !isMetadataGetter(method))
58+
if (isGetter(method))
4259
ret.add(method);
4360
return ret;
4461
}
4562

46-
static boolean isMetadataGetter(Method getter) {
47-
return getter.getParameterCount() == 0 && hasAnnotation(getter, Meta.class);
63+
private static boolean isBuilder(Method method) {
64+
return method.getParameterCount() == 1 && method.getDeclaringClass().isAssignableFrom(method.getReturnType());
65+
}
66+
67+
private static boolean isAnyGetter(Method method) {
68+
return method.getParameterCount() == 0 && !method.isDefault() && !method.isSynthetic();
69+
}
70+
71+
private static boolean isGetter(Method method) {
72+
return isAnyGetter(method) && !isMetadataGetter(method);
73+
}
74+
75+
static boolean isMetadataGetter(Method method) {
76+
return isAnyGetter(method) && hasAnnotation(method, Meta.class);
4877
}
4978

5079
static boolean isRequired(Method getter) {
@@ -107,7 +136,7 @@ private static Method getCorrespondingGetter(Method builderMethod) {
107136
Method correspondingGetter = type.getMethod(builderMethod.getName());
108137
return correspondingGetter;
109138
} catch (NoSuchMethodException ex) {
110-
throw new IllegalStateException("Builder methods must have a corresponding getter method or a @Key annotation.", ex);
139+
throw new IllegalStateException("Builder method " + builderMethod + " must have a corresponding getter method or a @Key annotation.", ex);
111140
}
112141
}
113142

src/test/java/com/github/rschmitt/dynamicobject/internal/ReflectionTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44
import static org.junit.Assert.assertTrue;
55

66
import java.lang.reflect.Method;
7+
import java.util.Arrays;
78
import java.util.Collection;
9+
import java.util.HashSet;
810

911
import org.junit.Test;
1012

13+
import clojure.java.api.Clojure;
14+
import com.github.rschmitt.dynamicobject.Cached;
1115
import com.github.rschmitt.dynamicobject.DynamicObject;
1216
import com.github.rschmitt.dynamicobject.Key;
1317
import com.github.rschmitt.dynamicobject.Meta;
@@ -30,6 +34,33 @@ public void requiredFields() throws Exception {
3034
assertEquals(1, methods.size());
3135
assertTrue(methods.contains(VariousMethods.class.getMethod("num")));
3236
}
37+
38+
@Test
39+
public void testCachedAnnotations() throws Exception {
40+
HashSet<Object> expectedKeys = new HashSet<>(Arrays.asList(
41+
Clojure.read(":cachedGetter"),
42+
Clojure.read(":cachedGetterWithKey"),
43+
Clojure.read(":cachedBuilder"),
44+
Clojure.read(":cachedBuilderWithKey"),
45+
Clojure.read(":nameFromGetter")
46+
));
47+
48+
HashSet<Object> actualKeys = new HashSet<>(Reflection.cachedKeys(CachedAnnotationTests.class));
49+
50+
assertEquals(expectedKeys, actualKeys);
51+
}
52+
53+
public interface CachedAnnotationTests extends DynamicObject<CachedAnnotationTests> {
54+
@Cached Object cachedGetter();
55+
@Key(":cachedGetterWithKey") @Cached Object differentMethodName();
56+
57+
Object cachedBuilder();
58+
@Cached CachedAnnotationTests cachedBuilder(Object value);
59+
@Key(":cachedBuilderWithKey") @Cached CachedAnnotationTests differentMethodName2(Object value);
60+
61+
@Key(":nameFromGetter") Object nameFromGetterFunc();
62+
@Cached CachedAnnotationTests nameFromGetterFunc(Object value);
63+
}
3364
}
3465

3566
interface VariousMethods extends DynamicObject<VariousMethods> {

0 commit comments

Comments
 (0)