Skip to content

Commit d789fe6

Browse files
committed
Merge branch 'master' into fork/javamodules/feat/jpms
# Conflicts: # pom.xml
2 parents f108b3a + f2682cb commit d789fe6

File tree

12 files changed

+208
-65
lines changed

12 files changed

+208
-65
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
target
2+
release.properties
3+
pom.xml.releaseBackup
24
.DS_Store
35
*.iml
46
.idea

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ All functionality of the library is exposed via a handful of classes:
5252
<dependency>
5353
<groupId>io.leangen.geantyref</groupId>
5454
<artifactId>geantyref</artifactId>
55-
<version>1.3.15</version>
55+
<version>1.3.16</version>
5656
</dependency>
5757
```
5858

5959
### Other build tools:
6060

61-
You can find instructions at [maven.org](https://central.sonatype.com/artifact/io.leangen.geantyref/geantyref/1.3.15)
61+
You can find instructions at [maven.org](https://central.sonatype.com/artifact/io.leangen.geantyref/geantyref/1.3.16)
6262

6363
## Examples
6464

pom.xml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<groupId>io.leangen.geantyref</groupId>
44
<artifactId>geantyref</artifactId>
55
<packaging>jar</packaging>
6-
<version>1.3.16-SNAPSHOT</version>
6+
<version>1.3.17-SNAPSHOT</version>
77

88
<inceptionYear>2016</inceptionYear>
99
<name>GeantyRef</name>
@@ -59,9 +59,8 @@
5959
<artifactId>maven-compiler-plugin</artifactId>
6060
<version>3.12.1</version>
6161
<configuration>
62-
<source>9</source>
63-
<target>9</target>
6462
<release>9</release>
63+
<testRelease>17</testRelease>
6564
</configuration>
6665
</plugin>
6766

src/main/java/io/leangen/geantyref/AnnotatedTypeVariableImpl.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
import java.lang.reflect.AnnotatedTypeVariable;
1111
import java.lang.reflect.TypeVariable;
1212

13+
/*Implementation note #IMPLTNOTE1:
14+
* Currently the principle everywhere is not to replace the underlying variable unless the bounds are being resolved.
15+
* The annotations are never replaced on the TypeVariable itself. Not even when replacing the bounds.
16+
* Find all places with #IMPLTNOTE1 if this principle changes.
17+
*/
1318
class AnnotatedTypeVariableImpl extends AnnotatedTypeImpl implements AnnotatedTypeVariable {
1419

1520
private AnnotatedType[] annotatedBounds;
@@ -27,9 +32,16 @@ class AnnotatedTypeVariableImpl extends AnnotatedTypeImpl implements AnnotatedTy
2732
this.annotatedBounds = annotatedBounds;
2833
}
2934

30-
void init(AnnotatedType[] annotatedBounds) {
31-
this.type = new TypeVariableImpl<>((TypeVariable<?>) this.type, this.getAnnotations(), annotatedBounds);
35+
AnnotatedTypeVariableImpl init(AnnotatedType[] annotatedBounds) {
36+
this.type = new TypeVariableImpl<>((TypeVariable<?>) this.type, /*#IMPLTNOTE1 this.getAnnotations(),*/ annotatedBounds);
3237
this.annotatedBounds = annotatedBounds;
38+
return this;
39+
}
40+
41+
AnnotatedTypeVariableImpl setAnnotations(Annotation[] annotations) {
42+
//#IMPLTNOTE1 this.type = new TypeVariableImpl<>((TypeVariable<?>) this.type, annotations, this.annotatedBounds);
43+
this.annotations = toMap(annotations);
44+
return this;
3345
}
3446

3547
@Override

src/main/java/io/leangen/geantyref/GenericTypeReflector.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,13 @@ public static <T extends AnnotatedType> T replaceAnnotations(T original, Annotat
943943
((AnnotatedWildcardType) original).getAnnotatedLowerBounds(),
944944
((AnnotatedWildcardType) original).getAnnotatedUpperBounds());
945945
}
946+
//Type variables can be recursive (self-referential), so instances must be mutated
947+
//#IMPLTNOTE1 setAnnotations can already take care of replacing the underlying variable as well
948+
if (original instanceof AnnotatedTypeVariableImpl) {
949+
return (T) ((AnnotatedTypeVariableImpl) original).setAnnotations(annotations);
950+
}
946951
if (original instanceof AnnotatedTypeVariable) {
952+
//#IMPLTNOTE1 Replace the underlying variable as well
947953
return (T) new AnnotatedTypeVariableImpl((TypeVariable<?>) original.getType(), annotations);
948954
}
949955
if (original instanceof AnnotatedArrayType) {

src/main/java/io/leangen/geantyref/TypeVariableImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ public Annotation[] getAnnotations() {
7272
return annotations.values().toArray(new Annotation[0]);
7373
}
7474

75-
//should this maybe return only annotations directly on the variable?
7675
@Override
7776
public Annotation[] getDeclaredAnnotations() {
77+
//#IMPLTNOTE1 variable.getAnnotations()
7878
return getAnnotations();
7979
}
8080

src/main/java/io/leangen/geantyref/VarMap.java

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,14 @@
66
package io.leangen.geantyref;
77

88
import java.lang.annotation.Annotation;
9-
import java.lang.reflect.AnnotatedArrayType;
10-
import java.lang.reflect.AnnotatedParameterizedType;
11-
import java.lang.reflect.AnnotatedType;
12-
import java.lang.reflect.AnnotatedTypeVariable;
13-
import java.lang.reflect.AnnotatedWildcardType;
14-
import java.lang.reflect.ParameterizedType;
15-
import java.lang.reflect.Type;
16-
import java.lang.reflect.TypeVariable;
17-
import java.lang.reflect.WildcardType;
9+
import java.lang.reflect.*;
1810
import java.util.Arrays;
1911
import java.util.HashMap;
2012
import java.util.Map;
2113

22-
import static io.leangen.geantyref.GenericTypeReflector.*;
14+
import static io.leangen.geantyref.GenericTypeReflector.annotate;
15+
import static io.leangen.geantyref.GenericTypeReflector.merge;
16+
import static io.leangen.geantyref.GenericTypeReflector.updateAnnotations;
2317
import static java.util.Arrays.stream;
2418

2519
/**
@@ -28,9 +22,11 @@
2822
* @author Wouter Coekaerts {@literal (wouter@coekaerts.be)}
2923
* @author Bojan Tomic {@literal (veggen@gmail.com)}
3024
*/
25+
@SuppressWarnings("rawtypes")
3126
class VarMap {
3227

3328
private final Map<TypeVariable, AnnotatedType> map = new HashMap<>();
29+
private final Map<AnnotatedTypeVariable, AnnotatedTypeVariable> varCache = new HashMap<>();
3430

3531
/**
3632
* Creates an empty VarMap
@@ -51,7 +47,8 @@ class VarMap {
5147

5248
// since we're looping over two arrays in parallel, just to be sure check they have the same size
5349
if (arguments.length != typeParameters.length) {
54-
throw new IllegalStateException("The given type [" + type + "] is inconsistent: it has " +
50+
throw new IllegalStateException(
51+
"The given type [" + type + "] is inconsistent: it has " +
5552
arguments.length + " arguments instead of " + typeParameters.length);
5653
}
5754

@@ -94,15 +91,21 @@ AnnotatedType map(AnnotatedType type, MappingMode mappingMode) {
9491
TypeVariable<?> tv = (TypeVariable) type.getType();
9592
if (!map.containsKey(tv)) {
9693
if (mappingMode.equals(MappingMode.ALLOW_INCOMPLETE)) {
97-
AnnotatedTypeVariable variable = (AnnotatedTypeVariable) type;
98-
AnnotatedType[] bounds = map(variable.getAnnotatedBounds(), mappingMode);
94+
AnnotatedTypeVariable variable = cloneVar((AnnotatedTypeVariable) type);
95+
96+
if (varCache.containsKey(variable)) {
97+
return varCache.get(variable);
98+
}
9999
Annotation[] merged = merge(variable.getAnnotations(), tv.getAnnotations());
100-
TypeVariableImpl v = new TypeVariableImpl<>(tv, merged, bounds);
101-
return new AnnotatedTypeVariableImpl(v, merged);
100+
AnnotatedTypeVariableImpl v = new AnnotatedTypeVariableImpl(tv, merged);
101+
varCache.put(variable, v);
102+
AnnotatedType[] bounds = map(variable.getAnnotatedBounds(), mappingMode);
103+
return v.init(bounds);
102104
} else {
103105
throw new UnresolvedTypeVariableException(tv);
104106
}
105107
}
108+
//#IMPLTNOTE1 Flip key.equals(tv), as the equality check will fail if the underlying variable is replaced
106109
TypeVariable varFromClass = map.keySet().stream().filter(key -> key.equals(tv)).findFirst().get();
107110
Annotation[] merged = merge(type.getAnnotations(), tv.getAnnotations(), map.get(tv).getAnnotations(), varFromClass.getAnnotations());
108111
return updateAnnotations(map.get(tv), merged);
@@ -116,8 +119,8 @@ AnnotatedType map(AnnotatedType type, MappingMode mappingMode) {
116119
typeParameters[i] = updateAnnotations(typeParameter, raw.getTypeParameters()[i].getAnnotations());
117120
}
118121
Type[] rawArgs = stream(typeParameters).map(AnnotatedType::getType).toArray(Type[]::new);
119-
Type innerOwnerType = inner.getOwnerType() == null ? null : map(annotate(inner.getOwnerType()), mappingMode).getType();
120-
ParameterizedType newInner = new ParameterizedTypeImpl((Class) inner.getRawType(), rawArgs, innerOwnerType);
122+
Type innerOwnerType = inner.getOwnerType() == null ? null : map(annotate(inner.getOwnerType()), mappingMode).getType();
123+
ParameterizedType newInner = new ParameterizedTypeImpl((Class) inner.getRawType(), rawArgs, innerOwnerType);
121124
return new AnnotatedParameterizedTypeImpl(newInner, merge(pType.getAnnotations(), raw.getAnnotations()), typeParameters);
122125
} else if (type instanceof AnnotatedWildcardType) {
123126
AnnotatedWildcardType wType = (AnnotatedWildcardType) type;
@@ -139,7 +142,7 @@ AnnotatedType map(AnnotatedType type, MappingMode mappingMode) {
139142
}
140143

141144
AnnotatedType[] map(AnnotatedType[] types) {
142-
return map(types, MappingMode.EXACT);
145+
return map(types, MappingMode.EXACT);
143146
}
144147

145148
AnnotatedType[] map(AnnotatedType[] types, MappingMode mappingMode) {
@@ -162,4 +165,11 @@ Type map(Type type) {
162165
public enum MappingMode {
163166
EXACT, ALLOW_INCOMPLETE
164167
}
168+
169+
AnnotatedTypeVariable cloneVar(AnnotatedTypeVariable v) {
170+
if (v instanceof AnnotatedTypeVariableImpl) {
171+
return v;
172+
}
173+
return new AnnotatedTypeVariableImpl((TypeVariable<?>) v.getType(), v.getAnnotations());
174+
}
165175
}

src/test/java/io/leangen/geantyref/Annotations.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,12 @@ public interface Annotations {
3333
@Retention(RetentionPolicy.RUNTIME)
3434
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
3535
@interface A5 {}
36+
37+
@Retention(RetentionPolicy.RUNTIME)
38+
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
39+
@interface A6 {}
40+
41+
@Retention(RetentionPolicy.RUNTIME)
42+
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
43+
@interface A7 {}
3644
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package io.leangen.geantyref;
2+
3+
import java.lang.annotation.Annotation;
4+
import java.lang.reflect.*;
5+
import java.util.Arrays;
6+
import java.util.Collections;
7+
import java.util.IdentityHashMap;
8+
import java.util.Set;
9+
import java.util.stream.Collectors;
10+
11+
import static org.junit.Assert.assertArrayEquals;
12+
import static org.junit.Assert.assertEquals;
13+
import static org.junit.Assert.assertTrue;
14+
15+
public class Assertions {
16+
17+
@SafeVarargs
18+
public static void assertAnnotationsPresent(AnnotatedType type, Class<? extends Annotation>... annotations) {
19+
assertArrayEquals(annotations, Arrays.stream(type.getAnnotations()).map(Annotation::annotationType).toArray());
20+
}
21+
22+
public static void assertEqualTypeVariables(TypeVariable<?> expected, Type actual) {
23+
if (actual instanceof TypeVariableImpl<?> var) {
24+
//!!Expected and actual values are intentionally reversed.
25+
assertEquals(var, expected);
26+
} else {
27+
assertEquals(expected, actual);
28+
}
29+
}
30+
31+
public static void assertTypeIsRecursive(AnnotatedParameterizedType type) {
32+
Set<AnnotatedTypeVariable> roots = Arrays.stream(type.getAnnotatedActualTypeArguments())
33+
.filter(arg -> arg instanceof AnnotatedTypeVariable)
34+
.map(arg -> (AnnotatedTypeVariable) arg)
35+
.collect(Collectors.toCollection(() -> Collections.newSetFromMap(new IdentityHashMap<>())));
36+
assertTrue("Variable " + type + " does not recur within given depth", isRecursive(roots, type, 0, 10));
37+
}
38+
39+
private static boolean isRecursive(Set<AnnotatedTypeVariable> roots, AnnotatedType node, int currentDepth, int maxDepth) {
40+
if (currentDepth >= maxDepth) {
41+
return false;
42+
}
43+
if (node instanceof AnnotatedTypeVariable var) {
44+
if (roots.contains(var)) {
45+
return true;
46+
}
47+
return Arrays.stream(var.getAnnotatedBounds())
48+
.allMatch(bound -> isRecursive(roots, bound, currentDepth + 1, maxDepth));
49+
} else if (node instanceof AnnotatedParameterizedType parameterized) {
50+
return Arrays.stream(parameterized.getAnnotatedActualTypeArguments())
51+
.allMatch(typeArg -> isRecursive(roots, typeArg, currentDepth + 1, maxDepth));
52+
} else {
53+
return false;
54+
}
55+
}
56+
}

src/test/java/io/leangen/geantyref/GenericTypeReflectorTest.java

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,18 @@
55

66
package io.leangen.geantyref;
77

8-
import java.awt.Dimension;
8+
import java.awt.*;
99
import java.io.Serializable;
10-
import java.lang.annotation.Annotation;
11-
import java.lang.reflect.AnnotatedArrayType;
12-
import java.lang.reflect.AnnotatedParameterizedType;
13-
import java.lang.reflect.AnnotatedType;
14-
import java.lang.reflect.Constructor;
15-
import java.lang.reflect.Field;
16-
import java.lang.reflect.Method;
17-
import java.lang.reflect.Type;
18-
import java.lang.reflect.TypeVariable;
19-
import java.util.ArrayList;
20-
import java.util.Arrays;
21-
import java.util.Collection;
10+
import java.lang.reflect.*;
2211
import java.util.List;
23-
import java.util.Map;
24-
import java.util.Optional;
25-
import java.util.Set;
26-
27-
import static io.leangen.geantyref.Annotations.A1;
28-
import static io.leangen.geantyref.Annotations.A2;
29-
import static io.leangen.geantyref.Annotations.A3;
30-
import static io.leangen.geantyref.Annotations.A4;
31-
import static io.leangen.geantyref.Annotations.A5;
12+
import java.util.*;
13+
14+
import static io.leangen.geantyref.Annotations.*;
15+
import static io.leangen.geantyref.Assertions.assertAnnotationsPresent;
3216
import static io.leangen.geantyref.GenericTypeReflector.annotate;
3317
import static io.leangen.geantyref.GenericTypeReflector.getExactSubType;
3418
import static io.leangen.geantyref.GenericTypeReflector.resolveExactType;
3519
import static io.leangen.geantyref.GenericTypeReflector.resolveType;
36-
import static org.junit.Assert.assertArrayEquals;
3720

3821
/**
3922
* Test for reflection done in GenericTypeReflector.
@@ -239,11 +222,6 @@ public void testReduceBounded() {
239222
assertEquals(Long.class, reduced.getAnnotatedActualTypeArguments()[1].getType());
240223
}
241224

242-
@SafeVarargs
243-
private static void assertAnnotationsPresent(AnnotatedType type, Class<? extends Annotation>... annotations) {
244-
assertArrayEquals(annotations, Arrays.stream(type.getAnnotations()).map(Annotation::annotationType).toArray());
245-
}
246-
247225
private class N {}
248226
private class P<S, K> extends N {}
249227
private class L<S, K> extends P<List<K>, List<Map<K, S>>> {}

0 commit comments

Comments
 (0)