Symfony Serializer反序列化含属性XML失败求助
问题排查与解决
为啥反序列化出来是空的?
核心问题出在注解路径错误和反序列化目标类型不匹配:
- 你给Issue实体的
#[SerializedName]加了issue/前缀,但实际反序列化时,Serializer已经聚焦到<issue>节点内部了,不需要再指定外层的issue路径。 - XML根节点是
<issues>,里面包着<issue>,直接反序列化为Issue::class,Serializer找不到对应的数据映射关系。
一步步解决
1. 修正Issue和Page的注解
把注解里的issue/前缀删掉,直接用节点内部的属性/节点名:
// Issue类 class Issue { #[ORM\Id] #[ORM\Column] #[SerializedName('@id')] // 对应<issue id="1">的id属性 private ?int $id = null; #[ORM\Column(length: 255, nullable: true)] #[SerializedName('@name')] // 对应<issue name="test">的name属性 private ?string $name = null; #[ORM\OneToMany(mappedBy: 'issue', targetEntity: Page::class)] #[SerializedName('page')] // 对应<issue>下的多个<page>节点 private Collection $pages; // 必须在构造函数初始化集合! public function __construct() { $this->pages = new ArrayCollection(); } // 省略getter/setter }
// Page类 class Page { #[ORM\Id] #[ORM\Column] #[SerializedName('@id')] private ?int $id = null; #[ORM\Column(length: 255, nullable: true)] #[SerializedName('@name')] private ?string $name = null; #[ORM\ManyToOne(inversedBy: 'pages')] private ?Issue $issue = null; // 省略getter/setter }
2. 调整反序列化逻辑
因为XML根是<issues>,里面是<issue>,直接反序列化为Issue::class会错位,推荐用包裹类来适配结构:
// 新建一个Issues包裹类 class Issues { #[SerializedName('issue')] private ?Issue $issue = null; // 生成getter/setter public function getIssue(): ?Issue { return $this->issue; } public function setIssue(?Issue $issue): self { $this->issue = $issue; return $this; } }
然后修改反序列化代码:
$issuesWrapper = $serializer->deserialize($xml, Issues::class, 'xml'); $issue = $issuesWrapper->getIssue();
如果不想新建包裹类,也可以先转成数组再提取:
// 先把XML转成数组 $arrayData = $serializer->deserialize($xml, 'array', 'xml'); // 取出<issue>节点的数据 $issueData = $arrayData['issue']; // 再把数组转成Issue对象 $issue = $serializer->deserialize(json_encode($issueData), Issue::class, 'json');
3. 检查Serializer配置
确保ObjectNormalizer支持集合和关联关系,调整配置:
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory); $normalizers = [ new ArrayDenormalizer(), new ObjectNormalizer( $classMetadataFactory, $metadataAwareNameConverter, null, new ReflectionExtractor(), null, null, ['enable_max_depth' => true] // 开启深度支持,处理关联集合 ) ]; $encoders = [new XmlEncoder()]; $serializer = new Serializer($normalizers, $encoders);
验证效果
做完上面的修改后,再反序列化就能正确拿到Issue的id、name,以及pages集合里的所有Page对象了。
内容的提问来源于stack exchange,提问作者23nr1
相关产品推荐
相关产品推荐

