首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用JMS序列化程序序列化/反序列化继承类

使用JMS序列化程序序列化/反序列化继承类
EN

Stack Overflow用户
提问于 2014-06-30 21:27:18
回答 2查看 7.1K关注 0票数 1

为了简单起见,我有

代码语言:javascript
复制
/*
 * @JMS\Discriminator(field = "type", map = {
 *     "one": "...\ItemOne",
 *     "two": "...\ItemTwo"
 * })
 */
Abstract Class Item {}
.
.
.
class ItemOne extends Item {/* Contains multiple properties */}
class ItemTwo extends Item {/* Contains multiple properties */}

class Example
{
      /**
        * @var Item[] $items
        * 
        * @ORM\OneToMany(targetEntity="...\Items", mappedBy="holder",cascade={"persist", "remove"})
        */
      protected $items;
}

一旦我使用FOSRestBundle序列化了这个实体,一切看起来都很好,我得到了项的数组,每个元素都有一个鉴别器字段,但是在反序列化时,我得到了以下错误

代码语言:javascript
复制
"You must define a type for ...\Example::$items."

因此,为了解决这个问题,我添加了

代码语言:javascript
复制
/**
  * @ORM\...
  * @JMS\Type("ArrayCollection<...\Item>")
  */
protected $items;

这一次,序列化的$items似乎仅限于父类Item,所有对象都将丢失与子类ItemOneItemTwo相关的所有属性,并且将在没有任何鉴别器字段的情况下被序列化,因此反序列化将失败并显示错误

代码语言:javascript
复制
"The discriminator field name "type" for base-class "...\Item" was not found in input data."

我该如何解决这个问题?

编辑正如@erlangb建议的那样,这似乎是JMS Serializer https://github.com/schmittjoh/JMSSerializerBundle/issues/292中的常见问题

尽管我不能使用上面提到的变通方法让它工作

代码语言:javascript
复制
/**
 * @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');

仍然会得到

代码语言:javascript
复制
 The discriminator field name "type" for base-class "...\Test\Vehicle" was not found in input data. 

或者,如果我从Saloon->veichle中删除@JMS\Type,我会得到

代码语言:javascript
复制
The discriminator field name "type" of the base-class "...\Test\Vehicle" conflicts with a regular property of the sub-class "...\Test\Moped". 
EN

回答 2

Stack Overflow用户

发布于 2014-06-30 23:35:38

这是一个已知的问题。几年前我也遇到过同样的问题。我不知道他们是否解决了这个问题,但看看这里:https://github.com/schmittjoh/JMSSerializerBundle/issues/292

现在我发现在jms序列化程序中有这样的注解:

代码语言:javascript
复制
/**
* @Discriminator(field = "type", map = {"car": "Car", "moped": "Moped"})
*/
abstract class Vehicle { }
class Car extends Vehicle { }
class Moped extends Vehicle { }

您可以像这样设置虚拟属性:

代码语言:javascript
复制
class Car extends Vehicle {
    /**
     * @Serializer\VirtualProperty
     */
    public function getType()
    {
        return 'car';
    }
}

class Moped extends Vehicle {
    /**
     * @Serializer\VirtualProperty
     */
    public function getType()
    {
        return 'moped';
    }
}

试着这样做

票数 3
EN

Stack Overflow用户

发布于 2014-07-01 20:37:53

代码语言:javascript
复制
/**
 * @JMS\Discriminator(field = "type", map = {
 *    "user": "User",
 *    "mod": "Moderator"
 * })
 */
abstract class AbstractUser
{
    /**
     * @JMS\Type("integer")
     */
    public $id;

    /**
     * @JMS\Type("string")
     */
    public $name
}

class Moderator extends AbstractUser
{
    /**
     * @JMS\Type("string")
     */
    public $foo;
}

class User extends AbstractUser
{
    /**
     * @JMS\Type("string")
     */
    public $bar;
}

这是我的测试:

代码语言:javascript
复制
public function testSerializer()
{
    $data = new Moderator();
    $data->foo = 'foo';
    $data->name = 'daniele';
    $serializer = SerializerBuilder::create()->build();
    $jsonContent = $serializer->serialize($data, 'json');

    $obj = $serializer->deserialize($jsonContent, '..MyBundle\...\AbstractUser',     json');
    $this->assertTrue(get_class($obj), 'MyBundle....\Moderator');

}

我简化了名称空间,但它是有效的

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24491222

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档