Skip to content

Commit

Permalink
Bump minimum Java to v9 and implement new APIs.
Browse files Browse the repository at this point in the history
Closes #26
Closes #28
  • Loading branch information
kaqqao committed Sep 1, 2024
1 parent d789fe6 commit 9d28ce0
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 127 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,4 @@ public int hashCode() {
public String toString() {
return componentType.toString() + " " + annotationsString() + "[]";
}

@Override
public AnnotatedType getAnnotatedOwnerType() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ class AnnotatedParameterizedTypeImpl extends AnnotatedTypeImpl implements Annota

private final AnnotatedType[] typeArguments;

AnnotatedParameterizedTypeImpl(ParameterizedType rawType, Annotation[] annotations, AnnotatedType[] typeArguments) {
AnnotatedParameterizedTypeImpl(ParameterizedType rawType, Annotation[] annotations, AnnotatedType[] typeArguments, AnnotatedType ownerType) {
super(rawType, annotations);
this.typeArguments = typeArguments;
this.ownerType = ownerType;
}

@Override
Expand Down Expand Up @@ -46,20 +47,15 @@ public String toString() {
String rawName = GenericTypeReflector.getTypeName(rawType.getRawType());

StringBuilder typeName = new StringBuilder();
if (rawType.getOwnerType() != null) {
typeName.append(GenericTypeReflector.getTypeName(rawType.getOwnerType())).append('$');
if (ownerType != null) {
typeName.append(ownerType).append('$');

String prefix = (rawType.getOwnerType() instanceof ParameterizedType) ? ((Class<?>) ((ParameterizedType) rawType.getOwnerType()).getRawType()).getName() + '$'
: ((Class<?>) rawType.getOwnerType()).getName() + '$';
if (rawName.startsWith(prefix))
rawName = rawName.substring(prefix.length());
}
typeName.append(rawName);
return annotationsString() + typeName + "<" + typesString(typeArguments) + ">";
}

@Override
public AnnotatedType getAnnotatedOwnerType() {
return null;
return annotationsString() + typeName + (typeArguments != null && typeArguments.length > 0 ? "<" + typesString(typeArguments) + ">" : "");
}
}
13 changes: 12 additions & 1 deletion src/main/java/io/leangen/geantyref/AnnotatedTypeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ class AnnotatedTypeImpl implements AnnotatedType {

protected Type type;
protected Map<Class<? extends Annotation>, Annotation> annotations;
protected AnnotatedType ownerType;

AnnotatedTypeImpl(Type type) {
this(type, new Annotation[0]);
this(type, new Annotation[0], null);
}

AnnotatedTypeImpl(Type type, Annotation[] annotations) {
this(type, annotations, null);
}

AnnotatedTypeImpl(Type type, Annotation[] annotations, AnnotatedType ownerType) {
this.type = Objects.requireNonNull(type);
this.annotations = toMap(annotations);
this.ownerType = ownerType;
}

@Override
Expand All @@ -51,6 +57,11 @@ public Annotation[] getDeclaredAnnotations() {
return getAnnotations();
}

@Override
public AnnotatedType getAnnotatedOwnerType() {
return ownerType;
}

@Override
public boolean equals(Object other) {
if (this == other) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class AnnotatedTypeVariableImpl extends AnnotatedTypeImpl implements AnnotatedTy
}

AnnotatedTypeVariableImpl(TypeVariable<?> type, Annotation[] annotations) {
super(type, annotations);
super(type, annotations, null);
AnnotatedType[] annotatedBounds = type.getAnnotatedBounds();
if (annotatedBounds == null || annotatedBounds.length == 0) {
annotatedBounds = new AnnotatedType[0];
Expand Down Expand Up @@ -58,9 +58,4 @@ public boolean equals(Object other) {
public String toString() {
return annotationsString() + ((TypeVariable<?>) type).getName();
}

@Override
public AnnotatedType getAnnotatedOwnerType() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,4 @@ private static void validateBounds(WildcardType type, AnnotatedType[] lowerBound
}
}
}

@Override
public AnnotatedType getAnnotatedOwnerType() {
return null;
}
}
143 changes: 68 additions & 75 deletions src/main/java/io/leangen/geantyref/GenericTypeReflector.java

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions src/main/java/io/leangen/geantyref/TypeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,25 @@ public static AnnotatedType annotatedClass(Class<?> clazz, Annotation[] annotati
}

public static AnnotatedType parameterizedAnnotatedClass(Class<?> clazz, Annotation[] annotations, AnnotatedType... arguments) {
return parameterizedAnnotatedInnerClass(null, clazz, annotations, arguments);
return parameterizedAnnotatedInnerClass((AnnotatedType) null, clazz, annotations, arguments);
}

public static AnnotatedType annotatedInnerClass(Type owner, Class<?> clazz, Annotation[] annotations) {
return parameterizedAnnotatedInnerClass(owner, clazz, annotations);
}

public static AnnotatedType parameterizedAnnotatedInnerClass(Type owner, Class<?> clazz, Annotation[] annotations, AnnotatedType... arguments) {
AnnotatedType ownerType = owner != null ? GenericTypeReflector.annotate(owner) : null;
return parameterizedAnnotatedInnerClass(ownerType, clazz, annotations, arguments);
}

public static AnnotatedType parameterizedAnnotatedInnerClass(AnnotatedType owner, Class<?> clazz, Annotation[] annotations, AnnotatedType... arguments) {
if (arguments == null || arguments.length == 0) {
return GenericTypeReflector.annotate(clazz, annotations);
}
Type[] typeArguments = Arrays.stream(arguments).map(AnnotatedType::getType).toArray(Type[]::new);
return new AnnotatedParameterizedTypeImpl((ParameterizedType) parameterizedInnerClass(owner, clazz, typeArguments), annotations, arguments);
Type innerOwner = owner != null ? owner.getType() : null;
return new AnnotatedParameterizedTypeImpl((ParameterizedType) parameterizedInnerClass(innerOwner, clazz, typeArguments), annotations, arguments, owner);
}

public static AnnotatedParameterizedType parameterizedAnnotatedType(ParameterizedType type, Annotation[] typeAnnotations, Annotation[]... argumentAnnotations) {
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/io/leangen/geantyref/TypeVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ protected AnnotatedType visitParameterizedType(AnnotatedParameterizedType type)
AnnotatedType[] params = Arrays.stream(type.getAnnotatedActualTypeArguments())
.map(param -> transform(param, this))
.toArray(AnnotatedType[]::new);
AnnotatedType owner = type.getAnnotatedOwnerType();
if (owner != null) {
owner = transform(owner, this);
}

return GenericTypeReflector.replaceParameters(type, params);
return GenericTypeReflector.replaceParameters(type, params, owner);
}

protected AnnotatedType visitWildcardType(AnnotatedWildcardType type) {
Expand Down
15 changes: 7 additions & 8 deletions src/main/java/io/leangen/geantyref/VarMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -56,8 +55,8 @@ class VarMap {
add(typeParameters[i], arguments[i]);
}

Type owner = ((ParameterizedType) type.getType()).getOwnerType();
type = (owner instanceof ParameterizedType) ? (AnnotatedParameterizedType) annotate(owner) : null;
AnnotatedType owner = type.getAnnotatedOwnerType();
type = (owner instanceof AnnotatedParameterizedType) ? (AnnotatedParameterizedType) owner : null;
} while (type != null);
}

Expand Down Expand Up @@ -119,9 +118,9 @@ AnnotatedType map(AnnotatedType type, MappingMode mappingMode) {
typeParameters[i] = updateAnnotations(typeParameter, raw.getTypeParameters()[i].getAnnotations());
}
Type[] rawArgs = stream(typeParameters).map(AnnotatedType::getType).toArray(Type[]::new);
Type innerOwnerType = inner.getOwnerType() == null ? null : map(annotate(inner.getOwnerType()), mappingMode).getType();
ParameterizedType newInner = new ParameterizedTypeImpl((Class) inner.getRawType(), rawArgs, innerOwnerType);
return new AnnotatedParameterizedTypeImpl(newInner, merge(pType.getAnnotations(), raw.getAnnotations()), typeParameters);
AnnotatedType ownerType = pType.getAnnotatedOwnerType() == null ? null : map(pType.getAnnotatedOwnerType(), mappingMode);
ParameterizedType newInner = new ParameterizedTypeImpl((Class) inner.getRawType(), rawArgs, ownerType != null ? ownerType.getType() : null);
return new AnnotatedParameterizedTypeImpl(newInner, merge(pType.getAnnotations(), raw.getAnnotations()), typeParameters, ownerType);
} else if (type instanceof AnnotatedWildcardType) {
AnnotatedWildcardType wType = (AnnotatedWildcardType) type;
AnnotatedType[] up = map(wType.getAnnotatedUpperBounds(), mappingMode);
Expand Down Expand Up @@ -154,8 +153,8 @@ AnnotatedType[] map(AnnotatedType[] types, MappingMode mappingMode) {
}

Type[] map(Type[] types) {
AnnotatedType[] result = map(Arrays.stream(types).map(GenericTypeReflector::annotate).toArray(AnnotatedType[]::new));
return Arrays.stream(result).map(AnnotatedType::getType).toArray(Type[]::new);
AnnotatedType[] result = map(stream(types).map(GenericTypeReflector::annotate).toArray(AnnotatedType[]::new));
return stream(result).map(AnnotatedType::getType).toArray(Type[]::new);
}

Type map(Type type) {
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
*/

/**
* GenTyRef - Type reflection library for Java
* GeantyRef - Type reflection library for Java
*/
module io.leangen.geantyref {
requires static java.desktop;
exports io.leangen.geantyref;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,17 @@

package io.leangen.geantyref;

import static org.junit.Assert.assertNotEquals;

import junit.framework.TestCase;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.RandomAccess;

import static org.junit.Assert.assertNotEquals;

public abstract class AbstractGenericsReflectorTest extends TestCase {
/**
* A constant that's false, to use in an if() block for code that's only there to show that it
Expand Down Expand Up @@ -100,7 +96,7 @@ private void testMutualSupertypes(TypeToken<?>... types) {
* Tests that the types given are not equal, but they are eachother's supertype.
*/
private <T> void checkedTestMutualSupertypes(TypeToken<T> type1, TypeToken<T> type2) {
assertFalse(type1.equals(type2));
assertNotEquals(type1, type2);
assertTrue(isSupertype(type1, type2));
assertTrue(isSupertype(type2, type1));
}
Expand Down
84 changes: 79 additions & 5 deletions src/test/java/io/leangen/geantyref/GenericTypeReflectorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@

package io.leangen.geantyref;

import java.awt.*;
import java.io.Serializable;
import java.lang.reflect.*;
import java.util.List;
import java.util.*;

import static io.leangen.geantyref.Annotations.*;
Expand All @@ -28,7 +26,6 @@ public GenericTypeReflectorTest() {
}

public void testGetTypeParameter() {
@SuppressWarnings("serial")
class StringList extends ArrayList<String> {
}
assertEquals(String.class, GenericTypeReflector.getTypeParameter(StringList.class, Collection.class.getTypeParameters()[0]));
Expand Down Expand Up @@ -62,10 +59,19 @@ public void testGetExactReturnTypeIllegalArgument() throws SecurityException, No
/**
* Same as {@link #testGetExactReturnTypeIllegalArgument()} for getExactFieldType
*/
public void testGetExactFieldTypeShadowedFieldIllegalArgument() throws SecurityException, NoSuchFieldException {
Field field = GummyWorm.class.getField("size");
try {
GenericTypeReflector.getExactFieldType(field, Gummy.class);
fail("expected exception");
} catch (IllegalArgumentException e) { // expected
}
}

public void testGetExactFieldTypeIllegalArgument() throws SecurityException, NoSuchFieldException {
Field field = Dimension.class.getField("width");
Field field = Pen.class.getField("size");
try {
GenericTypeReflector.getExactFieldType(field, List.class);
GenericTypeReflector.getExactFieldType(field, GummyWorm.class);
fail("expected exception");
} catch (IllegalArgumentException e) { // expected
}
Expand Down Expand Up @@ -222,6 +228,48 @@ public void testReduceBounded() {
assertEquals(Long.class, reduced.getAnnotatedActualTypeArguments()[1].getType());
}

public void testOwnerTypeResolution() throws NoSuchMethodException {
AnnotatedType type = new TypeToken<Box<@A4 Integer>.Lock<@A5 Double>>() {}.getAnnotatedType();
Method echo = Box.Lock.class.getDeclaredMethod("echo");
AnnotatedType exactReturnType = GenericTypeReflector.getExactReturnType(echo, type);
assertTrue(exactReturnType instanceof AnnotatedParameterizedType);
AnnotatedParameterizedType parameterized = (AnnotatedParameterizedType) exactReturnType;
assertEquals(Integer.class, parameterized.getAnnotatedActualTypeArguments()[0].getType());
assertAnnotationsPresent(parameterized.getAnnotatedActualTypeArguments()[0], A4.class, A1.class, A2.class);
AnnotatedParameterizedType owner = (AnnotatedParameterizedType) parameterized.getAnnotatedOwnerType();
assertEquals(Integer.class, owner.getAnnotatedActualTypeArguments()[0].getType());
assertAnnotationsPresent(owner.getAnnotatedActualTypeArguments()[0], A4.class, A1.class);
}

public void testOwnerTypeResolution2() throws NoSuchMethodException {
AnnotatedType type = new TypeToken<Box<@A4 Integer>.Lock<@A5 Double>>() {}.getAnnotatedType();
Method echo = Box.Lock.class.getDeclaredMethod("echo2");
AnnotatedType exactReturnType = GenericTypeReflector.getExactReturnType(echo, type);
assertTrue(exactReturnType instanceof AnnotatedParameterizedType);
AnnotatedParameterizedType parameterized = (AnnotatedParameterizedType) exactReturnType;
assertEquals(Double.class, parameterized.getAnnotatedActualTypeArguments()[0].getType());
assertAnnotationsPresent(parameterized.getAnnotatedActualTypeArguments()[0], A5.class, A2.class);
AnnotatedParameterizedType owner = (AnnotatedParameterizedType) parameterized.getAnnotatedOwnerType();
assertEquals(Integer.class, owner.getAnnotatedActualTypeArguments()[0].getType());
assertAnnotationsPresent(owner.getAnnotatedActualTypeArguments()[0], A4.class, A1.class);
}

public void testOwnerTypeResolution3() throws NoSuchMethodException {
AnnotatedType type = new TypeToken<Box<@A4 Integer>.Shackle>() {}.getAnnotatedType();
Method echo = Box.Shackle.class.getDeclaredMethod("echo2");
AnnotatedType exactReturnType = GenericTypeReflector.resolveExactType(echo.getAnnotatedReturnType(), type);
System.out.println(exactReturnType);
assertTrue(exactReturnType instanceof AnnotatedParameterizedType);
AnnotatedParameterizedType parameterized = (AnnotatedParameterizedType) exactReturnType;
//Only parameterized because its owner is. No actual parameters of its own.
assertEquals(0, parameterized.getAnnotatedActualTypeArguments().length);
assertEquals(Box.Shackle.class, GenericTypeReflector.erase(parameterized.getType()));
AnnotatedParameterizedType annotatedOwnerType = (AnnotatedParameterizedType) parameterized.getAnnotatedOwnerType();
assertEquals(Box.class, GenericTypeReflector.erase(annotatedOwnerType.getType()));
assertEquals(Integer.class, annotatedOwnerType.getAnnotatedActualTypeArguments()[0].getType());
assertAnnotationsPresent(annotatedOwnerType.getAnnotatedActualTypeArguments()[0], A4.class, A1.class);
}

private class N {}
private class P<S, K> extends N {}
private class L<S, K> extends P<List<K>, List<Map<K, S>>> {}
Expand All @@ -243,4 +291,30 @@ private static class ComplexBounds<T extends Number & Serializable, U extends T>
private static AnnotatedType t2 = new TypeToken<@A5 Optional<@A4 Map<@A2 String, @A3 Integer @A1 []>>>(){}.getAnnotatedType();

private class Outer { @A1 class Inner { @A2 class Innermost {}}}

public static class Pen {
public int size;
}
public static class Gummy {
public int size;
}
public static class GummyWorm extends Gummy {
public int size;
}

class Box<@A1 T> {
class Lock<@A2 S> {
Lock<T> echo() {
return null;
}
Lock<S> echo2() {
return null;
}
}
class Shackle extends Lock<Double> {
Shackle echo2() {
return this;
}
}
}
}

0 comments on commit 9d28ce0

Please sign in to comment.