From 132689cfb1fd861ed64a08d4ae6305dc75cb5d26 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Tue, 16 Feb 2021 14:30:37 +0300 Subject: [PATCH 1/6] Allow generating documentation when property and method start from "is" (property `isActive` and method `isActive`) --- CHANGELOG.md | 1 + src/JsonSchema/SchemaFactory.php | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b763b90a50..9bec670bbbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Mercure: Do not use data in options when deleting (#4056) * Doctrine: Support for foreign identifiers +* SchemaFactory: Allow generating documentation when property and method start from "is" (property `isActive` and method `isActive`) ## 2.6.2 diff --git a/src/JsonSchema/SchemaFactory.php b/src/JsonSchema/SchemaFactory.php index 2093ef60b93..f7f4e0343aa 100644 --- a/src/JsonSchema/SchemaFactory.php +++ b/src/JsonSchema/SchemaFactory.php @@ -327,6 +327,9 @@ private function getFactoryOptions(array $serializerContext, array $validationGr { $options = []; + /* @see https://github.com/symfony/symfony/blob/v5.1.0/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php */ + $options['enable_getter_setter_extraction'] = true; + if (isset($serializerContext[AbstractNormalizer::GROUPS])) { /* @see https://github.com/symfony/symfony/blob/v4.2.6/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php */ $options['serializer_groups'] = (array) $serializerContext[AbstractNormalizer::GROUPS]; From 7172b0a589ac93f9d9426f6a29b3d7291a7dcc28 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Tue, 16 Feb 2021 16:22:33 +0300 Subject: [PATCH 2/6] add isDummyBoolean to tests --- .../Common/Filter/BooleanFilterTestTrait.php | 5 ++++ .../Doctrine/Orm/Filter/ExistsFilterTest.php | 5 ++++ .../Doctrine/Orm/Filter/OrderFilterTest.php | 12 +++++++++ .../Doctrine/Orm/Filter/RangeFilterTest.php | 25 +++++++++++++++++++ .../Doctrine/Orm/Filter/SearchFilterTest.php | 14 +++++++++++ tests/Fixtures/TestBundle/Entity/Dummy.php | 25 ++++++++++++++++++- tests/Hydra/JsonSchema/SchemaFactoryTest.php | 2 +- 7 files changed, 86 insertions(+), 2 deletions(-) diff --git a/tests/Bridge/Doctrine/Common/Filter/BooleanFilterTestTrait.php b/tests/Bridge/Doctrine/Common/Filter/BooleanFilterTestTrait.php index 3745fd2b02a..9c2e0daff66 100644 --- a/tests/Bridge/Doctrine/Common/Filter/BooleanFilterTestTrait.php +++ b/tests/Bridge/Doctrine/Common/Filter/BooleanFilterTestTrait.php @@ -46,6 +46,11 @@ public function testGetDescriptionDefaultFields() 'type' => 'bool', 'required' => false, ], + 'isDummyBoolean' => [ + 'property' => 'isDummyBoolean', + 'type' => 'bool', + 'required' => false, + ], ], $filter->getDescription($this->resourceClass)); } diff --git a/tests/Bridge/Doctrine/Orm/Filter/ExistsFilterTest.php b/tests/Bridge/Doctrine/Orm/Filter/ExistsFilterTest.php index 471a74689fe..4ecdf1f21f7 100644 --- a/tests/Bridge/Doctrine/Orm/Filter/ExistsFilterTest.php +++ b/tests/Bridge/Doctrine/Orm/Filter/ExistsFilterTest.php @@ -90,6 +90,11 @@ public function testGetDescriptionDefaultFields() 'type' => 'bool', 'required' => false, ], + 'exists[isDummyBoolean]' => [ + 'property' => 'isDummyBoolean', + 'type' => 'bool', + 'required' => false, + ], ], $filter->getDescription($this->resourceClass)); } diff --git a/tests/Bridge/Doctrine/Orm/Filter/OrderFilterTest.php b/tests/Bridge/Doctrine/Orm/Filter/OrderFilterTest.php index 77417ba1714..c2c3965c7fb 100644 --- a/tests/Bridge/Doctrine/Orm/Filter/OrderFilterTest.php +++ b/tests/Bridge/Doctrine/Orm/Filter/OrderFilterTest.php @@ -180,6 +180,18 @@ public function testGetDescriptionDefaultFields() ], ], ], + 'order[isDummyBoolean]' => [ + 'property' => 'isDummyBoolean', + 'type' => 'string', + 'required' => false, + 'schema' => [ + 'type' => 'string', + 'enum' => [ + 'asc', + 'desc', + ], + ], + ], ], $filter->getDescription($this->resourceClass)); } diff --git a/tests/Bridge/Doctrine/Orm/Filter/RangeFilterTest.php b/tests/Bridge/Doctrine/Orm/Filter/RangeFilterTest.php index 178b379ecdb..25416d1ef2c 100644 --- a/tests/Bridge/Doctrine/Orm/Filter/RangeFilterTest.php +++ b/tests/Bridge/Doctrine/Orm/Filter/RangeFilterTest.php @@ -332,6 +332,31 @@ public function testGetDescriptionDefaultFields() 'type' => 'string', 'required' => false, ], + 'isDummyBoolean[between]' => [ + 'property' => 'isDummyBoolean', + 'type' => 'string', + 'required' => false, + ], + 'isDummyBoolean[gt]' => [ + 'property' => 'isDummyBoolean', + 'type' => 'string', + 'required' => false, + ], + 'isDummyBoolean[gte]' => [ + 'property' => 'isDummyBoolean', + 'type' => 'string', + 'required' => false, + ], + 'isDummyBoolean[lt]' => [ + 'property' => 'isDummyBoolean', + 'type' => 'string', + 'required' => false, + ], + 'isDummyBoolean[lte]' => [ + 'property' => 'isDummyBoolean', + 'type' => 'string', + 'required' => false, + ], ], $filter->getDescription($this->resourceClass)); } diff --git a/tests/Bridge/Doctrine/Orm/Filter/SearchFilterTest.php b/tests/Bridge/Doctrine/Orm/Filter/SearchFilterTest.php index 1dbb23905dd..5d83a002c8a 100644 --- a/tests/Bridge/Doctrine/Orm/Filter/SearchFilterTest.php +++ b/tests/Bridge/Doctrine/Orm/Filter/SearchFilterTest.php @@ -214,6 +214,20 @@ public function testGetDescriptionDefaultFields() 'strategy' => 'exact', 'is_collection' => true, ], + 'isDummyBoolean' => [ + 'property' => 'isDummyBoolean', + 'type' => 'bool', + 'required' => false, + 'strategy' => 'exact', + 'is_collection' => false, + ], + 'isDummyBoolean[]' => [ + 'property' => 'isDummyBoolean', + 'type' => 'bool', + 'required' => false, + 'strategy' => 'exact', + 'is_collection' => true, + ], ], $filter->getDescription($this->resourceClass)); } diff --git a/tests/Fixtures/TestBundle/Entity/Dummy.php b/tests/Fixtures/TestBundle/Entity/Dummy.php index af81454acb1..43d60f3c4ea 100644 --- a/tests/Fixtures/TestBundle/Entity/Dummy.php +++ b/tests/Fixtures/TestBundle/Entity/Dummy.php @@ -94,6 +94,13 @@ class Dummy */ public $dummyBoolean; + /** + * @var bool A dummy boolean + * + * @ORM\Column(type="boolean", nullable=true) + */ + public $isDummyBoolean; + /** * @var \DateTime A dummy date * @@ -316,7 +323,7 @@ public function setRelatedOwningDummy(RelatedOwningDummy $relatedOwningDummy) /** * @return bool */ - public function isDummyBoolean() + public function getDummyBoolean() { return $this->dummyBoolean; } @@ -329,6 +336,22 @@ public function setDummyBoolean($dummyBoolean) $this->dummyBoolean = $dummyBoolean; } + /** + * @return bool + */ + public function isDummyBoolean() + { + return $this->isDummyBoolean; + } + + /** + * @param bool $isDummyBoolean + */ + public function setIsDummyBoolean($isDummyBoolean) + { + $this->isDummyBoolean = $isDummyBoolean; + } + public function setDummy($dummy = null) { $this->dummy = $dummy; diff --git a/tests/Hydra/JsonSchema/SchemaFactoryTest.php b/tests/Hydra/JsonSchema/SchemaFactoryTest.php index f80caf4dcb9..5c29c60ae6b 100644 --- a/tests/Hydra/JsonSchema/SchemaFactoryTest.php +++ b/tests/Hydra/JsonSchema/SchemaFactoryTest.php @@ -39,7 +39,7 @@ protected function setUp(): void $resourceMetadataFactory = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactory->create(Dummy::class)->willReturn(new ResourceMetadata(Dummy::class)); $propertyNameCollectionFactory = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactory->create(Dummy::class, [])->willReturn(new PropertyNameCollection()); + $propertyNameCollectionFactory->create(Dummy::class, ['enable_getter_setter_extraction' => true])->willReturn(new PropertyNameCollection()); $propertyMetadataFactory = $this->prophesize(PropertyMetadataFactoryInterface::class); $baseSchemaFactory = new BaseSchemaFactory( From 351172a144eb807c5665f5e0437dc2c0caf1563f Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Tue, 16 Feb 2021 16:52:26 +0300 Subject: [PATCH 3/6] Fix Behat tests --- features/hal/collection.feature | 13 +++++++++++++ features/hal/hal.feature | 2 ++ features/json/relation.feature | 1 + features/jsonapi/related-resouces-inclusion.feature | 1 + features/main/content_negotiation.feature | 9 +++++---- features/main/crud.feature | 4 ++++ features/main/relation.feature | 1 + features/main/subresource.feature | 2 ++ features/security/strong_typing.feature | 5 +++-- features/security/unknown_attributes.feature | 1 + phpunit.xml.dist | 1 + 11 files changed, 34 insertions(+), 6 deletions(-) diff --git a/features/hal/collection.feature b/features/hal/collection.feature index 8507c886621..2b801be527e 100644 --- a/features/hal/collection.feature +++ b/features/hal/collection.feature @@ -73,6 +73,7 @@ Feature: HAL Collections support "description": "Smart dummy.", "dummy": "SomeDummyTest1", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -93,6 +94,7 @@ Feature: HAL Collections support "description": "Not so smart dummy.", "dummy": "SomeDummyTest2", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -113,6 +115,7 @@ Feature: HAL Collections support "description": "Smart dummy.", "dummy": "SomeDummyTest3", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -180,6 +183,7 @@ Feature: HAL Collections support "description": "Smart dummy.", "dummy": "SomeDummyTest7", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -200,6 +204,7 @@ Feature: HAL Collections support "description": "Not so smart dummy.", "dummy": "SomeDummyTest8", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -220,6 +225,7 @@ Feature: HAL Collections support "description": "Smart dummy.", "dummy": "SomeDummyTest9", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -278,6 +284,7 @@ Feature: HAL Collections support "description": "Not so smart dummy.", "dummy": "SomeDummyTest10", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -339,6 +346,7 @@ Feature: HAL Collections support "description": "Not so smart dummy.", "dummy": "SomeDummyTest4", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -359,6 +367,7 @@ Feature: HAL Collections support "description": "Smart dummy.", "dummy": "SomeDummyTest5", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -379,6 +388,7 @@ Feature: HAL Collections support "description": "Not so smart dummy.", "dummy": "SomeDummyTest6", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -501,6 +511,7 @@ Feature: HAL Collections support "description": "Not so smart dummy.", "dummy": "SomeDummyTest2", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -550,6 +561,7 @@ Feature: HAL Collections support "description": "Not so smart dummy.", "dummy": "SomeDummyTest8", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -599,6 +611,7 @@ Feature: HAL Collections support "description": "Not so smart dummy.", "dummy": "SomeDummyTest8", "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, diff --git a/features/hal/hal.feature b/features/hal/hal.feature index 933c844caed..d0cf487fc58 100644 --- a/features/hal/hal.feature +++ b/features/hal/hal.feature @@ -71,6 +71,7 @@ Feature: HAL support "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": "2015-03-01T10:00:00+00:00", "dummyFloat": null, "dummyPrice": null, @@ -114,6 +115,7 @@ Feature: HAL support "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": "2015-03-01T10:00:00+00:00", "dummyFloat": null, "dummyPrice": null, diff --git a/features/json/relation.feature b/features/json/relation.feature index 7c39dc75f71..129b3bc189e 100644 --- a/features/json/relation.feature +++ b/features/json/relation.feature @@ -208,6 +208,7 @@ Feature: JSON relations support "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, diff --git a/features/jsonapi/related-resouces-inclusion.feature b/features/jsonapi/related-resouces-inclusion.feature index d2850d7ea49..34ab3dfbb31 100644 --- a/features/jsonapi/related-resouces-inclusion.feature +++ b/features/jsonapi/related-resouces-inclusion.feature @@ -338,6 +338,7 @@ Feature: JSON API Inclusion of Related Resources "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, diff --git a/features/main/content_negotiation.feature b/features/main/content_negotiation.feature index f6f6593c448..4d12ec0e679 100644 --- a/features/main/content_negotiation.feature +++ b/features/main/content_negotiation.feature @@ -19,7 +19,7 @@ Feature: Content Negotiation support And the XML should be equal to: """ - 1XML! + 1XML! """ Scenario: Retrieve a collection in XML @@ -31,7 +31,7 @@ Feature: Content Negotiation support And the XML should be equal to: """ - 1XML! + 1XML! """ Scenario: Retrieve a collection in XML using the .xml URL @@ -42,7 +42,7 @@ Feature: Content Negotiation support And the XML should be equal to: """ - 1XML! + 1XML! """ Scenario: Retrieve a collection in JSON @@ -58,6 +58,7 @@ Feature: Content Negotiation support "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -89,7 +90,7 @@ Feature: Content Negotiation support And the XML should be equal to: """ - 2Sent in JSON + 2Sent in JSON """ Scenario: Requesting the same format in the Accept header and in the URL should work diff --git a/features/main/crud.feature b/features/main/crud.feature index f73bb80f8f6..150b4333342 100644 --- a/features/main/crud.feature +++ b/features/main/crud.feature @@ -33,6 +33,7 @@ Feature: Create-Retrieve-Update-Delete "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": "2015-03-01T10:00:00+00:00", "dummyFloat": null, "dummyPrice": null, @@ -69,6 +70,7 @@ Feature: Create-Retrieve-Update-Delete "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": "2015-03-01T10:00:00+00:00", "dummyFloat": null, "dummyPrice": null, @@ -119,6 +121,7 @@ Feature: Create-Retrieve-Update-Delete "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": "2015-03-01T10:00:00+00:00", "dummyFloat": null, "dummyPrice": null, @@ -523,6 +526,7 @@ Feature: Create-Retrieve-Update-Delete "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": "2018-12-01T13:12:00+00:00", "dummyFloat": null, "dummyPrice": null, diff --git a/features/main/relation.feature b/features/main/relation.feature index 8c268ed8417..37f97588e2c 100644 --- a/features/main/relation.feature +++ b/features/main/relation.feature @@ -155,6 +155,7 @@ Feature: Relations support "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, diff --git a/features/main/subresource.feature b/features/main/subresource.feature index c2f0341c600..3746d443dae 100644 --- a/features/main/subresource.feature +++ b/features/main/subresource.feature @@ -383,6 +383,7 @@ Feature: Subresource support "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -416,6 +417,7 @@ Feature: Subresource support "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, diff --git a/features/security/strong_typing.feature b/features/security/strong_typing.feature index ef630a2c27a..dab2e8caf44 100644 --- a/features/security/strong_typing.feature +++ b/features/security/strong_typing.feature @@ -25,6 +25,7 @@ Feature: Handle properly invalid data submitted to the API "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, @@ -33,8 +34,8 @@ Feature: Handle properly invalid data submitted to the API "jsonData": [], "arrayData": [], "name_converted": null, - "relatedOwnedDummy": null, - "relatedOwningDummy": null, + "relatedOwnedDummy": null, + "relatedOwningDummy": null, "id": 1, "name": "Not existing", "alias": null, diff --git a/features/security/unknown_attributes.feature b/features/security/unknown_attributes.feature index efe7b954c0a..4e7d4cb9e66 100644 --- a/features/security/unknown_attributes.feature +++ b/features/security/unknown_attributes.feature @@ -25,6 +25,7 @@ Feature: Ignore unknown attributes "description": null, "dummy": null, "dummyBoolean": null, + "isDummyBoolean": null, "dummyDate": null, "dummyFloat": null, "dummyPrice": null, diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4518373e404..5a032936aa2 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,6 +6,7 @@ backupGlobals="false" bootstrap="tests/Fixtures/app/bootstrap.php" colors="true" + stopOnFailure="true" > From 327983cba91b0f2922df9c19dabb4998e9f2cc72 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Tue, 16 Feb 2021 16:55:18 +0300 Subject: [PATCH 4/6] revert phpunit.xml.dist --- phpunit.xml.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5a032936aa2..4518373e404 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,7 +6,6 @@ backupGlobals="false" bootstrap="tests/Fixtures/app/bootstrap.php" colors="true" - stopOnFailure="true" > From 22846bb2d51e4f1558e8b73c318a19c08b267758 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Tue, 16 Feb 2021 17:04:46 +0300 Subject: [PATCH 5/6] add isDummyBoolean to the Dummy Document --- tests/Fixtures/TestBundle/Document/Dummy.php | 25 +++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/Fixtures/TestBundle/Document/Dummy.php b/tests/Fixtures/TestBundle/Document/Dummy.php index 8e276fe7939..12cdc4b811a 100644 --- a/tests/Fixtures/TestBundle/Document/Dummy.php +++ b/tests/Fixtures/TestBundle/Document/Dummy.php @@ -98,6 +98,13 @@ class Dummy */ public $dummyBoolean; + /** + * @var bool A dummy boolean + * + * @ODM\Field(type="bool", nullable=true) + */ + public $isDummyBoolean; + /** * @var \DateTime A dummy date * @@ -315,7 +322,7 @@ public function setRelatedOwningDummy(RelatedOwningDummy $relatedOwningDummy) /** * @return bool */ - public function isDummyBoolean() + public function getDummyBoolean() { return $this->dummyBoolean; } @@ -328,6 +335,22 @@ public function setDummyBoolean($dummyBoolean) $this->dummyBoolean = $dummyBoolean; } + /** + * @return bool + */ + public function isDummyBoolean() + { + return $this->isDummyBoolean; + } + + /** + * @param bool $isDummyBoolean + */ + public function setIsDummyBoolean($isDummyBoolean) + { + $this->isDummyBoolean = $isDummyBoolean; + } + public function setDummy($dummy = null) { $this->dummy = $dummy; From 687a7273a4bea0da50afcbf4982d32da65267bb3 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Tue, 16 Feb 2021 17:05:40 +0300 Subject: [PATCH 6/6] follow code style --- src/JsonSchema/SchemaFactory.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/JsonSchema/SchemaFactory.php b/src/JsonSchema/SchemaFactory.php index f7f4e0343aa..561814223a6 100644 --- a/src/JsonSchema/SchemaFactory.php +++ b/src/JsonSchema/SchemaFactory.php @@ -325,10 +325,10 @@ private function getValidationGroups(ResourceMetadata $resourceMetadata, ?string */ private function getFactoryOptions(array $serializerContext, array $validationGroups, ?string $operationType, ?string $operationName): array { - $options = []; - - /* @see https://github.com/symfony/symfony/blob/v5.1.0/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php */ - $options['enable_getter_setter_extraction'] = true; + $options = [ + /* @see https://github.com/symfony/symfony/blob/v5.1.0/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php */ + 'enable_getter_setter_extraction' => true, + ]; if (isset($serializerContext[AbstractNormalizer::GROUPS])) { /* @see https://github.com/symfony/symfony/blob/v4.2.6/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php */