Skip to content

Commit 86010a6

Browse files
committed
Added two methods and changed how compatibility lists work when passing null-arguments
1 parent cac1fce commit 86010a6

4 files changed

Lines changed: 105 additions & 43 deletions

File tree

src/main/java/org/bbottema/javareflection/MethodUtils.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.jetbrains.annotations.Nullable;
1313
import org.slf4j.Logger;
1414

15+
import java.lang.annotation.Annotation;
1516
import java.lang.reflect.AccessibleObject;
1617
import java.lang.reflect.Constructor;
1718
import java.lang.reflect.InvocationTargetException;
@@ -20,6 +21,7 @@
2021

2122
import static java.lang.String.format;
2223
import static org.bbottema.javareflection.LookupCaches.METHOD_CACHE;
24+
import static org.bbottema.javareflection.TypeUtils.containsAnnotation;
2325
import static org.bbottema.javareflection.util.MiscUtil.trustedCast;
2426
import static org.bbottema.javareflection.util.MiscUtil.trustedNullableCast;
2527
import static org.slf4j.LoggerFactory.getLogger;
@@ -561,4 +563,26 @@ public static Method onlyMethod(Set<InvokableObject<Method>> methods) {
561563
throw new AssertionError("Expected 1 or less methods, but found more than 1 methods: " + methods);
562564
}
563565
}
566+
567+
@SuppressWarnings("unchecked")
568+
@Nullable
569+
public static <T extends Annotation, Target> Target firstParameterArgumentByAnnotation(Method method, Object[] arguments, Class<T> annotationClass) {
570+
if (isMethodCompatible(method, arguments)) {
571+
for (int i = 0; i < method.getParameterTypes().length; i++) {
572+
if (containsAnnotation(method.getParameterAnnotations()[i], annotationClass)) {
573+
return (Target) arguments[i];
574+
}
575+
}
576+
}
577+
return null;
578+
}
579+
580+
public static <T extends Annotation> int firstParameterIndexByAnnotation(Method method, Class<T> annotationClass) {
581+
for (int i = 0; i < method.getParameterTypes().length; i++) {
582+
if (containsAnnotation(method.getParameterAnnotations()[i], annotationClass)) {
583+
return i;
584+
}
585+
}
586+
return -1;
587+
}
564588
}

