Repository: JsonMapper/JsonMapper (php)

Issue:
Cannot lookup property of namespace in parent class
**Describe the bug**
The mapper does not correctly lookup the namespace of a property in a parent class correctly

**To Reproduce**
I have something like these classes:
```php
<?php

declare(strict_types = 1);

namespace Foo;

use Bar\UpdateCustomer;

class Customer extends UpdateCustomer
{
}

```

```php
<?php

declare(strict_types = 1);

namespace Bar;

class UpdateCustomer
{
    /** @var null|CustomerState */
    public $customerState;

}

```

```php
<?php

declare(strict_types = 1);

namespace Bar;

class CustomerState
{
    /** @var null|string */
    public $description;
}
```

**Expected behavior**
The properties should be mapped correctly

**Stacktrace**
Unable to map to CustomerState

**Environment (please complete the following information):**
 - PHP: 7.2
 
**Additional context**

It seems the Bar namespace is not evaluated with the lookup for the CustomerState.
If I just a "use Bar\CustomerState;" to the initial customer class it works.


Pull request:
Fix namespace resolving for properties in parent namespace
Fixes #134 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77ba8fd..9df2b2d 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]
+### Fixed
+- Cannot lookup property of namespace in parent class [PR#135](https://github.com/JsonMapper/JsonMapper/pull/135) Thanks to [jg-development](https://github.com/jg-development) for reporting the issue 
 
 ## [2.11.1] - 2022-03-08
 ### Fixed
diff --git a/src/Middleware/NamespaceResolver.php b/src/Middleware/NamespaceResolver.php
index 48a68c3..79cdfa0 100644
--- a/src/Middleware/NamespaceResolver.php
+++ b/src/Middleware/NamespaceResolver.php
@@ -83,11 +83,19 @@ class NamespaceResolver extends AbstractMiddleware
             return new PropertyType(\array_shift($matches)->getImport(), $type->isArray());
         }
 
-        if (class_exists($object->getReflectedObject()->getNamespaceName() . '\\' . $type->getType())) {
-            return new PropertyType(
-                $object->getReflectedObject()->getNamespaceName() . '\\' . $type->getType(),
-                $type->isArray()
-            );
+        $reflectedObject = $object->getReflectedObject();
+        while (true) {
+            if (class_exists($reflectedObject->getNamespaceName() . '\\' . $type->getType())) {
+                return new PropertyType(
+                    $reflectedObject->getNamespaceName() . '\\' . $type->getType(),
+                    $type->isArray()
+                );
+            }
+
+            $reflectedObject = $reflectedObject->getParentClass();
+            if (! $reflectedObject) {
+                break;
+            }
         }
 
         return $type;


Test patch:
diff --git a/tests/Implementation/Bar/CustomerState.php b/tests/Implementation/Bar/CustomerState.php
new file mode 100644
index 0000000..8b3f264
--- /dev/null
+++ b/tests/Implementation/Bar/CustomerState.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace JsonMapper\Tests\Implementation\Bar;
+
+class CustomerState
+{
+    /** @var null|string */
+    public $description;
+}
diff --git a/tests/Implementation/Bar/UpdateCustomer.php b/tests/Implementation/Bar/UpdateCustomer.php
new file mode 100644
index 0000000..a1c63dc
--- /dev/null
+++ b/tests/Implementation/Bar/UpdateCustomer.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace JsonMapper\Tests\Implementation\Bar;
+
+class UpdateCustomer
+{
+    /** @var null|CustomerState */
+    public $customerState;
+}
diff --git a/tests/Implementation/Foo/Customer.php b/tests/Implementation/Foo/Customer.php
new file mode 100644
index 0000000..1105da4
--- /dev/null
+++ b/tests/Implementation/Foo/Customer.php
@@ -0,0 +1,11 @@
+<?php
+
+declare(strict_types=1);
+
+namespace JsonMapper\Tests\Implementation\Foo;
+
+use JsonMapper\Tests\Implementation\Bar\UpdateCustomer;
+
+class Customer extends UpdateCustomer
+{
+}
diff --git a/tests/Unit/Middleware/NamespaceResolverTest.php b/tests/Unit/Middleware/NamespaceResolverTest.php
index 4d78a47..36097c1 100644
--- a/tests/Unit/Middleware/NamespaceResolverTest.php
+++ b/tests/Unit/Middleware/NamespaceResolverTest.php
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace JsonMapper\Tests\Unit\Middleware;
 
-use Exception;
+use JsonMapper\Tests\Implementation\Bar\CustomerState;
 use JsonMapper\Builders\PropertyBuilder;
 use JsonMapper\Cache\NullCache;
 use JsonMapper\Enums\Visibility;
@@ -14,6 +14,7 @@ use JsonMapper\Middleware\DocBlockAnnotations;
 use JsonMapper\Middleware\NamespaceResolver;
 use JsonMapper\Tests\Helpers\AssertThatPropertyTrait;
 use JsonMapper\Tests\Implementation\ComplexObject;
+use JsonMapper\Tests\Implementation\Foo\Customer;
 use JsonMapper\Tests\Implementation\Models\NamespaceAliasObject;
 use JsonMapper\Tests\Implementation\Models\NamespaceObject;
 use JsonMapper\Tests\Implementation\Models\Sub\AnotherValueHolder;
@@ -25,6 +26,7 @@ use JsonMapper\Wrapper\ObjectWrapper;
 use PHPUnit\Framework\Assert;
 use PHPUnit\Framework\TestCase;
 use Psr\SimpleCache\CacheInterface;
+use JsonMapper\Tests\Implementation\Bar\UpdateCustomer;
 
 class NamespaceResolverTest extends TestCase
 {
@@ -233,4 +235,24 @@ class NamespaceResolverTest extends TestCase
         self::assertInstanceOf(AnotherValueHolder::class, $object->anotherValueHolder);
         self::assertInstanceOf(ValueHolder::class, $object->valueHolder);
     }
+
+    /**
+     * @covers \JsonMapper\Middleware\NamespaceResolver
+     */
+    public function testReturnsCorrectNamespaceWithPropertyDefinedInParentInOtherNamespace(): void
+    {
+        $object = new Customer();
+        $input = (object) [
+            'customerState' => (object) ['description' => 'loremipsum'],
+        ];
+        $mapper = JsonMapperBuilder::new()
+            ->withMiddleware(new DocBlockAnnotations(new NullCache()))
+            ->withMiddleware(new NamespaceResolver(new NullCache()))
+            ->build();
+
+        $mapper->mapObject($input, $object);
+
+        self::assertInstanceOf(CustomerState::class, $object->customerState);
+        self::assertEquals($input->customerState->description, $object->customerState->description);
+    }
 }