如何用JMS Serializer处理混合类型score字段的反序列化?
解决JMS Serializer中score字段混合类型的反序列化问题
针对你遇到的score字段类型不固定(整数/布尔值),需要将true转为100、false转为0同时保留原始整数的需求,这里有两种实用的解决方案:
方法一:使用@PostLoad回调处理(快速实现)
这种方式最简单,在实体类中添加一个反序列化完成后的回调方法,直接修正score字段的值:
use JMS\Serializer\Annotation as Serializer; class Lorem { /** * @Serializer\Type("string") * @Serializer\SerializedName("label") * @var string */ private $label; /** * 这里不指定严格类型,让JMS自动推断原始类型 * @Serializer\SerializedName("score") * @var int */ private $score; // 常规getter/setter方法... /** * @Serializer\PostLoad */ public function postLoad(): void { // 区分布尔值和整数,按需求转换 if (is_bool($this->score)) { $this->score = $this->score ? 100 : 0; } // 确保最终值为整数类型 $this->score = (int)$this->score; } }
原理:@PostLoad注解会在JMS完成反序列化后触发这个方法,我们在这里检查score的原始类型,将布尔值转换为目标整数,同时保留原始整数的数值。注意不要给score字段加@Type("int"),否则JMS会提前把布尔值转成1/0,导致无法区分原始类型。
方法二:自定义类型处理器(全局复用)
如果你需要在多个实体中复用这个转换逻辑,可以自定义一个类型处理器,实现JMS的HandlerInterface:
1. 创建自定义处理器类
use JMS\Serializer\Context; use JMS\Serializer\GraphNavigatorInterface; use JMS\Serializer\Handler\HandlerInterface; use JMS\Serializer\VisitorInterface; class ScoreTypeHandler implements HandlerInterface { // 序列化逻辑(如果需要反向转换可以在这里实现) public function serialize(VisitorInterface $visitor, $data, array $type, Context $context) { return $data; } // 反序列化核心逻辑 public function deserialize(VisitorInterface $visitor, $data, array $type, Context $context) { if (is_bool($data)) { return $data ? 100 : 0; } return (int)$data; } // 注册处理器的订阅规则 public static function getSubscribingMethods() { return [ [ 'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION, 'format' => 'json', 'type' => 'custom_score', 'method' => 'deserialize', ], [ 'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION, 'format' => 'json', 'type' => 'custom_score', 'method' => 'serialize', ], ]; } }
2. 注册处理器到JMS Serializer
以Symfony项目为例,在config/packages/jms_serializer.yaml中添加配置:
jms_serializer: handlers: - App\Serializer\Handler\ScoreTypeHandler
3. 在实体中使用自定义类型
class Lorem { /** * @Serializer\Type("string") * @Serializer\SerializedName("label") * @var string */ private $label; /** * 使用我们自定义的类型 * @Serializer\Type("custom_score") * @Serializer\SerializedName("score") * @var int */ private $score; // getter/setter方法... }
这种方式更适合需要在多个实体或场景中复用转换逻辑的场景,扩展性更强。
内容的提问来源于stack exchange,提问作者HanXHX
相关产品推荐
相关产品推荐