src/main/java/org/bbottema/javareflection/TypeUtils.java

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static Class<?>[] collectTypes(final Object[] objects) {
6969
final Class<?>[] types = new Class<?>[objects.length];
7070
for (int i = 0; i < objects.length; i++) {
7171
final Object o = objects[i];
72-
types[i] = o != null ? o.getClass() : Object.class;
72+
types[i] = o != null ? o.getClass() : null;
7373
}
7474
return types;
7575
}
@@ -81,7 +81,7 @@ public static boolean isTypeListCompatible(Class<?>[] inputTypeList, Class<?>[]
8181
for (Class<?>[] derivableTypeList : derivableTypeLists) {
8282
boolean currentTypeListCompatible = true;
8383
for (int i = 0; i < derivableTypeList.length && currentTypeListCompatible; i++) {
84-
if (!derivableTypeList[i].equals(targetTypeList[i])) {
84+
if (derivableTypeList[i] != null && !derivableTypeList[i].equals(targetTypeList[i])) {
8585
currentTypeListCompatible = false;
8686
}
8787
}
@@ -137,47 +137,49 @@ private static List<Class<?>[]> generateCompatibleTypeLists(final int index, fin
137137
// 1. don't generate compatible list; just try the normal type first
138138
// remember, in combinations types should be allowed to be converted)
139139
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, inputTypelist.clone());
140-
141-
// 2. generate type in which the original can be (un)wrapped
142-
if (lookupMode.contains(LookupMode.AUTOBOX) && !lookupMode.contains(LookupMode.SMART_CONVERT)) {
143-
final Class<?> autoboxed = autobox(original);
144-
if (autoboxed != null) {
145-
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, autoboxed);
146-
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
140+
141+
if (original != null) {
142+
// 2. generate type in which the original can be (un)wrapped
143+
if (lookupMode.contains(LookupMode.AUTOBOX) && !lookupMode.contains(LookupMode.SMART_CONVERT)) {
144+
final Class<?> autoboxed = autobox(original);
145+
if (autoboxed != null) {
146+
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, autoboxed);
147+
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
148+
}
147149
}
148-
}
149-
150-
// autocast to supertype or interface?
151-
if (lookupMode.contains(LookupMode.CAST_TO_INTERFACE)) {
152-
// 3. generate implemented interfaces the original value could be converted (cast) into
153-
for (final Class<?> iface : original.getInterfaces()) {
154-
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, iface);
155-
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
150+
151+
// autocast to supertype or interface?
152+
if (lookupMode.contains(LookupMode.CAST_TO_INTERFACE)) {
153+
// 3. generate implemented interfaces the original value could be converted (cast) into
154+
for (final Class<?> iface : original.getInterfaces()) {
155+
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, iface);
156+
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
157+
}
156158
}
157-
}
158-
159-
if (lookupMode.contains(LookupMode.CAST_TO_SUPER)) {
160-
// 4. generate supertypes the original value could be converted (cast) into
161-
Class<?> supertype = original;
162-
while ((supertype = supertype.getSuperclass()) != null) {
163-
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, supertype);
164-
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
159+
160+
if (lookupMode.contains(LookupMode.CAST_TO_SUPER)) {
161+
// 4. generate supertypes the original value could be converted (cast) into
162+
Class<?> supertype = original;
163+
while ((supertype = supertype.getSuperclass()) != null) {
164+
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, supertype);
165+
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
166+
}
165167
}
166-
}
167-
168-
// 5. generate types the original value could be converted into
169-
if (lookupMode.contains(LookupMode.COMMON_CONVERT) && !lookupMode.contains(LookupMode.SMART_CONVERT)) {
170-
for (final Class<?> convert : collectRegisteredCompatibleTargetTypes(original)) {
171-
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, convert);
172-
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
168+
169+
// 5. generate types the original value could be converted into
170+
if (lookupMode.contains(LookupMode.COMMON_CONVERT) && !lookupMode.contains(LookupMode.SMART_CONVERT)) {
171+
for (final Class<?> convert : collectRegisteredCompatibleTargetTypes(original)) {
172+
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, convert);
173+
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
174+
}
173175
}
174-
}
175-
176-
// 6. generate types the original value could be converted into with intermediary conversions
177-
if (lookupMode.contains(LookupMode.SMART_CONVERT)) {
178-
for (final Class<?> convert : collectCompatibleTargetTypes(original)) {
179-
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, convert);
180-
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
176+
177+
// 6. generate types the original value could be converted into with intermediary conversions
178+
if (lookupMode.contains(LookupMode.SMART_CONVERT)) {
179+
for (final Class<?> convert : collectCompatibleTargetTypes(original)) {
180+
final Class<?>[] newTypeList = replaceInArray(inputTypelist.clone(), index, convert);
181+
generateCompatibleTypeLists(index + 1, lookupMode, compatibleTypeLists, newTypeList);
182+
}
181183
}
182184
}
183185
}

