programing

잭슨:각 값에 대해 올바른 유형의 맵으로 역직렬화

bestprogram 2023. 4. 2. 12:01

잭슨:각 값에 대해 올바른 유형의 맵으로 역직렬화

나는 다음과 같은 수업을 듣는다.

public class MyClass {
   private String val1;
   private String val2;
   private Map<String,Object> context;
   // Appropriate accessors removed for brevity.
   ...
}

오브젝트에서 JSON까지 잭슨과 왕복할 수 있기를 기대하고 있습니다.위의 오브젝트를 시리얼화하여 다음 출력을 수신할 수 있습니다.

{
    "val1": "foo",
    "val2": "bar",
    "context": {
        "key1": "enumValue1",
        "key2": "stringValue1",
        "key3": 3.0
    }
}

여기서 문제가 발생하고 있는 것은 시리얼화된 맵의 값에 유형 정보가 없기 때문에 올바르게 역직렬화되지 않는다는 것입니다.예를 들어 위의 예에서는 enumValue1을 열거값으로 역직렬화해야 하지만 대신 문자열로 역직렬화해야 합니다.다양한 것에 근거한 타입의 예를 봐 왔지만, 제 시나리오에서는 타입을 알 수 없기 때문에(미리 알 수 없는 사용자 생성 오브젝트) 타입 정보를 키 값 쌍으로 시리얼화할 수 있어야 합니다.잭슨이랑 어떻게 해야 돼?

참고로 잭슨 버전 2.4.2를 사용하고 있습니다.왕복 테스트에 사용하는 코드는 다음과 같습니다.

@Test
@SuppressWarnings("unchecked")
public void testJsonSerialization() throws Exception {
    // Get test object to serialize
    T serializationValue = getSerializationValue();
    // Serialize test object
    String json = mapper.writeValueAsString(serializationValue);
    // Test that object was serialized as expected
    assertJson(json);
    // Deserialize to complete round trip
    T roundTrip = (T) mapper.readValue(json, serializationValue.getClass());
    // Validate that the deserialized object matches the original one
    assertObject(roundTrip);
}

이것은 스프링 기반 프로젝트이므로 다음과 같이 매퍼가 작성됩니다.

@Configuration
public static class SerializationConfiguration {

    @Bean
    public ObjectMapper mapper() {
        Map<Class<?>, Class<?>> mixins = new HashMap<Class<?>, Class<?>>();
        // Add unrelated MixIns
        .. 

        return new Jackson2ObjectMapperBuilder()
                .featuresToDisable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS)
                .dateFormat(new ISO8601DateFormatWithMilliSeconds())
                .mixIns(mixins)
                .build();
    }
}

원하는 것을 달성하는 가장 간단한 방법은 다음을 사용하는 것이라고 생각합니다.

ObjectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

그러면 직렬화된 json에 유형 정보가 추가됩니다.

다음은 봄에 적응해야 하는 실행 예시입니다.

public class Main {

    public enum MyEnum {
        enumValue1
    }

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        MyClass obj = new MyClass();
        obj.setContext(new HashMap<String, Object>());

        obj.setVal1("foo");
        obj.setVal2("var");
        obj.getContext().put("key1", "stringValue1");
        obj.getContext().put("key2", MyEnum.enumValue1);
        obj.getContext().put("key3", 3.0);

        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);

        System.out.println(json);

        MyClass readValue = mapper.readValue(json, MyClass.class);
        //Check the enum value was correctly deserialized
        Assert.assertEquals(readValue.getContext().get("key2"), MyEnum.enumValue1);
    }

}

오브젝트는 다음과 같은 것으로 시리얼화 됩니다.

[ "so_27871226.MyClass", {
  "val1" : "foo",
  "val2" : "var",
  "context" : [ "java.util.HashMap", {
    "key3" : 3.0,
    "key2" : [ "so_27871226.Main$MyEnum", "enumValue1" ],
    "key1" : "stringValue1"
  } ]
} ]

그리고 올바르게 역직렬화 될 것이고, 주장은 통과될 것이다.

덧붙여서, 자세한 것은, https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization 를 참조해 주세요.

도움이 되었으면 좋겠어요.

언급URL : https://stackoverflow.com/questions/27871226/jackson-deserialize-to-a-mapstring-object-with-correct-type-for-each-value