0

Given the following SampleTestClass where I try to parse JSON to Java:

class EmptyListDeserializerTest {

final ObjectMapper objectMapper = new ObjectMapper();

{
    objectMapper.configOverride(List.class)
            .setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY, Nulls.AS_EMPTY));
}

@Test
void test2() throws JsonProcessingException {
    final var result = objectMapper.readValue("null", new TypeReference<List<MyClass>>() {});

    assertThat(result).isEmpty();
}

@Test
void test3() throws JsonProcessingException {
    final var json = """
            [{
               "name": "John Doe",
               "address": null
             }]
            """;
    final var result = objectMapper.readValue(json, new TypeReference<List<MyComplexClass>>() {});

    assertThat(result.get(0).address).isEmpty();
}

@Test
void test4() throws JsonProcessingException {
    final var json = """
            [{
               "name": "John Doe"
             }]
            """;
    final var result = objectMapper.readValue(json, new TypeReference<List<MyComplexClass>>() {});

    assertThat(result.get(0).address).isEmpty();
}

public static class MyClass {

    public MyClass() {
    }

    private String name;

    public MyClass(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }
}

public static class MyComplexClass {

    public MyComplexClass() {
    }

    private String name;
    private List<String> address;

    public MyComplexClass(final String name, final List<String> address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public List<String> getAddress() {
        return address;
    }

    public void setAddress(final List<String> address) {
        this.address = address;
    }
}

}

I want to achieve to map all kind of non-existing lists to empty lists.

Adapting the entities itself is not a solution. Only the ObjectMapper is adaptable.

I tried all kind of potential solutions , but only managed to get test3 to pass, all others fail.

I also tried a CustomerDeserializer, but it was never called, even though registered:

public List<?> deserialize(JsonParser p, DeserializationContext ctxt)

So, what am I missing?

--- EDIT ---

Using this config instead:

    {
    objectMapper.configOverride(List.class)
            .setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY, Nulls.AS_EMPTY));
    SimpleModule module = new SimpleModule();
    module.addDeserializer(List.class, new EmptyListDeserializer());
    this.objectMapper.registerModule(module);
    }

and modifying the test2 slightly (adding escaped double-quotes):

@Test
void test2() throws JsonProcessingException {
    final var result = objectMapper.readValue("\"null\"", new TypeReference<List<MyClass>>() {});

    assertThat(result).isEmpty();
}

the test2 passes, but then test3 fails.

The CustomDeserializer looks like this:

public class EmptyListDeserializer extends JsonDeserializer<List<?>> {

@Override
public List<?> deserialize(JsonParser p, DeserializationContext ctxt)
        throws IOException, JsonProcessingException {
    // Check for null or 'null' string value
    if (p.getCurrentToken() == JsonToken.VALUE_NULL
            || p.getCurrentToken().isScalarValue()
            || (p.getCurrentToken() == JsonToken.VALUE_STRING && "null".equals(p.getText()))) {
        return Collections.emptyList();
    }
    // Otherwise, proceed with default deserialization
    return p.readValueAs(List.class);
}
0

1 Answer 1

-1

There is no solution for test4. Jackson iterate trough json properties and never touch properties not mentioned in json.

I see two option here:

  1. Add custom instantiator and fill lists with defaults.
  2. Post process deserealized object and replace nulls with empty list.

test2 also won't work. Just check result and replace null with required value.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.