Dart适配PocketBase的双向异构JsonConverter实现难题
解决PocketBase API序列化/反序列化的转换器兼容问题
针对你遇到的JsonConverter泛型约束限制,没法分别指定反序列化输入(Map)和序列化输出(String)的问题,这里有几种实用的解决方案:
方案1:自定义双向转换器+适配类
先绕开标准JsonConverter的单泛型限制,定义一个支持不同输入输出类型的转换器接口,再写适配类把它套成标准转换器可用的形式:
- 定义双向转换器接口
public interface TwoWayConverter<In, Out> { Out from(In input); In to(Out output); }
- 实现Relation专属的转换逻辑
public class RelationTwoWayConverter implements TwoWayConverter<Map<String, Object>, Relation> { @Override public Relation from(Map<String, Object> expandMap) { // 把expand返回的Map转成Relation实例 return new Relation( (String) expandMap.get("id"), (String) expandMap.get("name") // 其他字段按需映射 ); } @Override public Map<String, Object> to(Relation relation) { // 返回仅包含id的Map,适配后续序列化逻辑 Map<String, Object> result = new HashMap<>(); result.put("id", relation.getId()); return result; } }
- 写适配类对接标准
JsonConverter
public class RelationConverterAdapter implements JsonConverter<Relation> { private final TwoWayConverter<Map<String, Object>, Relation> converter; private final Gson gson = new Gson(); public RelationConverterAdapter(TwoWayConverter<Map<String, Object>, Relation> converter) { this.converter = converter; } @Override public Relation fromJson(JsonElement jsonElement) throws JsonParseException { Map<String, Object> expandMap = gson.fromJson(jsonElement, new TypeToken<Map<String, Object>>(){}.getType()); return converter.from(expandMap); } @Override public JsonElement toJson(Relation relation) throws JsonSerializationException { // 序列化时直接输出id字符串 return new JsonPrimitive(relation.getId()); } }
方案2:用TypeAdapter直接突破泛型限制(推荐)
如果用Gson这类序列化库,直接用TypeAdapter比JsonConverter灵活得多,它不需要强制输入输出类型统一:
public class RelationTypeAdapter extends TypeAdapter<Relation> { @Override public void write(JsonWriter out, Relation relation) throws IOException { // 写操作:直接输出Relation的id字符串 out.value(relation.getId()); } @Override public Relation read(JsonReader in) throws IOException { // 读操作:把expand返回的整个对象Map转成Relation实例 in.beginObject(); Map<String, Object> data = new HashMap<>(); while (in.hasNext()) { String key = in.nextName(); switch (key) { case "id": data.put(key, in.nextString()); break; case "name": data.put(key, in.nextString()); break; // 其他字段按需处理,不需要的直接跳过 default: in.skipValue(); break; } } in.endObject(); return new Relation((String) data.get("id"), (String) data.get("name")); } }
然后注册这个TypeAdapter到你的Gson实例里:
Gson gson = new GsonBuilder() .registerTypeAdapter(Relation.class, new RelationTypeAdapter()) .create();
这样反序列化时会自动把expand里的对象转成Relation实例,序列化时自动把Relation转成id字符串,完全替代预处理逻辑。
方案3:注解绑定序列化/反序列化器(Jackson适用)
如果用Jackson,可以直接给模型类的Relation字段加注解,绑定专属的序列化和反序列化器:
public class YourModel { // 其他字段 @JsonDeserialize(using = RelationDeserializer.class) @JsonSerialize(using = RelationSerializer.class) private Relation relation; // getter/setter } // 反序列化器:处理expand的Map转Relation public class RelationDeserializer extends JsonDeserializer<Relation> { @Override public Relation deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); return new Relation( node.get("id").asText(), node.get("name").asText() ); } } // 序列化器:处理Relation转id字符串 public class RelationSerializer extends JsonSerializer<Relation> { @Override public void serialize(Relation value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(value.getId()); } }
这种方式直接绑定到字段上,代码更集中,不需要额外的适配类。
内容的提问来源于stack exchange,提问作者TomTom101
相关产品推荐
相关产品推荐

