Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialization Context Naming Strategy #1394

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

dgafka
Copy link
Contributor

@dgafka dgafka commented Feb 20, 2022

This introduces possibility to set custom naming strategy for given serialization/deserialization using SerializationContext.

Q A
Bug fix? no
New feature? yes
Doc updated no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets -
License MIT

@dgafka
Copy link
Contributor Author

dgafka commented May 22, 2022

I can't find the cause of error in scrutinizer.
@scyzoryck can you point me to it? :)

@scyzoryck
Copy link
Collaborator

Hi! @dgafka - code looks good, thanks! Could you try to rebase your branch based on the newest master? I hope it might help :)

Best, scyzoryck.

@dgafka
Copy link
Contributor Author

dgafka commented May 24, 2022

@scyzoryck @goetas can this be reviewed / merged? :)

Copy link
Collaborator

@scyzoryck scyzoryck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the code looks good, thanks for contribution! Could you add two missing test scenarios to make sure that we are not missing anything, please?
It would be nice to add new test case for PHPBench to check how it will impact performance of serialisation ;)

Best, Marcin.

src/GraphNavigator/SerializationGraphNavigator.php Outdated Show resolved Hide resolved
@dgafka dgafka requested a review from scyzoryck October 12, 2022 18:27
@dgafka
Copy link
Contributor Author

dgafka commented Oct 12, 2022

Hey @goetas @scyzoryck

I've covered changing context in next serialization runs and using context together with naming attributes.

Can you review? :)

@dgafka
Copy link
Contributor Author

dgafka commented Oct 17, 2022

@scyzoryck can we push this forward? :)

Copy link
Collaborator

@scyzoryck scyzoryck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dgafka Thanks for changes! I left one additional request. Could you also describe this feature in the docs, please?

@dgafka
Copy link
Contributor Author

dgafka commented Nov 15, 2022

@scyzoryck docs updated.
Can review?

cc:
@goetas

@dgafka
Copy link
Contributor Author

dgafka commented Nov 19, 2022

@scyzoryck thanks for reviewing :)

@goetas can we merge this?

@dgafka
Copy link
Contributor Author

dgafka commented Jun 25, 2023

Will fixing the conflicts make it possible to merge?

@scyzoryck
Copy link
Collaborator

Hi! @dgafka - fine for me to merge it :)

@dgafka
Copy link
Contributor Author

dgafka commented Dec 26, 2023

Hey @scyzoryck, PR rebased and green :)

Copy link
Collaborator

@scyzoryck scyzoryck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Great coverage with tests, no impact on the performance. 👍
I left 2 small comments :)

$cloned = clone $propertyMetadata;
$cloned->setter = null;
$this->accessor->setValue($object, $cloned->defaultValue, $cloned, $this->context);
if (true === $contextSpecificMetadata->hasDefault) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid it can has some side effects if $this->context->getPropertyNamingStrategy() is null as we are not going to clone at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah true. Should we clone always or leave this part code as it was before?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would left it as it used to be :)

/**
* @var string|null
*/
public $preContextSerializedName;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be not used anymore.

@scyzoryck
Copy link
Collaborator

Just in general I wonder about use case that it would solve - I do not know so many cases when it would require dynamic change during of the (de-)serialisation naming. On the other hand generating name of the function was one of the biggest performance updates when migration from 1.x to 2.x so using this feature might cause some performance issues. ;-)

@dgafka
Copy link
Contributor Author

dgafka commented Dec 29, 2023

Just in general I wonder about use case that it would solve - I do not know so many cases when it would require dynamic change during of the (de-)serialisation naming. On the other hand generating name of the function was one of the biggest performance updates when migration from 1.x to 2.x so using this feature might cause some performance issues. ;-)

The feature is opt-in, so should not affect current usage if I am not mistaken?

And the use case is to use same JMS instance for two different purposes, like serialization of API responses (camel cases needed) and to do Database Mapping (snake cases needed).

@scyzoryck
Copy link
Collaborator

Just in general I wonder about use case that it would solve - I do not know so many cases when it would require dynamic change during of the (de-)serialisation naming. On the other hand generating name of the function was one of the biggest performance updates when migration from 1.x to 2.x so using this feature might cause some performance issues. ;-)

The feature is opt-in, so should not affect current usage if I am not mistaken?

Yes it is optin - so only performance impact will be with custom naming strategy.

And the use case is to use same JMS instance for two different purposes, like serialization of API responses (camel cases needed) and to do Database Mapping (snake cases needed).
Ok, but IMO especially for those operations we should care about performance - so having 2 instances that are cached seems to be still better option for me - specially that they will be in a different application layers and can be configure independently :) For the cases that you mentioned you might also need more options soon - like different config for enums or datetime handlers.
We can also make some call if'd be helpful for you :D

When I was taking another look I spotted another potential issue - when passing it into context it overrides all names - also the name defined in attribute/annotation. This behaviour is different than the default one - so it can potential source of the issues for other users. :(

@dgafka
Copy link
Contributor Author

dgafka commented Jan 2, 2024

so having 2 instances that are cached seems to be still better option for me - specially that they will be in a different application layers and can be configure independently :) For the cases that you mentioned you might also need more options soon - like different config for enums or datetime handlers.

The configuration will stay the same, so that's fine. I've checked how much bootstrapping ($builder->build) takes and it around 5ms (with almost no config, like custom Handlers) for the simplest case and I think it may increase when there is more configuration involved.
Therefore having like three instances (identical property, camel case, underscores), seems like a bit of overkill, especially that only one of them will be used in most of the cases.

I may hack my way around, and try to bootstrap them conditionally depending on the usage. This is not ideal but at least there wouldn't be bootstraping penalty.
But do we know, how much using the solution from the PR would affect performance? As if the percentage is small, then I would still consider it preferable over multiple instances of JMS.

@scyzoryck
Copy link
Collaborator

With following bench added:

class JsonCamelCaseSerializationBench extends JsonSerializationBench
{
    protected function createContext(): SerializationContext
    {
        return parent::createContext()->setPropertyNamingStrategy(new CamelCaseNamingStrategy());
    }
}

Results on my local was:

\JMS\Serializer\Tests\Benchmark\Performance\JsonCamelCaseSerializationBench

    benchSerialization......................I2 - Mo973.740ms (±2.40%)

\JMS\Serializer\Tests\Benchmark\Performance\JsonSerializationBench

    benchSerialization......................I2 - Mo853.821ms (±2.72%)

So the difference seems to be around 15% ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants