Skip to content

Commit

Permalink
Fixes mockito#1917
Browse files Browse the repository at this point in the history
  • Loading branch information
sectorpre committed Oct 20, 2023
1 parent 6f4eb02 commit 0860571
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 6 deletions.
Expand Up @@ -8,9 +8,9 @@

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

import org.mockito.exceptions.base.MockitoException;
import org.mockito.internal.util.reflection.FieldInitializationReport;
Expand Down Expand Up @@ -43,9 +43,9 @@ public ConstructorInjection() {}
public boolean processInjection(Field field, Object fieldOwner, Set<Object> mockCandidates) {
try {
SimpleArgumentResolver simpleArgumentResolver =
new SimpleArgumentResolver(mockCandidates);
new SimpleArgumentResolver(mockCandidates);
FieldInitializationReport report =
new FieldInitializer(fieldOwner, field, simpleArgumentResolver).initialize();
new FieldInitializer(fieldOwner, field, simpleArgumentResolver).initialize();

return report.fieldWasInitializedUsingContructorArgs();
} catch (MockitoException e) {
Expand All @@ -67,6 +67,21 @@ static class SimpleArgumentResolver implements ConstructorArgumentResolver {
public SimpleArgumentResolver(Set<Object> objects) {
this.objects = objects;
}
/**
* types -> actual constructor types
* argTypes -> fake constructor types
* hashMap -> mocks
*/
@Override
public Object[] resolveTypeInstancesGeneric(HashMap<String, Type> hashMap, Type[] types) {
// list of mocks not constructors
List<Object> argumentInstances = new ArrayList<>(types.length);
for (Type parameterType: types) {
argumentInstances.add(objectThatIsAssignableFromGeneric(hashMap,parameterType));
}
return argumentInstances.toArray();

}

@Override
public Object[] resolveTypeInstances(Class<?>... argTypes) {
Expand All @@ -85,5 +100,26 @@ private Object objectThatIsAssignableFrom(Class<?> argType) {
}
return null;
}

private Object objectThatIsAssignableFromGeneric(HashMap<String, Type> hashMap, Type parameterType) {
Class<?> typeclass = null;
// converts parameter Type into Class
if (parameterType instanceof Class) {
typeclass = (Class<?>) parameterType;
} else if (parameterType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) parameterType;
typeclass = (Class<?>) parameterizedType.getRawType();
}
assert typeclass != null;
// for each mock object
for (Object object : objects) {
if (typeclass.isAssignableFrom(object.getClass())) {
// if mock object class(including parameterized classes) matches class of constructor class
if (hashMap.get(object.toString()) == null) continue;
if (hashMap.get(object.toString()).equals(parameterType)) return object;
}
}
return null;
}
}
}
Expand Up @@ -165,6 +165,7 @@ public interface ConstructorArgumentResolver {
* @return The argument instances to be given to the constructor, should not be null.
*/
Object[] resolveTypeInstances(Class<?>... argTypes);
Object[] resolveTypeInstancesGeneric(HashMap<String, Type> hashMap, Type[] types);
}

private interface ConstructorInstantiator {
Expand Down Expand Up @@ -284,9 +285,17 @@ private int countMockableParams(Constructor<?> constructor) {

@Override
public FieldInitializationReport instantiate() {
Field[] fields = testClass.getClass().getDeclaredFields();
HashMap<String, Type> hashmap = new HashMap<>();

for (Field field : fields) {
hashmap.put(field.getName(), field.getGenericType());
}
final MemberAccessor accessor = Plugins.getMemberAccessor();
Constructor<?> constructor = biggestConstructor(field.getType());
final Object[] args = argResolver.resolveTypeInstances(constructor.getParameterTypes());
final Object[] args = argResolver.resolveTypeInstancesGeneric(
hashmap, constructor.getGenericParameterTypes());
//final Object[] args = argResolver.resolveTypeInstances(constructor.getParameterTypes());
try {
Object newFieldInstance = accessor.newInstance(constructor, args);
accessor.set(field, testClass, newFieldInstance);
Expand Down

0 comments on commit 0860571

Please sign in to comment.