jackson-dataformats-binary icon indicating copy to clipboard operation
jackson-dataformats-binary copied to clipboard

[Ion] Incorrect IonValue deserialization for wrapper/value classes - IonStructs not handled correctly

Open mcliedtke opened this issue 6 years ago • 1 comments

Ran into a strange issue with deserializing wrapper/value classes when the content of the IonValue is suppose to be a struct. Some test cases are below. The issue is shown at the bottom of the test below: mapper.readValue("{ a: b }", TestValueType.class);. This gets read as an ion symbol 'b' instead of an ion struct { a: b } and I believe it's because of the code here that steps into the struct before yielding to the deserializer?

Not sure if this is the correct analysis or what the proper course of action should be if it is correct. Any ideas?

public static class TestValueType {
    
    private IonValue value;

    private TestValueType(IonValue value) {
        this.value = value;
    }
    
    @JsonCreator
    public static TestValueType of(IonValue value) {
        return new TestValueType(value);
    }
    
    @JsonValue
    public IonValue getValue() {
        return value;
    }
}


@Test
public void deserializeValueType() throws IOException {
    IonSystem ionSystem = IonSystemBuilder.standard().build();
    
    IonObjectMapper mapper = new IonObjectMapper();
    mapper.registerModule(new IonValueModule());
    TestValueType testType;
    
    testType = mapper.readValue("a_symbol", TestValueType.class);
    assertEquals(ionSystem.newSymbol("a_symbol"), testType.getValue());
    
    testType = mapper.readValue("\"a_string\"", TestValueType.class);
    assertEquals(ionSystem.newString("a_string"), testType.getValue());
    
    testType = mapper.readValue("1.0", TestValueType.class);
    assertEquals(ionSystem.newDecimal(1.0), testType.getValue());
    
    testType = mapper.readValue("1", TestValueType.class);
    assertEquals(ionSystem.newInt(1), testType.getValue());
    
    testType = mapper.readValue("1.0e0", TestValueType.class);
    assertEquals(ionSystem.newFloat(1.0), testType.getValue());
    
    testType = mapper.readValue("[1, 2]", TestValueType.class);
    IonList expectedList = (IonList) ionSystem.singleValue("[1, 2]");
    assertEquals(expectedList, testType.getValue());
    
    testType = mapper.readValue("(a b)", TestValueType.class);
    IonSexp expectedSexp = (IonSexp) ionSystem.singleValue("(a b)");
    assertEquals(expectedSexp, testType.getValue());
    
    testType = mapper.readValue("{ a: b }", TestValueType.class);
    
    //Should be this
    //IonStruct expectedStruct = (IonStruct) ionSystem.singleValue("{ a: b }");
    //assertEquals(expectedStruct, testType.getValue()); 
    
    //Unfortunately, it's this
    IonSymbol actualValue = (IonSymbol) ionSystem.singleValue("b");
    assertEquals(actualValue, testType.getValue());
}

mcliedtke avatar Oct 09 '17 14:10 mcliedtke

Unfortunately never looked into this. Assuming you think it is a valid issue (I am not familiar enough with Ion's type system unfortunately), would probably make sense to add test case in repo, at least (under failing so as not to break builds).

cowtowncoder avatar Jun 27 '20 22:06 cowtowncoder