当前位置: 首页 > 知识库问答 >
问题:

基于值反序列化到通用成员

乐城
2023-03-14

我有这样一个通用类:

public class Pojo<T> {
    
    @JsonProperty("value")
    public T[] values;
};

T可以包含StringLocalDateTimeintger。String和intger之间的区别似乎工作正常,很可能是因为这些类型在序列化的JSON文件中表示不同。然而,当我在JSON对象中有一个日期时间时(参见示例),它无论如何都会被解析为字符串。

value字段的实际使用类型是由输入决定的。虽然我在下面的最小示例中确实有这方面的知识,但这并不适用于我程序中该代码的所有使用。我只能依赖字段value的值模式。

public class Main {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

    String json = "{\"value\": \"2022-02-22T12:00:00\"}";
    Pojo<?> deserialized = mapper.readValue(json, Pojo.class);
    assert deserialized.value[0] instanceof LocalDateTime;
}

我还没有成功修补JsonTypeInfo。如果该字段的所有值都匹配模式yyyy-MM-dd'T'hh:MM:ss,是否有方法将该值字段解析为LocalDateTime对象的数组?

共有1个答案

轩辕经国
2023-03-14

这是你的问题——Pojo

ObjectMapper不知道要将T解析为什么类型。要告诉它类型,您需要使用带有TypeReference的readValue重载,或者使用带有JavaType的重载。我发现JavaType更容易阅读,下面是一个例子:

public class Test {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

        String json = "{\"value\": \"2022-02-22T12:00:00\"}";
        JavaType javaType = TypeFactory.defaultInstance().constructParametricType(Pojo.class, LocalDateTime.class);
        Pojo<LocalDateTime> deserialized = mapper.readValue(json, javaType);
        System.out.println(deserialized.values[0].toLocalDate());
        System.out.println(deserialized.values[0].toLocalTime());
    }
}

当构造参数JavaType时,第一个参数是类本身,接下来是具体的泛型类型。

编辑:考虑到新的信息,我能想到的最好的方法是自定义反序列化程序,它在运行时解析类型。比如:

public class UnknownTypeDeserializer<T> extends StdDeserializer<Pojo<T>> {

    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");

    public UnknownTypeDeserializer() {
        super((Class<?>) null);
    }

    @Override
    public Pojo<T> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JacksonException {
        JsonNode node = parser.getCodec().readTree(parser);
        String value = node.get("value").asText();
        Pojo<T> pojo = new Pojo<>();
        T[] arr;
        try {
            arr = (T[]) new LocalDateTime[]{LocalDateTime.parse(value, this.formatter)};
        } catch (Exception exc) {
            try {
                arr = (T[]) new Integer[]{Integer.parseInt(value)};
            } catch (NumberFormatException numberFormatException) {
                arr = (T[]) new String[]{value};
            }
        }
        pojo.values = arr;
        return pojo;
    }
}

这个想法是尝试解析到LocalDateTime,如果不可能,尝试解析到int,如果不可能,再次保留为String。这是非常丑陋的方法,但我只是想说明这个想法。与其捕捉异常,不如检查格式,例如使用正则表达式,并根据正则表达式匹配,解析以纠正类型。我用字符串和int测试了它,它实际上是有效的。

public class Test {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addDeserializer(Pojo.class, new UnknownTypeDeserializer<>());
        mapper.registerModule(simpleModule);

        String json1 = "{\"value\": \"2022-02-22T12:00:00\"}";
        Pojo<?> deserialized1 = mapper.readValue(json1, Pojo.class);
        System.out.println("is date - " + (deserialized1.values[0] instanceof LocalDateTime));

        String json2 = "{\"value\": \"bla bla bla\"}";
        Pojo<?> deserialized2 = mapper.readValue(json2, Pojo.class);
        System.out.println("is string - " + (deserialized2.values[0] instanceof String));

        String json3 = "{\"value\": 41}";
        Pojo<?> deserialized3 = mapper.readValue(json3, Pojo.class);
        System.out.println("is int - " + (deserialized3.values[0] instanceof Integer));
    }
}

 类似资料:
  • 问题内容: 我试图读取JSON文件并将其转换为数组,但是在读取JSON文件后从数组获取空值。我正在为我的班级使用默认构造函数。 JSON文件: 本类: 问题答案: 您的Gson映射与给定的JSON不匹配。默认情况下,Gson通过 确切 名称将JSON属性映射到目标映射中的相应字段。看一眼: 和 属性名称大小写和字段名称大小写不匹配。您需要的是正确映射JSON。要么: 或通过覆盖名称匹配(这更适合J

  • 问题内容: 我对WCF有点陌生,将尝试清楚地描述我要做什么。 我有一个使用JSON请求的WCF Web服务。我在大多数情况下都可以很好地发送/接收JSON。例如,以下代码可以正常运行,并且符合预期。 JSON已发送: WCF: 这将按预期返回带有“ Dave”的JSON对象。问题是我无法始终保证我收到的JSON与我的DataContract中的成员完全匹配。例如,JSON: 由于大小写不匹配,将无

  • 我正在努力实现的是: 我们有一个JSON对象流进来。 我想从JSON重建一个Java对象。 我想应用转换(如更改字符串的格式和拒绝一个对象,如果满足一些条件,如'isToBe消耗'==false和可能的平坦从嵌套到线性的继承) 我希望能够将JSON对象的值存储到数据库中。 当一种新类型的JSON对象流出现时,我可以为每种类型的流运行CREATE TABLE,但我不想做任何代码更改。 换句话说,我希

  • 我正在使用JacksonPolymorphicDeserialization,这是我的代码,它反序列化到基于“type”属性的适当类中: 它工作得很好,我的json根据“type”值变成了预期的类。 但是,我正在考虑将“type”属性从String移动到Enum,这是我的新代码,带有以下更改: 和枚举: 问题是,第二种方法不起作用。。。知道为什么吗???我可以在这里使用Enum吗??? 谢谢!

  • 我和杰克逊有一个问题,我认为这个问题应该很容易解决,但它正在折磨我。 假设我有一个java POJO类,看起来像这样(假设我有getter和setter): 我想反序列化看起来像这样的JSON到一个User对象: Jackson给了我一些问题,因为User不是JSON中的第一级对象。我显然可以创建一个UserWrapper类,它有一个用户对象,然后使用它反序列化,但我知道一定有一个更优雅的解决方案

  • 问题内容: 我正在使用大猩猩 websocket,并且正在计划使用json进行序列化/反序列化。 假设我有这样的结构来接收传入的消息: 和 大猩猩提供接收传入的消息。传入的消息可以是Foo或Bar,但是我不能使用和收听其他消息,这很混乱。我想要像javascript 这样的东西。如果接收到Foo,则如何处理传入消息,然后将其存储到结构中;如果接收到Bar,则将其存储到结构中? 我正在解决方案正在使