-
-
Notifications
You must be signed in to change notification settings - Fork 587
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
Type mismatch should throw an exception instead of coercing when deserializing JSON #561
Comments
EDIT: This solution does not work. Move on to my next comment. I'd recommend checking that in the setter, which you can define via the (Just guessing, hope it works that way.) <?php
namespace JMS\Serializer\Tests\Serializer\yml;
use JMS\Serializer\Annotation\Accessor;
use JMS\Serializer\Annotation\Expose;
use JMS\Serializer\Annotation\Type;
class Something
{
/**
* @var int
*
* @Expose
* @Type("integer")
* @Accessor(getter="getId", setter="setId")
*/
private $id;
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param int $id
*/
public function setId($id)
{
// Do check here and maybe throw error
$this->id = (int) $id;
}
} |
You could also register a custom type & handler. (Also not tested, there may be typos etc.) Use it with <?php
namespace JMS\Serializer\Tests\Serializer\yml;
use JMS\Serializer\Context;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\JsonSerializationVisitor;
class StrictIntegerHandler implements SubscribingHandlerInterface
{
/**
* Return format:
*
* array(
* array(
* 'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
* 'format' => 'json',
* 'type' => 'DateTime',
* 'method' => 'serializeDateTimeToJson',
* ),
* )
*
* The direction and method keys can be omitted.
*
* @return array
*/
public static function getSubscribingMethods()
{
return [
[
'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
'format' => 'json',
'type' => 'strict_integer',
'method' => 'deserializeStrictIntegerFromJSON',
],
[
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => 'strict_integer',
'method' => 'serializeStrictIntegerToJSON',
],
];
}
/**
* @param JsonDeserializationVisitor $visitor
* @param mixed $data
* @param array $type
* @return int
*/
public function deserializeStrictIntegerFromJSON(JsonDeserializationVisitor $visitor, $data, array $type)
{
// Do checks on data
return (int) $data;
}
/**
* @param JsonSerializationVisitor $visitor
* @param mixed $data
* @param array $type
* @param Context $context
* @return int
*/
public function serializeStrictIntegerFromJSON(JsonSerializationVisitor $visitor, $data, array $type, Context $context)
{
return $visitor->visitInteger($data, $type, $context);
}
} |
Thank you, I will have a look into it! |
@maennchen I've just checked the first suggested solution. Unfortunately the value is already coerced into an integer in the setter. :( I have my field set up like this in YAML:
And the setter is written like this in the entity:
The dump shows
I will now try your second suggestion. |
Okay, @maennchen your second suggestion solves my problem. Using a custom deserialisation handler allows for pushing the data unchanged through and leave it to the validation to deal with wrong types. Thank you! @schmittjoh To be honest in case of JSON the way JMS serializer deals with types just feels wrong. JSON knows about (some) types and coercing them will always lead to problems. So there should be at least a simple option to turn on strict handling of types or turn off type coercion. |
Primitives such as int, float and string are decoded correctly via the native json_decode and so should not be coerced. I now have to write my own custom handlers for each of these types just to bypass the incorrect default behaviour. +1 @reieRMeister for bringing this up. +1 @maennchen for coming up with a solution |
I solved it by writing an own DeserializationVisitor which behaves correctly for my needs: use JMS\Serializer\Context;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\Exception\RuntimeException;
/**
* Class TypeSafeJsonDeserializationVisitor
*/
class TypeSafeJsonDeserializationVisitor extends JsonDeserializationVisitor
{
/**
* @param mixed $data
* @param array $type
* @param Context $context
* @return integer|mixed
* @throws RuntimeException
*/
public function visitInteger($data, array $type, Context $context)
{
$castedValue = parent::visitInteger($data, $type, $context);
if ((string) $castedValue !== (string) $data) {
return $data;
}
return $castedValue;
}
} Then I override the default JSON deserialization class in my parameters:
jms_serializer.json_deserialization_visitor.class: TypeSafeJsonDeserializationVisitor and then everything works as expected (at least for |
Hi,
when I try to deserialize the JSON string
into an entity where
id
is defined as aninteger
the original type (string
) gets juggled into aninteger
. The result isint(123)
. And there is no way for me to check if really aninteger
was handed over.And it gets worse. When I try to deserialize
it gets deserialized into
int(0)
which is totally wrong.The only correct way to submit an
integer
should beSetting up a Type validator does not work because it gets called after the whole type juggling.
Is there a way to prevent the type juggling or let JMS serializer throw an exception on type mismatch?
Greetings
The text was updated successfully, but these errors were encountered: