Skip to content

Commit 8bdccce

Browse files
committed
use immutable list except case when InvocationContext constructor takes list in parameters
1 parent 18bcaa8 commit 8bdccce

File tree

2 files changed

+112
-12
lines changed

2 files changed

+112
-12
lines changed

framework/src/play/Invoker.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package play;
22

33
import java.lang.annotation.Annotation;
4-
import java.util.ArrayList;
54
import java.util.Arrays;
65
import java.util.HashSet;
76
import java.util.List;
@@ -26,6 +25,8 @@
2625
import play.libs.F.Promise;
2726
import play.utils.PThreadFactory;
2827

28+
import static java.util.Collections.unmodifiableList;
29+
2930
/**
3031
* Run some code in a Play! context
3132
*/
@@ -115,8 +116,7 @@ public static InvocationContext current() {
115116
}
116117

117118
public InvocationContext(String invocationType) {
118-
this.invocationType = invocationType;
119-
this.annotations = new ArrayList<>();
119+
this(invocationType, List.of());
120120
}
121121

122122
public InvocationContext(String invocationType, List<Annotation> annotations) {
@@ -125,16 +125,11 @@ public InvocationContext(String invocationType, List<Annotation> annotations) {
125125
}
126126

127127
public InvocationContext(String invocationType, Annotation[] annotations) {
128-
this.invocationType = invocationType;
129-
this.annotations = Arrays.asList(annotations);
128+
this(invocationType, List.of(annotations));
130129
}
131130

132131
public InvocationContext(String invocationType, Annotation[]... annotations) {
133-
this.invocationType = invocationType;
134-
this.annotations = new ArrayList<>();
135-
for (Annotation[] some : annotations) {
136-
this.annotations.addAll(Arrays.asList(some));
137-
}
132+
this(invocationType, Arrays.stream(annotations).flatMap(Arrays::stream).toList());
138133
}
139134

140135
public List<Annotation> getAnnotations() {
@@ -144,7 +139,7 @@ public List<Annotation> getAnnotations() {
144139
@SuppressWarnings("unchecked")
145140
public <T extends Annotation> T getAnnotation(Class<T> clazz) {
146141
for (Annotation annotation : annotations) {
147-
if (annotation.annotationType().isAssignableFrom(clazz)) {
142+
if (annotation.annotationType() == clazz) {
148143
return (T) annotation;
149144
}
150145
}
@@ -153,7 +148,7 @@ public <T extends Annotation> T getAnnotation(Class<T> clazz) {
153148

154149
public <T extends Annotation> boolean isAnnotationPresent(Class<T> clazz) {
155150
for (Annotation annotation : annotations) {
156-
if (annotation.annotationType().isAssignableFrom(clazz)) {
151+
if (annotation.annotationType() == clazz) {
157152
return true;
158153
}
159154
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package play;
2+
3+
import org.junit.jupiter.api.Nested;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.lang.annotation.Annotation;
7+
import java.lang.reflect.InvocationHandler;
8+
import java.lang.reflect.Proxy;
9+
import java.util.Arrays;
10+
import java.util.List;
11+
import java.util.function.Consumer;
12+
import java.util.stream.Stream;
13+
14+
import static org.assertj.core.api.Assertions.assertThat;
15+
16+
class InvokerTest {
17+
18+
@Nested
19+
class InvocationContextTest {
20+
21+
@Test void constructorStringShouldCreateInvocationContextWithEmptyAnnotationsCollection() {
22+
String invocationType = "constructorString";
23+
var context = new Invoker.InvocationContext(invocationType);
24+
assertThat(context.getInvocationType()).isSameAs(invocationType);
25+
assertThat(context.getAnnotations()).isEmpty();
26+
}
27+
28+
@Test void constructorStringAndListShouldCreateInvocationContextWithSameAnnotationsCollection() {
29+
String invocationType = "constructorStringAndList";
30+
var annotations = List.of(stubAnnotationsFor(A.class, B.class, C.class, D.class));
31+
var context = new Invoker.InvocationContext(invocationType, annotations);
32+
assertThat(context.getInvocationType()).isSameAs(invocationType);
33+
assertThat(context.getAnnotations()).isSameAs(annotations);
34+
}
35+
36+
@Test void constructorStringAndOneDimensionArrayShouldCreateInvocationContextWithAnnotationsCollectionFromArray() {
37+
String invocationType = "constructorStringAndOneDimensionArray";
38+
var annotations = stubAnnotationsFor(A.class, B.class, C.class, D.class);
39+
var context = new Invoker.InvocationContext(invocationType, annotations);
40+
41+
assertThat(context.getInvocationType()).isSameAs(invocationType);
42+
assertThat(context.getAnnotations()).satisfiesExactly(
43+
Arrays.stream(annotations)
44+
.<Consumer<? super Annotation>>map(annotation -> actual -> assertThat(actual).isSameAs(annotation))
45+
.toArray(Consumer[]::new)
46+
);
47+
}
48+
49+
@Test void constructorStringAndTwoDimensionsArrayShouldCreateInvocationContextWithAnnotationsCollectionFromArray() {
50+
String invocationType = "constructorStringAndTwoDimensionsArray";
51+
var abAnnotations = stubAnnotationsFor(A.class, B.class);
52+
var cdAnnotations = stubAnnotationsFor(C.class, D.class);
53+
var context = new Invoker.InvocationContext(invocationType, abAnnotations, cdAnnotations);
54+
55+
assertThat(context.getInvocationType()).isSameAs(invocationType);
56+
assertThat(context.getAnnotations()).satisfiesExactly(
57+
Stream.concat(Arrays.stream(abAnnotations), Arrays.stream(cdAnnotations))
58+
.<Consumer<? super Annotation>>map(annotation -> actual -> assertThat(actual).isSameAs(annotation))
59+
.toArray(Consumer[]::new)
60+
);
61+
}
62+
63+
@Test void getAnnotationShouldReturnFirstAnnotationFromList() {
64+
var annotations = stubAnnotationsFor(A.class, B.class, C.class, B.class);
65+
var context = new Invoker.InvocationContext("someInvocationType", annotations);
66+
assertThat(context.getAnnotation(B.class)).isSameAs(annotations[1]);
67+
}
68+
69+
@Test void getAnnotationShouldReturnNull() {
70+
var context = new Invoker.InvocationContext("someInvocationType", stubAnnotationsFor(A.class, B.class, C.class));
71+
assertThat(context.getAnnotation(D.class)).isNull();
72+
}
73+
74+
@Test void isAnnotationPresentShouldReturnTrue() {
75+
var annotations = stubAnnotationsFor(A.class, B.class, C.class, B.class);
76+
var context = new Invoker.InvocationContext("someInvocationType", annotations);
77+
assertThat(context.isAnnotationPresent(C.class)).isTrue();
78+
}
79+
80+
@Test void isAnnotationPresentShouldReturnFalse() {
81+
var context = new Invoker.InvocationContext("someInvocationType", stubAnnotationsFor(A.class, B.class, C.class));
82+
assertThat(context.isAnnotationPresent(D.class)).isFalse();
83+
}
84+
85+
@SafeVarargs
86+
private Annotation[] stubAnnotationsFor(Class<? extends Annotation>... annotations) {
87+
return Arrays.stream(annotations).map(this::stubAnnotationFor).toArray(Annotation[]::new);
88+
}
89+
90+
private <T extends Annotation> T stubAnnotationFor(Class<T> annotation) {
91+
InvocationHandler handler = (proxy, method, args) ->
92+
method.getName().equals("annotationType") ? annotation : method.invoke(proxy, args);
93+
94+
return (T) Proxy.newProxyInstance(annotation.getClassLoader(), new Class[] { annotation }, handler);
95+
}
96+
97+
private @interface A {}
98+
private @interface B {}
99+
private @interface C {}
100+
private @interface D {}
101+
102+
}
103+
104+
105+
}

0 commit comments

Comments
 (0)