From 402a9af308ac9fccacbadd79d6ec84b17fe80e63 Mon Sep 17 00:00:00 2001 From: Tobias Knell Date: Wed, 21 Feb 2024 12:54:02 +0100 Subject: [PATCH] Fix constructor creation with generic types and collections --- .../strategies/AbstractCreatorStrategy.java | 11 ++-- .../strategies/JustAnotherBeanStrategy.java | 4 +- .../beanfiller/ConstructorCreationTest.java | 51 ++++++++++++------- .../testobjects/ArrayConstructorObject.java | 15 ++++++ .../testobjects/ListConstructorObject.java | 17 +++++++ .../testobjects/MapConstructorObject.java | 17 +++++++ 6 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 src/test/java/org/synyx/beanfiller/testobjects/ArrayConstructorObject.java create mode 100644 src/test/java/org/synyx/beanfiller/testobjects/ListConstructorObject.java create mode 100644 src/test/java/org/synyx/beanfiller/testobjects/MapConstructorObject.java diff --git a/src/main/java/org/synyx/beanfiller/strategies/AbstractCreatorStrategy.java b/src/main/java/org/synyx/beanfiller/strategies/AbstractCreatorStrategy.java index c9dc3c7..e7fa94c 100644 --- a/src/main/java/org/synyx/beanfiller/strategies/AbstractCreatorStrategy.java +++ b/src/main/java/org/synyx/beanfiller/strategies/AbstractCreatorStrategy.java @@ -2,7 +2,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.synyx.beanfiller.creator.Creator; import org.synyx.beanfiller.domain.ObjectInformation; import org.synyx.beanfiller.exceptions.FillingException; @@ -10,9 +9,10 @@ import org.synyx.beanfiller.services.CreatorRegistry; import org.synyx.beanfiller.util.GenericsUtils; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; - import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -236,7 +236,12 @@ protected List getTypeArgumentObjectInformation(ObjectInforma List typeArgumentObjectInformationList = new ArrayList<>(); - List actualTypeArguments = GenericsUtils.getActualTypeArguments(objectInformation.getField()); + List actualTypeArguments; + if(objectInformation.getType() instanceof ParameterizedType){ + actualTypeArguments = Arrays.asList(((ParameterizedType) objectInformation.getType()).getActualTypeArguments()); + }else{ + actualTypeArguments = GenericsUtils.getActualTypeArguments(objectInformation.getField()); + } for (Type type : actualTypeArguments) { typeArgumentObjectInformationList.add(createObjectInformationForType(type, objectInformation)); diff --git a/src/main/java/org/synyx/beanfiller/strategies/JustAnotherBeanStrategy.java b/src/main/java/org/synyx/beanfiller/strategies/JustAnotherBeanStrategy.java index ebc0a69..72c082e 100644 --- a/src/main/java/org/synyx/beanfiller/strategies/JustAnotherBeanStrategy.java +++ b/src/main/java/org/synyx/beanfiller/strategies/JustAnotherBeanStrategy.java @@ -11,6 +11,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Type; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; @@ -82,10 +83,11 @@ public Object createObjectInternal(ObjectInformation parentInformation) throws F instance = declaredConstructor.newInstance(); } else { Class[] parameterTypes = declaredConstructor.getParameterTypes(); + Type[] genericParameterTypes = declaredConstructor.getGenericParameterTypes(); Object[] parameters = new Object[declaredConstructor.getParameterCount()]; for (int i = 0; i < parameterTypes.length; i++) { - ObjectInformation information = new ObjectInformation(parameterTypes[i], null, null, null, null, + ObjectInformation information = new ObjectInformation(parameterTypes[i], null, genericParameterTypes[i], null, null, null); AbstractCreatorStrategy strategy = getStrategyManager().getStrategyFor(information); parameters[i] = strategy.createObject(information); diff --git a/src/test/java/org/synyx/beanfiller/ConstructorCreationTest.java b/src/test/java/org/synyx/beanfiller/ConstructorCreationTest.java index ad1f4b2..d4eb3b6 100644 --- a/src/test/java/org/synyx/beanfiller/ConstructorCreationTest.java +++ b/src/test/java/org/synyx/beanfiller/ConstructorCreationTest.java @@ -2,11 +2,13 @@ import org.junit.Test; import org.synyx.beanfiller.exceptions.FillingException; +import org.synyx.beanfiller.testobjects.ArrayConstructorObject; +import org.synyx.beanfiller.testobjects.ListConstructorObject; +import org.synyx.beanfiller.testobjects.MapConstructorObject; import org.synyx.beanfiller.testobjects.TestEnum; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.*; public class ConstructorCreationTest { @@ -23,30 +25,45 @@ public void createsObjectViaConstructor() throws FillingException { assertThat(object.innerObject.foo, notNullValue()); } + @Test + public void createsObjectWithListInConstructor() throws FillingException { + + ListConstructorObject listConstructorObject = new BeanFiller().fillBean(ListConstructorObject.class); + assertThat(listConstructorObject,notNullValue()); + assertThat(listConstructorObject.getValues(),notNullValue()); + assertThat(listConstructorObject.getValues().size(), is(greaterThan(0))); + } + + @Test + public void createsObjectWithArrayInConstructor() throws FillingException { + + ArrayConstructorObject object = new BeanFiller().fillBean(ArrayConstructorObject.class); + assertThat(object,notNullValue()); + assertThat(object.getValues(),notNullValue()); + assertThat(object.getValues().length, is(greaterThan(0))); + } + + @Test + public void createsObjectWithMapInConstructor() throws FillingException { + + MapConstructorObject object = new BeanFiller().fillBean(MapConstructorObject.class); + assertThat(object,notNullValue()); + assertThat(object.getValues(),notNullValue()); + assertThat(object.getValues().size(), is(greaterThan(0))); + } + public static class TestObjectWithConstructor{ private final String[] array; private final TestEnum testEnum; private final InnerObject innerObject; - TestObjectWithConstructor(String[] array, TestEnum testEnum, InnerObject innerObject){ + TestObjectWithConstructor(String[] array, TestEnum testEnum, InnerObject innerObject) { this.array = array; this.testEnum = testEnum; this.innerObject = innerObject; } - - public String[] getArray() { - return array; - } - - public TestEnum getTestEnum() { - return testEnum; - } - - public InnerObject getInnerObject() { - return innerObject; - } } public static class InnerObject{ @@ -56,9 +73,5 @@ public static class InnerObject{ public InnerObject(String foo) { this.foo = foo; } - - public String getFoo() { - return foo; - } } } diff --git a/src/test/java/org/synyx/beanfiller/testobjects/ArrayConstructorObject.java b/src/test/java/org/synyx/beanfiller/testobjects/ArrayConstructorObject.java new file mode 100644 index 0000000..6331fc1 --- /dev/null +++ b/src/test/java/org/synyx/beanfiller/testobjects/ArrayConstructorObject.java @@ -0,0 +1,15 @@ +package org.synyx.beanfiller.testobjects; + +public class ArrayConstructorObject { + + private final String[] values; + + public ArrayConstructorObject(String[] values){ + + this.values = values; + } + + public String[] getValues() { + return values; + } +} diff --git a/src/test/java/org/synyx/beanfiller/testobjects/ListConstructorObject.java b/src/test/java/org/synyx/beanfiller/testobjects/ListConstructorObject.java new file mode 100644 index 0000000..97676be --- /dev/null +++ b/src/test/java/org/synyx/beanfiller/testobjects/ListConstructorObject.java @@ -0,0 +1,17 @@ +package org.synyx.beanfiller.testobjects; + +import java.util.List; + +public class ListConstructorObject { + + private final List values; + + public ListConstructorObject(List values){ + + this.values = values; + } + + public List getValues() { + return values; + } +} diff --git a/src/test/java/org/synyx/beanfiller/testobjects/MapConstructorObject.java b/src/test/java/org/synyx/beanfiller/testobjects/MapConstructorObject.java new file mode 100644 index 0000000..887e9bb --- /dev/null +++ b/src/test/java/org/synyx/beanfiller/testobjects/MapConstructorObject.java @@ -0,0 +1,17 @@ +package org.synyx.beanfiller.testobjects; + +import java.util.Map; + +public class MapConstructorObject { + + private final Map values; + + public MapConstructorObject(Map values){ + + this.values = values; + } + + public Map getValues() { + return values; + } +}