fhiegel
fhiegel

Reputation: 741

Jackson deserialization/serialization does not sort properties

I'm using Jackson 2.8.9 in my application to generate some JSON. I have some unit tests in which I compare generated JSON with some files content.

When I compare my generated JSON with my file content, it does not match due to the properties order.

For the tests to be repeatable I need to have the properties sorted alphabetically. But with Jackson, it does not seems to work.

I wrote some tests for illustation. Only should_indent_properties pass.

public class FormatJsonWithJacksonTest {

private static final String INDENTED_UNSORTED = "{\r\n" + 
        "  \"firstChild\" : {\r\n" + 
        "    \"subChild\" : {\r\n" + 
        "      \"alphaItem\" : \"1234567891234567\",\r\n" + 
        "      \"otherProperty\" : \"2017-06-21\",\r\n" + 
        "      \"someOtherProperty\" : \"NONE\",\r\n" + 
        "      \"alphaType\" : \"KIND_OF_TYPE\"\r\n" + 
        "    }\r\n" + 
        "  }\r\n" + 
        "}";

private static final String INDENTED_SORTED = "{\r\n" + 
        "  \"firstChild\" : {\r\n" + 
        "    \"subChild\" : {\r\n" + 
        "      \"alphaItem\" : \"1234567891234567\",\r\n" + 
        "      \"alphaType\" : \"KIND_OF_TYPE\",\r\n" + 
        "      \"otherProperty\" : \"2017-06-21\",\r\n" + 
        "      \"someOtherProperty\" : \"NONE\"\r\n" + 
        "    }\r\n" + 
        "  }\r\n" + 
        "}";

private static final String UNINDENTED_UNSORTED = "{" + 
        "\"firstChild\":{" + 
        "\"subChild\":{" + 
        "\"alphaItem\":\"1234567891234567\"," + 
        "\"otherProperty\":\"2017-06-21\"," + 
        "\"someOtherProperty\":\"NONE\"," + 
        "\"alphaType\":\"KIND_OF_TYPE\"" + 
        "}" + 
        "}" + 
        "}";

private static final String UNINDENTED_SORTED = "{" + 
        "\"firstChild\":{" + 
        "\"subChild\":{" + 
        "\"alphaItem\":\"1234567891234567\"," + 
        "\"alphaType\":\"KIND_OF_TYPE\"," + 
        "\"otherProperty\":\"2017-06-21\"," + 
        "\"someOtherProperty\":\"NONE\"" + 
        "}" + 
        "}" + 
        "}";

@Test
public void should_sort_properties() throws Exception {
    // Given
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper = objectMapper
            .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);

    // When
    String formattedJson = tryingToFormatJson(objectMapper, INDENTED_UNSORTED);

    // Then
    assertEquals(UNINDENTED_SORTED, formattedJson);
}


@Test
public void should_indent_properties() throws Exception {
    // Given
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper = objectMapper.enable(SerializationFeature.INDENT_OUTPUT);

    // When
    String formattedJson = tryingToFormatJson(objectMapper, UNINDENTED_UNSORTED);

    // Then
    assertEquals(INDENTED_UNSORTED, formattedJson);
}

@Test
public void should_sort_and_indent_properties() throws Exception {
    // Given
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper = objectMapper
            .configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
            .enable(SerializationFeature.INDENT_OUTPUT);

    // When
    String formattedJson = tryingToFormatJson(objectMapper, INDENTED_UNSORTED);

    // Then
    assertEquals(INDENTED_SORTED, formattedJson);
}

//
// Utils
//

private String tryingToFormatJson(ObjectMapper objectMapper, String unformattedJson)
        throws IOException, JsonProcessingException {
    JsonNode unsortedTree = objectMapper.readTree(unformattedJson);
    Object treeToValue = objectMapper.treeToValue(unsortedTree, Object.class);
    return objectMapper.writeValueAsString(treeToValue);
}

}

Upvotes: 0

Views: 2433

Answers (1)

user7605325
user7605325

Reputation:

When you call objectMapper.treeToValue(unsortedTree, Object.class), the Object's type is a subclass of Map - just put a System.out.println(treeToValue.getClass()) to check.

And according to javadoc, SORT_PROPERTIES_ALPHABETICALLY doesn't sort map keys:

Feature that defines default property serialization order used for POJO fields (note: does not apply to Map serialization!)


If you want to sort the fields, you have to create a custom class for you structure, like this:

public class Tree {
    private Map<String, Child> firstChild;

    // getters and setters
}

public class Child {
    private String alphaItem;

    private String otherProperty;

    private String someOtherProperty;

    private String alphaType;

    // getters and setters
}

And change the treeToValue call to:

Tree treeToValue = objectMapper.treeToValue(unsortedTree, Tree.class);

With this, the fields will be sorted and the test will work.

Upvotes: 1

Related Questions