为了账号安全,请及时绑定邮箱和手机立即绑定

使用在类字段中指定的自定义反序列化器反序列化字符串

使用在类字段中指定的自定义反序列化器反序列化字符串

米琪卡哇伊 2021-09-29 17:39:14
我需要编写一个方法,它接受一些对象、fieldName给定对象的类中存在的一些字段名称和一些字段值value。该值是字段的 JSON 序列化形式。该方法应取值并相应地反序列化它,如下所示:static void setField(Object obj, String fieldName, String value) throws Exception {    Field field = obj.getClass().getDeclaredField(fieldName)    Object valObj = objectMapper.readValue(value, field.getType());    field.set(obj, valObj);}(我实际上只需要检索反序列化的值,而不是再次设置它,但这使它成为一个更好的例子。)只要 jackson 的默认反序列化就足够了。现在让我们假设我有一个带有自定义(反)序列化器的类:class SomeDTO {    String foo;    @JsonSerialize(using = CustomInstantSerializer.class)    @JsonDeserialize(using = CustomInstantDeserializer.class)    Instant bar;}一种可能的解决方案是手动检查JsonDeserialize注释。但是,我真的不想尝试复制 Jackson 在决定使用哪种序列化器时遵循的任何策略,因为这看起来很脆弱(例如全局注册的序列化器)。是否有使用 DTO 类中定义的字段反序列化配置反序列化值的好方法?也许在将字段的注释传递给 Jackson 的同时将值反序列化为字段的类型,以便他们得到尊重?我设法获得了一个AnnotatedMember实例,其中包含所有必需的信息(JSON 注释和反射字段或 setter/getter 访问),但无法弄清楚我将如何使用它来反序列化一个独立的值由于缺乏文件:final JavaType dtoType = objectMapper.getTypeFactory().constructType(SomeDTO.class);final BeanDescription description = objectMapper.getDeserializationConfig().introspect(dtoType);for (BeanPropertyDefinition propDef: beanDescription.findProperties()) {    final AnnotatedMember mutator = propertyDefinition.getNonConstructorMutator();    // now what? Also: How do I filter for the correct property?}
查看完整描述

2 回答

?
繁花如伊

TA贡献2012条经验 获得超12个赞

一种可能性是序列化对象,替换给定的字段,然后再次反序列化它。当序列化 from/toJsonNode而不是 JSON-String 时,这可以轻松完成,如下所示:


static Object setField(Object obj, String fieldName, String value) throws Exception {

    // note: produces a new object instead of modifying the existing one

    JsonNode node = objectMapper.valueToTree(obj);

    ((ObjectNode) node).put(fieldName, value);

    return objectMapper.readValue(node.traverse(), obj.getClass());

}

但是,仅仅为了反序列化单个字段而对整个对象进行序列化和反序列化似乎开销很大,并且可能很脆弱,因为 DTO 类的其他方面会影响单个字段的反序列化过程


查看完整回答
反对 回复 2021-09-29
?
拉风的咖菲猫

TA贡献1995条经验 获得超2个赞

import com.fasterxml.jackson.core.JsonGenerator;

import com.fasterxml.jackson.core.JsonParser;

import com.fasterxml.jackson.core.JsonProcessingException;

import com.fasterxml.jackson.databind.DeserializationContext;

import com.fasterxml.jackson.databind.DeserializationFeature;

import com.fasterxml.jackson.databind.JsonNode;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.fasterxml.jackson.databind.SerializerProvider;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

import com.fasterxml.jackson.databind.ser.std.StdSerializer;


import java.io.IOException;

import java.util.Map;


public final class Jackson {


  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()

      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);


  public static void main(String[] args) throws IOException {

    Dto source = makeDto("Master", 31337);

    Dto dst = makeDto("Slave", 0xDEADBEEF);


    //1. read value of field "fieldName" from json source

    //2. clones destination object, sets up field "fieldName" and returns it

    //3. in case of no field either on "src" or "dst" - throws an exception

    Object result = restoreValue(dst, "details", OBJECT_MAPPER.writeValueAsString(source));

    System.out.println(result);

  }


  private static Object restoreValue(Object targetObject, String fieldName, String sourceObjectAsJson) throws IOException {

    String targetObjectAsJson = OBJECT_MAPPER.writeValueAsString(targetObject);

    Map sourceAsMap = OBJECT_MAPPER.readValue(sourceObjectAsJson, Map.class);

    Map targetAsMap = OBJECT_MAPPER.readValue(targetObjectAsJson, Map.class);

    targetAsMap.put(fieldName, sourceAsMap.get(fieldName));

    String updatedTargetAsJson = OBJECT_MAPPER.writeValueAsString(targetAsMap);

    return OBJECT_MAPPER.readValue(updatedTargetAsJson, targetObject.getClass());

  }


  private static Dto makeDto(String name, int magic) {

    Dto dto = new Dto();

    dto.setName(name);

    CustomDetails details = new CustomDetails();

    details.setMagic(magic);

    dto.setDetails(details);

    return dto;

  }


  private static final class Dto {

    private String name;

    @JsonSerialize(using = CustomDetails.CustomDetailsSerializer.class)

    @JsonDeserialize(using = CustomDetails.CustomDetailsDeserializer.class)

    private CustomDetails details;


    public String getName() {

      return name;

    }


    public void setName(String name) {

      this.name = name;

    }


    public CustomDetails getDetails() {

      return details;

    }


    public void setDetails(CustomDetails details) {

      this.details = details;

    }


    @Override

    public String toString() {

      return "Dto{" +

          "name='" + name + '\'' +

          ", details=" + details +

          '}';

    }

  }



  private static final class CustomDetails {

    private int magic;


    public int getMagic() {

      return magic;

    }


    public void setMagic(int magic) {

      this.magic = magic;

    }


    @Override

    public String toString() {

      return "CustomDetails{" +

          "magic=" + magic +

          '}';

    }


    public static final class CustomDetailsSerializer extends StdSerializer<CustomDetails> {


      public CustomDetailsSerializer() {

        this(null);

      }



      public CustomDetailsSerializer(Class<CustomDetails> t) {

        super(t);

      }


      @Override

      public void serialize(CustomDetails details, JsonGenerator jg, SerializerProvider serializerProvider) throws IOException {

        jg.writeStartObject();

        jg.writeNumberField("_custom_property_magic", details.magic);

        jg.writeEndObject();

      }

    }



    private static final class CustomDetailsDeserializer extends StdDeserializer<CustomDetails> {


      public CustomDetailsDeserializer() {

        this(null);

      }



      public CustomDetailsDeserializer(Class<CustomDetails> t) {

        super(t);

      }


      @Override

      public CustomDetails deserialize(JsonParser jp, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {

        JsonNode node = jp.getCodec().readTree(jp);

        int magic = (Integer) node.get("_custom_property_magic").numberValue();

        CustomDetails

            customDetails = new CustomDetails();

        customDetails.setMagic(magic);

        return customDetails;

      }

    }

  }

}

所以输出是:


Dto{name='Slave', details=CustomDetails{magic=31337}}


查看完整回答
反对 回复 2021-09-29
  • 2 回答
  • 0 关注
  • 190 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信