Problem/Motivation

When encoding into xml, this error appears when there are embed objects in the response:

Fatal error: Call to a member function normalize() on a non-object in vendor/symfony/serializer/Encoder/XmlEncoder.php on line 476

This is because, Drupal\serialization\Encoder\XmlEncoder is never setting the $baseEncoder serializer.

Proposed resolution

In Drupal\serialization\Encoder\XmlEncoder::getBaseEncoder() we should call Symfony\Component\Serializer\Encoder\SerializerAwareEncoder::setSerializer() and set the serializer.

Remaining tasks

  1. Write Patch

User interface changes

N/A

API changes

After the change, XML format should work just like JSON.

Data model changes

N/A

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

davidwbarratt created an issue. See original summary.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

cilefen’s picture

Title: Fatal error: Call to a member function normalize() on a non-object in vendor/symfony/serializer/Encoder/XmlEncoder.php on line 476 » Fatal error: Call to a member function normalize() on a non-object in XmlEncoder when encoding into xml and there are embedded objects in the response
ec0g’s picture

Issue tags: +neworleans2016

Working on reproducing this issue in the 8.2-x branch.

ec0g’s picture

@davidwbarratt or @cilefen, what's the best way to reproduce the issue? Are you using a REST view with an XML serializer? If so what kind of fields are you exporting?

I see where the "Symfony\Component\Serializer\Encoder\XmlEncoder" object is being instantiated without a serializer. I also see a serializer should have an instance (or multiple) of a normalizer in order for it to be able to normalize an object.

I haven't dug around this code at all, and I see that there's definitely a bug, but it will help if I can reproduce it. Thanks!

cilefen’s picture

Come find me in the sprint room.

cilefen’s picture

Sorry, mentoring room...

ec0g’s picture

Sucks I missed you earlier @cilefen. Had to leave at 3pm.

damiankloip’s picture

FileSize
1.24 KB

This is likely still the same problem it was, this is the fix. I'm pretty sure I can reproduce but some steps in the issue description here would be good. There is a unit test for this, but the base encoder is set manually for the test so it can be mocked. So we might want to think about that. We could probably expose this in \Drupal\serialization\Tests\EntitySerializationTest but likely there is not an object getting serialized in that test so the serializer on the base xml encoder is not called.

damiankloip’s picture

I think maybe this is not exposed in the regular entity tests also, because the entity is first normalized, which converts everything to an array. If you did the following, it would expose the bug:

$container->get('serializer')->encode(['a' => User::load(123)], 'xml')
damiankloip’s picture

Something simple like this can test it. A test only patch won't really show much though as the patch is required to have the setSerializer() method on the encoder.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Grayside’s picture

Issue tags: +xml
Wim Leers’s picture

Title: Fatal error: Call to a member function normalize() on a non-object in XmlEncoder when encoding into xml and there are embedded objects in the response » [PP-1] Fatal error: Call to a member function normalize() on a non-object in XmlEncoder when encoding into xml and there are embedded objects in the response
Status: Needs review » Postponed
Issue tags: +Needs tests
Related issues: +#2815845: Importing (deploying) REST resource config entities should automatically do the necessary route rebuilding, +#2800873: Add XML GET REST test coverage, work around XML encoder quirks

The only way I can reproduce this is if I add xml to one of the REST resource config entities (i.e. to make it support XML), but then fail to rebuild the router.

That's being fixed in #2815845: Importing (deploying) REST resource config entities should automatically do the necessary route rebuilding.


If you think this issue still needs to be resolved: this issue will need an IS update to clarify how to reproduce this, and test to prove that it's fixed.

Finally: in #2800873: Add XML GET REST test coverage, work around XML encoder quirks, we're considering to remove XML support.

Wim Leers’s picture

Priority: Major » Normal

Also, this is normal at best if this has received zero confirmations since it was reported: it doesn't seem to affect many sites. Also only 7 followers. Probably because almost no sites use the XML serializer.

Downgrading to normal.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

damiankloip’s picture

Status: Postponed » Needs review
Issue tags: -Needs tests

This can be reproduced quite easily IIRC, if you are using the serializer outside of rest. Not sure how not rebuilding the router would reproduce this issue? REST endpoints are not the only user of the serializer :) If you see my comment in #11 you can still reproduce this easily. As we already have the test and the fix for this, it still seems worth us just committing this.

damiankloip’s picture

Title: [PP-1] Fatal error: Call to a member function normalize() on a non-object in XmlEncoder when encoding into xml and there are embedded objects in the response » Fatal error: Call to a member function normalize() on a non-object in XmlEncoder when encoding into xml and there are embedded objects in the response
damiankloip’s picture

Patch in #11 is still good for 8.4.x

Pavan B S’s picture

Rerolled the patch against latest 8.4.x, please review.

Status: Needs review » Needs work