src/test/java/org/bbottema/javareflection/MethodUtilsTest.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,16 @@
44
import org.bbottema.javareflection.model.LookupMode;
55
import org.bbottema.javareflection.model.MethodModifier;
66
import org.bbottema.javareflection.model.MethodParameter;
7-
import org.bbottema.javareflection.testmodel.*;
7+
import org.bbottema.javareflection.testmodel.A;
8+
import org.bbottema.javareflection.testmodel.B;
9+
import org.bbottema.javareflection.testmodel.C;
10+
import org.bbottema.javareflection.testmodel.Foo;
11+
import org.bbottema.javareflection.testmodel.Fruit;
12+
import org.bbottema.javareflection.testmodel.Kraa;
13+
import org.bbottema.javareflection.testmodel.Meta;
14+
import org.bbottema.javareflection.testmodel.Moo;
15+
import org.bbottema.javareflection.testmodel.Pear;
16+
import org.bbottema.javareflection.testmodel.Skree;
817
import org.bbottema.javareflection.util.MetaAnnotationExtractor;
918
import org.bbottema.javareflection.valueconverter.ValueConversionHelper;
1019
import org.junit.Before;
@@ -19,13 +28,19 @@
1928
import java.lang.reflect.Method;
2029
import java.lang.reflect.Type;
2130
import java.util.AbstractMap.SimpleEntry;
22-
import java.util.*;
31+
import java.util.ArrayList;
32+
import java.util.Calendar;
33+
import java.util.EnumSet;
34+
import java.util.HashSet;
35+
import java.util.LinkedHashMap;
36+
import java.util.List;
37+
import java.util.Set;
2338

2439
import static java.util.Arrays.asList;
2540
import static java.util.EnumSet.allOf;
41+
import static java.util.Objects.requireNonNull;
2642
import static org.assertj.core.api.Assertions.assertThat;
2743
import static org.assertj.core.api.Assertions.fail;
28-
import static org.assertj.core.util.Lists.newArrayList;
2944
import static org.bbottema.javareflection.ClassUtils.collectMethodsByName;
3045
import static org.bbottema.javareflection.MethodUtils.onlyMethod;
3146
import static org.bbottema.javareflection.model.MethodModifier.MATCH_ANY;
@@ -298,4 +313,25 @@ public void testMethodHasCollectionParameter() {
298313
private Method findSkreeMethod(String methodName) {
299314
return collectMethodsByName(Skree.class, Skree.class, MATCH_ANY, methodName).iterator().next();
300315
}
316+
317+
@Test
318+
public void testFirstParameterArgumentByAnnotation() {
319+
final Method testMethod = requireNonNull(ClassUtils.findFirstMethodByName(Kraa.class, Kraa.class, MATCH_ANY, "testMethod"));
320+
final int argOne = 2;
321+
final List argTwo = null;
322+
final HashSet argThree = new HashSet();
323+
final Object[] arguments = {argOne, argTwo, argThree};
324+
assertThat(MethodUtils.firstParameterArgumentByAnnotation(testMethod, arguments, Nullable.class)).isSameAs(argTwo);
325+
assertThat(MethodUtils.firstParameterArgumentByAnnotation(testMethod, arguments, Nonnull.class)).isSameAs(argThree);
326+
assertThat(MethodUtils.firstParameterArgumentByAnnotation(testMethod, arguments, Meta.class)).isNull();
327+
}
328+
329+
@Test
330+
public void testFirstParameterIndexByAnnotation() {
331+
final Method testMethod = requireNonNull(ClassUtils.findFirstMethodByName(Kraa.class, Kraa.class, MATCH_ANY, "testMethod"));
332+
333+
assertThat(MethodUtils.firstParameterIndexByAnnotation(testMethod, Nullable.class)).isEqualTo(1);
334+
assertThat(MethodUtils.firstParameterIndexByAnnotation(testMethod, Nonnull.class)).isEqualTo(2);
335+
assertThat(MethodUtils.firstParameterIndexByAnnotation(testMethod, Meta.class)).isEqualTo(-1);
336+
}
301337
}

src/test/java/org/bbottema/javareflection/TypeUtilsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void testAutobox() {
4444

4545
@Test
4646
public void testCollectTypes() {
47-
final Class<?>[] expectedTypeList = new Class<?>[]{Pear.class, String.class, Object.class, Double.class};
47+
final Class<?>[] expectedTypeList = new Class<?>[]{Pear.class, String.class, null, Double.class};
4848
final Object[] objectList = new Object[]{new Pear(), "foo", null, 4d};
4949
assertThat(TypeUtils.collectTypes(objectList)).isEqualTo(expectedTypeList);
5050
}

0 commit comments

Comments
 (0)