Search code examples
javajacksonequalstostringstringify

Is Java jackson ObjectWriter.ObjectWriter.writeValueAsString(obj); stable?


I am currently writing test cases using TestNg. I populate objects using PodamFactory. I have following test case structure.

@Test
public void testIt(){ 
ARespObject resp = PodamFactory.manufacturePojo(ARespObject.class);
String responseXml = new JaxbStringTransformer().transform(resp);

// a new object with all the same data
ARespObject respActual = responder.getObj(responseXml);

Assert.assertTrue(TestUtils.areEqual(respActual , resp));
}

public static <T extends Object> boolean areEqual(T sourceObj, T target) {
    if (sourceObj == null && target == null) {
        return true;
    }
    if (sourceObj == target) {
        return true;
    }
    if (sourceObj.getClass() != target.getClass()) {
        return false;
    }
    if (sourceObj != null && target != null) {
        return stringifyObject(sourceObj).equals(stringifyObject(target));
    }

    return false;
}

public static String stringifyObject(Object obj) {
    String result = "";
    ObjectWriter ow = new JaxbJacksonObjectMapper().writer().withDefaultPrettyPrinter();
    try {
        result = ow.writeValueAsString(obj);
    } catch (JsonGenerationException e1) {
        LOG.error(e1);
    } catch (JsonMappingException e1) {
        LOG.error("JsonMappingException: " + e1);
    } catch (IOException e1) {
        LOG.error("IOException: " + e1);
    }
    return result;
}

I need to know if writeValueAsString(obj) will always provide same structure for both objects(i.e. its output will be stable) and following

stringifyObject(sourceObj).equals(stringifyObject(target));

is a valid check. I am concerned about whether it will ever give me different ordering of variables inside the ARespObject.


Solution

  • Rather than formatting the objects to strings for comparison, convert them to "tree model" (JsonNode implementations). ObjectNode implements equals/hashCode/toString etc to reasonably imitate JSON equivalence, so it will disregard the order of properties for example.

    ObjectMapper mapper = new ObjectMapper();
    JsonNode treeNode = mapper.convertValue(obj, JsonNode.class);
    

    (typically you will actually get an ObjectNode back, but you can just probably just use the JsonNode interface)

    The tree model classes will also perform a simple JSON formatting for toString() output, so "expected" and "actual" printouts should be readable (although not as pretty as with the pretty printer)