简体   繁体   English

使用 Jackson 反序列化 java.utils.logging.Level 类返回 null

[英]Deserialization of java.utils.logging.Level class with Jackson returns null

I am trying to deserialize a complex bean using jackson and Lombok builder.我正在尝试使用 jackson 和 Lombok builder 反序列化一个复杂的 bean。 I have solved already many errors related to serialization of other custom types but I am stuck with deserializing a Level object.我已经解决了许多与其他自定义类型的序列化相关的错误,但我仍然坚持反序列化Level对象。 The serialization works somehow but not the deserialization as shown below.序列化以某种方式起作用,但反序列化不起作用,如下所示。

Since the Level class is protected, I cannot for instance create an auxiliary variable to serialize the Level object attributes in a different way (eg an array of strings) and then call the constructor of Level after reading the serialized auxiliary variable like I did when deserializing a Pair type.因为 Level 类是受保护的,所以我不能例如创建一个辅助变量来以不同的方式序列化 Level 对象属性(例如字符串数组),然后在读取序列化的辅助变量后调用 Level 的构造函数,就像我在反序列化时所做的那样Pair类型。

The bean I am trying to deserialize is much more complex than the following, but I was able to reproduce the problem in a simpler more understandable case study.我试图反序列化的 bean 比下面的要复杂得多,但我能够在一个更简单、更易于理解的案例研究中重现这个问题。

TL;dr TL;博士

Deserialization of java.util.logging.Level with jackson is always null java.util.logging.Level 与 jackson 的反序列化始终为null

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;

import java.io.IOException;
import java.util.logging.Level;

public class ReproduceSerializationError {

public static void main(String[] args) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    MyObj obj1 = MyObj.builder()
                .level(Level.FINE)
                .var1(10.0)
                .build();
    System.out.println("initial object = " + obj1.toString());

    String serializedOj = serializeObj( obj1, objectMapper );
    System.out.println("serialized json = " + serializedOj.toString());

    MyObj deserialized = deserializeObj(serializedOj, objectMapper);
    System.out.println("deserialized object = " + deserialized.toString());
    System.out.println("logging level of deserialized object = " + deserialized.loggingLevel);
}

@ToString
@Getter
@JsonTypeInfo(use= JsonTypeInfo.Id.CLASS, property="class")
@JsonDeserialize(builder = MyObj.MyObjBuilder.class)
private static class MyObj{

    private final double var1;
    private Level level;

    @JsonPOJOBuilder(withPrefix = "")
    public static class MyObjBuilder {

    }

    @Builder
    public MyObj(Level level, double var1){
        this.level = level;
        this.var1 = var1;
    }
}

public static String serializeObj(MyObj obj1, ObjectMapper objectMapper) {
    try {
        return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj1);
    } catch(JsonProcessingException e) {
        throw new RuntimeException( e );
    }
}

public static MyObj deserializeObj(String jsonInFile, ObjectMapper objectMapper) throws IOException {
    return objectMapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).readValue( jsonInFile, MyObj.class);
    }
}

The code above prints the following:上面的代码打印以下内容:

initial object = ReproduceSerializationError.MyObj(var1=10.0, loggingLevel=FINE)
serialized json = {
  "class" : "org.targomo.gp2.util.ReproduceSerializationError$MyObj",
  "var1" : 10.0,
  "loggingLevel" : {
    "name" : "FINE",
    "resourceBundleName" : "sun.util.logging.resources.logging",
    "localizedName" : "FINE"
  }
}
deserialized object = ReproduceSerializationError.MyObj(var1=10.0, loggingLevel=null)
logging level of deserialized object = null

How can I correctly deserialize the loggingLevel attribute of MyObj ?我怎样才能正确地反序列化loggingLevel的属性MyObj

You need to implement custom serialiser and deserialiser for java.util.logging.Level class.您需要为java.util.logging.Level类实现自定义序列化器和反序列化器。 Since levels are predefined we can not create them, we should use already created and declared instances.由于级别是预定义的,我们无法创建它们,我们应该使用已经创建和声明的实例。 See below implementation:见下面的实现:

class LevelJsonSerializer extends JsonSerializer<Level> {

    @Override
    public void serialize(Level value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(value.getName());
    }
}

class LevelJsonDeserializer extends JsonDeserializer<Level> {

    @Override
    public Level deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String name = p.getText();

        return Level.parse(name);
    }
}

You can register above classes like below:您可以注册上述课程,如下所示:

SimpleModule levelModule = new SimpleModule("LevelModule");
levelModule.addSerializer(Level.class, new LevelJsonSerializer());
levelModule.addDeserializer(Level.class, new LevelJsonDeserializer());

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(levelModule);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM