Repository: JsonMapper/JsonMapper (php)

Issue:
Support variadic setter methods. 
**Is your feature request related to a problem? Please describe.**
As requested [here](https://github.com/cweiske/jsonmapper/issues/176)  support for variadic setter methods should be added to this version of JsonMapper. 

**Describe the solution you'd like**
Support for these type of setter methods are needed and the property mapper should be able to utilize such a setter. 

**Describe alternatives you've considered**
Since JsonMapper tries to move closer to people’s models instead models moving towards JsonMapper this seems like the correct way forward. 

**Additional context**
N/A


Pull request description:
Add support for variadic setter function
This PR would resolve #67 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d040f6..b1d68f9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Unreleased]
+### Added
+- Support variadic setter function. [PR#68](https://github.com/JsonMapper/JsonMapper/pull/68)
 
 ## [2.0.0] - 2021-01-07
 ### Changed
diff --git a/src/Handler/PropertyMapper.php b/src/Handler/PropertyMapper.php
index 2092b27..cabbba5 100644
--- a/src/Handler/PropertyMapper.php
+++ b/src/Handler/PropertyMapper.php
@@ -67,9 +67,17 @@ class PropertyMapper
             return;
         }
 
-        $setterMethod = 'set' . ucfirst($propertyInfo->getName());
-        if (method_exists($object->getObject(), $setterMethod)) {
-            $object->getObject()->$setterMethod($value);
+        $methodName = 'set' . ucfirst($propertyInfo->getName());
+        if (method_exists($object->getObject(), $methodName)) {
+            $method = new \ReflectionMethod($object->getObject(), $methodName);
+            $parameters = $method->getParameters();
+
+            if (is_array($value) && count($parameters) === 1 && $parameters[0]->isVariadic()) {
+                $object->getObject()->$methodName(...$value);
+                return;
+            }
+
+            $object->getObject()->$methodName($value);
             return;
         }
 


Test patch:
diff --git a/tests/Integration/JsonMapperTest.php b/tests/Integration/JsonMapperTest.php
index 98eb6aa..5ec7ffe 100644
--- a/tests/Integration/JsonMapperTest.php
+++ b/tests/Integration/JsonMapperTest.php
@@ -427,6 +427,34 @@ class JsonMapperTest extends TestCase
         self::assertEquals($now, $object->moment);
     }
 
+    public function testItCanMapAnArrayUsingAVariadicSetter(): void
+    {
+        // Arrange
+        $mapper = (new JsonMapperFactory())->bestFit();
+        $object = new class {
+            /** @var Popo[] */
+            private $popos;
+
+            public function setPopos(Popo ...$popos): void
+            {
+                $this->popos = $popos;
+            }
+
+            public function getPopos(): array
+            {
+                return $this->popos;
+            }
+        };
+        $json = (object) ['popos' => [(object) ['name' => 'one'], (object) ['name' => 'two']]];
+
+        // Act
+        $mapper->mapObject($json, $object);
+
+        // Assert
+        self::assertEquals($object->getPopos()[0]->name, $json->popos[0]->name);
+        self::assertEquals($object->getPopos()[1]->name, $json->popos[1]->name);
+    }
+
     public function scalarValueDataTypes(): array
     {
         return [
diff --git a/tests/Unit/Handler/PropertyMapperTest.php b/tests/Unit/Handler/PropertyMapperTest.php
index 8c0cb66..950a752 100644
--- a/tests/Unit/Handler/PropertyMapperTest.php
+++ b/tests/Unit/Handler/PropertyMapperTest.php
@@ -464,6 +464,42 @@ class PropertyMapperTest extends TestCase
         self::assertEquals($json->id, $object->id);
     }
 
+    /**
+     * @covers \JsonMapper\Handler\PropertyMapper
+     */
+    public function testItCanMapUsingAVariadicSetterFunction(): void
+    {
+        $property = PropertyBuilder::new()
+            ->setName('numbers')
+            ->setIsNullable(false)
+            ->setVisibility(Visibility::PRIVATE())
+            ->build();
+        $propertyMap = new PropertyMap();
+        $propertyMap->addProperty($property);
+        $json = (object) ['numbers' => [1, 2, 3, 4, 5]];
+        $object = new class {
+            /** @var int[] */
+            private $numbers;
+
+            public function getNumbers(): array
+            {
+                return $this->numbers;
+            }
+
+            public function setNumbers(int ...$numbers): void
+            {
+                $this->numbers = $numbers;
+            }
+        };
+        $wrapped = new ObjectWrapper($object);
+        $propertyMapper = new PropertyMapper();
+        $jsonMapper = (new JsonMapperFactory())->create($propertyMapper, new DocBlockAnnotations(new NullCache()));
+
+        $propertyMapper->__invoke($json, $wrapped, $propertyMap, $jsonMapper);
+
+        self::assertEquals([1, 2, 3, 4, 5], $object->getNumbers());
+    }
+
     public function scalarValueDataTypes(): array
     {
         return [