The last submitted patch, 20: 2685097-20.patch, failed testing.

damiankloip’s picture

Sweet, another commit mining attempt.

damiankloip’s picture

Status: Needs work » Needs review
FileSize
3.08 KB
688 bytes

The reroll was not good and broke things with a duplicate use statement.

Wim Leers’s picture

damiankloip’s picture

Hmm, well I think we should still support bugs of this nature. You can serialize anything using XML - not necessarily entities, or custom stuff. Anything really. Plus this already has the test coverage and the work is done :)

Wim Leers’s picture

Status: Needs review » Needs work

Every minute spent on improving XML support is a minute not spent on improving everything else, which is what the 99.99% use. But, sure.


+++ b/core/modules/serialization/tests/src/Unit/Encoder/XmlEncoderTest.php
@@ -76,4 +79,23 @@ public function testDecode() {
+     // The serializer should being set on the Drupal encoder should then set it

Grammatical problems here.

And can we please get a failing test-only patch and a passing complete patch? That'll help the core committer that looks at this.

damiankloip’s picture

Here are those changes quickly, I actually hit this issue when doing something for work yesterday! :)

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

I actually hit this issue when doing something for work yesterday! :)

So you're using the xml normalizer?

Aren't you also running into #2800873: Add XML GET REST test coverage, work around XML encoder quirks then?

damiankloip’s picture

Ha, well, it wasn't being used for a fieldable entity - so it was ok.

Wim Leers’s picture

Makes sense :)

The last submitted patch, 27: 2685097-27-test-only-FAIL.patch, failed testing.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: -Needs issue summary update

Committed and pushed 081132d to 8.4.x and 009a535 to 8.3.x. Thanks!

I've committed this to 8.3.x because essentially the XmlEncoder is broken and useless without this.

@ec0g thanks for trying to reproduce the issue. I thought about crediting you on this issue because of comment #5 which pinpointed where things were going wrong. But this was also included in the issue summary.

@Pavan B S I've not credited you on the issue because the reroll was not a good one. Given the patch contained a unit test that could have easily been run prior to uploading the patch to confirm the re-roll worked.

diff --git a/core/modules/serialization/tests/src/Unit/Encoder/XmlEncoderTest.php b/core/modules/serialization/tests/src/Unit/Encoder/XmlEncoderTest.php
index b0ee6b3..2a5bf3e 100644
--- a/core/modules/serialization/tests/src/Unit/Encoder/XmlEncoderTest.php
+++ b/core/modules/serialization/tests/src/Unit/Encoder/XmlEncoderTest.php
@@ -83,19 +83,21 @@ public function testDecode() {
     * @covers ::getBaseEncoder
     */
   public function testDefaultEncoderHasSerializer() {
-     // The serializer should be set on the Drupal encoder, which should then
-     // set it on our default encoder.
-     $encoder = new XmlEncoder();
-     $serialzer = new Serializer([new GetSetMethodNormalizer()]);
-     $encoder->setSerializer($serialzer);
-     $base_encoder = $encoder->getBaseEncoder();
-     $this->assertInstanceOf(BaseXmlEncoder::class, $base_encoder);
-     // Test the encoder.
-     $base_encoder->encode(['a' => new TestObject()], 'xml');
-   }
- }
- class TestObject {
+    // The serializer should be set on the Drupal encoder, which should then
+    // set it on our default encoder.
+    $encoder = new XmlEncoder();
+    $serialzer = new Serializer([new GetSetMethodNormalizer()]);
+    $encoder->setSerializer($serialzer);
+    $base_encoder = $encoder->getBaseEncoder();
+    $this->assertInstanceOf(BaseXmlEncoder::class, $base_encoder);
+    // Test the encoder.
+    $base_encoder->encode(['a' => new TestObject()], 'xml');
+  }
+
+}
+
+class TestObject {
   public function getA() {
-     return 'A';
-   }
+   return 'A';
+  }
 }

Sorted out all the spacing on commit.

  • alexpott committed 081132d on 8.4.x
    Issue #2685097 by damiankloip, Wim Leers: Fatal error: Call to a member...

  • alexpott committed 009a535 on 8.3.x
    Issue #2685097 by damiankloip, Wim Leers: Fatal error: Call to a member...
Wim Leers’s picture

Thanks for your impressive diligence, Alex!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

victor.priceputu’s picture

This fix actually breaks the serializer.
Line

$this->baseEncoder->setSerializer($this->serializer);

Using the service 'serializer.encoder.xml' no longer works, as $this->serializer is NULL.

damiankloip’s picture

That would suggest you're trying to use the XmlEncoder directly, not through the serializer. This is a standard pattern from Symfony, SerializerAwareEncoders get setSerializer() called on them when the serializer instance is created. You can't have been using this too well before due to this bug anyway. The XmlEncoder needs the serializer to do anything useful.

Wim Leers’s picture