JMSSerializerBundle
JMSSerializerBundle copied to clipboard
@Discriminator Error: The error is: The discriminator field name "type" for base-class "MyBundle\Entity\MyClass" was not found in input data
Hi, i have a problem with @discriminator for abstract class. For example, this structure of classes don't work correctly when I try to serialize and deserialize the objects.
class Saloon
{
/**
*@Type("integer")
*/
public $id;
/**
* @Type("MyME\HelloBundle\Controller\Vehicle")
*/
public $veichle;
}
/**
* @Discriminator(field = "type", map = {"car": "MyME\HelloBundle\Controller\Car", * "moped":"MyME\HelloBundle\Controller\Moped"})
*/
abstract class Vehicle {
public $id;
}
class Car extends Vehicle {
/**
*@Type("integer")
*/
public $id;
/**
*@Type("string")
*/
public $car_at;
}
class Moped extends Vehicle {
/**
*@Type("integer")
*/
public $id;
/**
*@Type("string")
*/
public $moped_at;
}
example usage:
$car = new Car();
$car->id = 1;
$car->car_at = "car";
$car2 = new Moped();
$car2->id = 2;
$car2->moped_at = "moped";
$saloon = new Saloon();
$sal0on->veichle = $car2;
$serializer = SerializerBuilder::create()->build();
$jsonveic = $serializer->serialize($saloon,'json');
$saloon_des = $serializer->deserialize($jsonveic,'MyME\HelloBundle\Controller\Saloon','json');
The error is: The discriminator field name "type" for base-class "MyME\HelloBundle\Controller\Vehicle" was not found in input data
Hi.
I have the same issue. Is it not possible to have the discriminator field automatically created when serializing?
Moreover, it seems like when I serialize, the fields from the extending classes are not exposed.
The problem is the abstract class. If you try to serialize only Car or Moped class the discriminator field is written in the serialized object. I remember that I tried to use "PreSerialize" and "PostSerialize" mehtod to avoid this problem, but I didn't remember the solution :S
Thanks for your answer.
I doesn't work. I have the following (simplified) classes.
class ExerciseModelResource
{
/**
* @Type("string")
*/
private $title;
/**
* @Type("CommonModel")
*/
private $content;
}
/**
* Abstract class for the exercise models.
*
* @Discriminator(field = "exercise_model_type", map = {
* "group-items": "GroupItems,
* "multiple-choice": "MultipleChoice"
* })
*/
abstract class CommonModel
{
/**
* @Type("string")
*/
protected $wording;
}
class GroupItems extends CommonModel
{
/**
* @Type("string")
*/
private $displayGroupNames;
}
class MultipleChoice extends CommonModel
{
/**
* @Type("array")
*/
private $questionBlocks = array();
}
When I serialize an ExerciseModelResource, I want the discriminator field to be written in the serialized object. I cannot put a more specific classe in @Type on $comment because it is not always the same when I serialize.
And in addition, I tried to replace this Type by MultipleChoice, just to see, be it added no field.
How can I do?
EDIT : I had a problem with the serializer I was using. Now, I get the field when I serialize if I specify no type (no abstract class). But as I want to use this class to serialize AND deserialize, I need one thing: how can I ignore an annotation (@Type) when I serialize and take it in account when I deserialize?
:+1: This issue has been a problem in my project as well
Look at the @Serializer\VirtualProperty Annotation. Worked for me.
class Car extends Vehicle {
/**
* @Serializer\VirtualProperty
*/
public function getType()
{
return 'car';
}
}
class Moped extends Vehicle {
/**
* @Serializer\VirtualProperty
*/
public function getType()
{
return 'moped';
}
}
What about the deserialize method? It works in the serialization as well, but what's happen when you try to deserialize it? The virtual property is not a discrimination field to mapping a "json" or a string representation in the right class! I think. Sorry I'm curios :D
My problem was that my discriminator property (discr) was not included during serialization but was required for the deserialization process. I didn't know how to get the Serializer to include it. What I achieved by adding this virtual property was to get the serializer to include it into the serialized format, thus deserialization worked fine after that.
I tried the mentioned work-around but couldn't get this to work
/**
* @JMS\Discriminator(field = "type", map = {"car": "...\Test\Car", "moped":"...\Test\Moped"})
*/
abstract class Vehicle {
public $id;
}
class Car extends Vehicle {
/**
*@JMS\Type("integer")
*/
public $id;
/**
*@JMS\Type("string")
*/
public $car_at;
/**
* @JMS\VirtualProperty
*/
public function getType()
{
return 'car';
}
}
class Moped extends Vehicle {
/**
*@JMS\Type("integer")
*/
public $id;
/**
*@JMS\Type("string")
*/
public $moped_at;
/**
* @JMS\VirtualProperty
*/
public function getType()
{
return 'moped';
}
}
class Saloon
{
/**
*@JMS\Type("integer")
*/
public $id;
/**
* @JMS\Type("...\Test\Vehicle")
*/
public $veichle;
}
//In controller
$car = new Car();
$car->id = 1;
$car->car_at = "car";
$car2 = new Moped();
$car2->id = 2;
$car2->moped_at = "moped";
$saloon = new Saloon();
$saloon->veichle = $car2;
$json = $this->get('jms_serializer')->serialize($saloon,'json');
$saloon_des = $this->get('jms_serializer')->deserialize($json,'...\Saloon','json');
//Error: The discriminator field name "type" for base-class "...\Test\Vehicle" was not found in input data.
Any suggestion?
The discriminator field will be correctly serialized if class is root class. If the class is a property of another class, discriminator field is not serialized. Any suggestion?
+1
I have to ask this question, too: any progress on this issue? We recently ran into the same issue, that our discriminated fields are properly deserialized but are missing upon serialization (serialization to JSON results in an empty object of that property).
After some investigation, it seems the serialization process does not recognize the discrimination properly.
When serializing the concrete class, the visitor visits the concrete class configuration. But when serializing the class which embeds the discriminated object, only the visitor for the abstract class is triggered.
I think this is a bug, because when deserializing it is working as intended. I just don't know if that's "another" bug which has not much to do with the one described in the ticket ;)
found out that serialization of discriminator field stops, when abstract base class is extended from a higher class itself
class base {}
abstract class user extends base {}
class admin extends user {}
class worker extends user {}
when serializing worker or admin there is no serialization of discriminator field. if class user is not extended from base, then the discriminator field will be serialized.
i made a patch: https://github.com/scasei/serializer/commit/bd09a4d41a24b312a49e75d8e302dcce06df90c5
and a pull request: https://github.com/schmittjoh/serializer/pull/309
You can, In fact get the discriminator value while serializing your objects using a virtual property but the getter should be named differently, here is an example:
use JMS\Serializer\Annotation as JMS;
/**
* @JMS\Discriminator(field = "objectType", map = {
* "file": "File"
* })
*/
abstract class ObjectAbstract {
/**
* @JMS\Type("integer")
*/
public $id;
/**
* @JMS\VirtualProperty
* @JMS\SerializedName("objectType")
*/
abstract public function getType();
}
class File extends ObjectAbstract {
/**
* @JMS\Type("string")
*/
public $fileUrl;
/**
* @JMS\Type("string")
*/
public $mimeType;
public function getType() {
return 'file';
}
}
It's a workaround, but hey! It work ;)
+1 same problem for me when i serialize an entity who include a property of type AbstractDiscriminatorEntity
@guillemcanal can you please try your solution in a parent concret class who take a class ObjectAbstract property, doesn't work for me (us)
Any solution ? maybe event pre/post serialize can do the job?
Any news on this issue?.
A precision, when i remove the type property in my yml config serializer, the serialize method work fine, unserialize does not.
If i use type in yml config, unserialize work, nut serialize fail.
Any help would be welcome.
I've been busy the last couple weeks, I'll do a Gist to demonstrate the workaround. I'm actually using discriminator to produce a json activitystream.
Hi I also faced with this issue. As a workaround i use such a listener
namespace Acme\Bundle\DemoBundle\EventListener;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\Events;
use JMS\Serializer\EventDispatcher\PreSerializeEvent;
class JMSSerializerListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
['event' => Events::PRE_SERIALIZE, 'method' => 'onPreSerialize']
];
}
/**
* @param PreSerializeEvent $event
*/
public function onPreSerialize(PreSerializeEvent $event)
{
$object = $event->getObject();
if (is_object($object) &&
is_subclass_of($object, 'Acme\Bundle\DemoBundle\Entity\ParentEntity') &&
get_class($object) !== $event->getType()['name']
) {
$event->setType(get_class($event->getObject()));
}
}
}
With this listener it works fine.
i've the same issue.
@molchanoviv's solution works well for me
yap that works, i even improved it with a tagging interface, so i only have to listen for an interface
Hi i have the same problem the discr property is not in the serialized XML ... can someone tell me how i have to format the virtual property so it gets loaded. If i only write virtual property with the name "discr" with a value the deserializer didnt get it... i have tried each "solution" i found here ... pls help /**
-
@Discriminator(field = "type", map = {"car": "MyME\HelloBundle\Controller\Car", * "moped":"MyME\HelloBundle\Controller\Moped"}) */ abstract class Vehicle {
public $id;
} class Car extends Vehicle {
/**
*@Type("integer")
*/
public $id;
/**
*@Type("string")
*/
public $car_at;
} class Moped extends Vehicle {
/**
*@Type("integer")
*/
public $id;
/**
*@Type("string")
*/
public $moped_at;
}
The discriminator field name "discr" for base-class "\Entity\Content\Content" was not found in input data.
class DiscriminatorSerializerListener implements EventSubscriberInterface
{
/**
* @inheritdoc
*/
public static function getSubscribedEvents()
{
return [
['event' => Events::PRE_SERIALIZE, 'method' => 'onPreSerialize'],
];
}
/**
* @param PreSerializeEvent $event
*/
public function onPreSerialize(PreSerializeEvent $event)
{
$object = $event->getObject();
if (is_object($object) && ($object instanceof Discriminatorable) && get_class($object) !== $event->getType()['name']) {
$event->setType(get_class($event->getObject()));
}
}
}
only give your parent class the Discriminatorable
interface
the serialization works fine but the deserialization stillt does not work -.- The discriminator field name "discr" for base-class "\Entity\Content\Content" was not found in input data.
yeah the discrimnator field must be serialized into the data...thats the listener for...then the deserialization works fine
As i debug the serialization, it never gets to the point $event->setType(get_class($event->getObject())); are there any other solutions ?
what ist the type you want to serialize?
vdzpeter [email protected] schrieb am Mi., 24. Juni 2015 12:44:
As i debug the serialization, it never gets to the point $event->setType(get_class($event->getObject())); are there any other solutions ?
— Reply to this email directly or view it on GitHub https://github.com/schmittjoh/JMSSerializerBundle/issues/292#issuecomment-114820331 .
i want to serialize a page class. The content of this class is linked with the class content which is a abstract class for multiple modules. if i exclude the content everything works fine. if i serialize one page with content@MaxDepth(1) i get:
The discriminator field name "discr" for base-class "Basecom\Bundle\AppFrameworkBundle\Entity\Content\Content" was not found in input data.
while deserializing.
if im going to set the MaxDepth to 3 i cant even serialize it with the error : Catchable Fatal Error: Argument 2 passed to JMS\Serializer\Handler\ArrayCollectionHandler::serializeCollection() must implement interface Doctrine\Common\Collections\Collection, instance of Proxies__CG__\Entity\Page given
Any solution ?