schmittjoh / serializer

Library for (de-)serializing data of any complexity (supports JSON, and XML)
http://jmsyst.com/libs/serializer
MIT License
2.31k stars 591 forks source link

stdClass Serialization Does Not Use Property Naming Strategy #1499

Open Brandon0 opened 1 year ago

Brandon0 commented 1 year ago
Q A
Bug report? no
Feature request? no
BC Break report? maybe?
RFC? no

I am upgrading an old application that was using jms/serializer 1.14.1. I have upgraded it to 3.24.0 and am seeing different behavior that wasn't reported as a BC and I'm not finding any information about how to get back to the old ways.

The issue revolves around serializing \stdClass objects. Previous behavior would be to apply the property naming strategy, which by default meant converting camel case to snake case. On the newer version, however, \stdClass does not appear to use the property naming strategy, even if defined explicitly.

What am I missing?

Steps required to reproduce the problem

        $data = (object) [
            "success" => true,
            "financingPartnerName" => "MoneyMan",
            "dealerFee" => 6.5,
        ];
        $serializer = \JMS\Serializer\SerializerBuilder::create()
            ->setPropertyNamingStrategy(new \JMS\Serializer\Naming\CamelCaseNamingStrategy())
            ->addDefaultHandlers()
            ->build();
        $json = $serializer->serialize($data, 'json');
        dump($json);

Expected Result

{
    "success": true,
    "financing_partner_name": "MoneyMan",
    "dealer_fee": 6.5
}

Actual Result

{
    "success": true,
    "financingPartnerName": "MoneyMan",
    "dealerFee": 6.5
}
scyzoryck commented 12 months ago

Hi! It looks like this feature has been abandoned long time ago. I would suggest to create a StdClass handler that will do the job for you and register it additionally. Here is the code from the standard handler that you can reuse src/Handler/StdClassHandler.php :

    public function serializeStdClass(SerializationVisitorInterface $visitor, \stdClass $stdClass, array $type, SerializationContext $context)
    {
        $classMetadata = $context->getMetadataFactory()->getMetadataForClass('stdClass');
        $visitor->startVisitingObject($classMetadata, $stdClass, ['name' => 'stdClass']);

        foreach ((array) $stdClass as $name => $value) {
            // use naming strategy for $name here.
            $metadata = new StaticPropertyMetadata('stdClass', $name, $value);
            $visitor->visitProperty($metadata, $value);
        }

        return $visitor->endVisitingObject($classMetadata, $stdClass, ['name' => 'stdClass']);
    }
Brandon0 commented 12 months ago

Hi, thank you for the response. I did notice in the docs that there were some known limitations of serializing \stdClass and it is "discouraged", but unfortunately my application does currently rely on it in some spots.

I had a similar thought with the code you posted and have gone through the exercise and implementing our own version of the stdClassHander, however, I was unable to find how we could go about accessing the configured \JMS\Serializer\Naming\PropertyNamingStrategyInterface from the context of a handler. It seems like the only place where that strategy is defined is deep within the \JMS\Serializer\Builder\DriverFactoryInterface instance and doesn't seem accessible.

Any ideas? Thanks.

scyzoryck commented 12 months ago

Hi! I do not think that configured PropertyNamingStrategyInterface object can be fetched anywhere. But if you are using also JMS Serializer Bundle, it should be available as an service in DI container.