20

I'm looking for a library function (ideally from a commonly used framework e.g. Spring, Guava, Apache Commons etc.) that will nicely print the values of any Java object.

This is a general question rather than a specific one. Have seen similar questions on StackOverflow for which a common answer is "implement your own toString() method on the class" but this option isn't always practical - am looking for a general way of doing this with any object I come across, which may originate from third party code. Another suggestion is to use RefectionToStringBuilder from Apache Commons, e.g:

new ReflectionToStringBuilder(complexObject, new RecursiveToStringStyle()).toString()

But this has limited use - e.g. when it comes across a collection it tends to output something like this:

java.util.ArrayList@fcc7ab1[size=1]

An actual use case example is to log an Iterable<PushResult> returned from JGit's pushCommand.call() method - if posting an answer please make sure it would work with this as well as any other complex object.

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • 3
    Probably not what you want but you could use a json library to serialise to json and pretty-print the json (or yaml or whatever format you like) – assylias Apr 12 '17 at 13:23
  • Thanks @assylias, this might be helpful. Could you maybe provide an example usage? – Steve Chambers Apr 12 '17 at 13:24
  • 1
    I've never worked with `ReflectionToStringBuilder` before, so I won't post this as an answer, but it looks like you might be able to do something like override the `getValue` method to return an array when a `Collection` is given as the field (or even just your own `String` version of that collection). – Zircon Apr 12 '17 at 13:40
  • Great question, SO's guidelines notwithstanding. – Arthur Jan 12 '23 at 16:43

5 Answers5

21

You could try and use Gson. it also serializes Arrays, Maps or whatever....

MyObject myObject = new MyObject();
Gson gson = new GsonBuilder().setPrettyPrinting().serializeNulls().create();
gson.toJson(myObject);

For deserialization use:

gson.fromJson(MyObject.class);

For typed maps see this answer: Gson: Is there an easier way to serialize a map

Community
  • 1
  • 1
Naxos84
  • 1,890
  • 1
  • 22
  • 34
4

You can use the Jackson ObjectMapper class is use to bind data with json. you can use it like below:

ObjectMapper mapper = new ObjectMapper();

you can save json into object like below

Object json = mapper.readValue(input,object.class);

you can write that in string variable

String prettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(json);

it should work fine.

Per Lundberg
  • 3,837
  • 1
  • 36
  • 46
Sagar Trivedi
  • 51
  • 1
  • 4
  • 1
    Please could you expand on the `mapper.readValue` call for the `Iterable` example - which overload is being used and what should be passed in? – Steve Chambers Apr 12 '17 at 14:50
3

You could use a JSON (or other format) mapper to pretty-print your object. It should handle most "standard" fields (primitives, strings, collections, maps, arrays etc.) and if it doesn't you can always add a custom serialiser.

For example, with Jackson, it could be as simple as this:

public static void main(String... args) throws Exception {
  ObjectMapper om = new ObjectMapper();
  om.enable(SerializationFeature.INDENT_OUTPUT); //pretty print
  String s = om.writeValueAsString(new Pojo());
  System.out.println(s);
}


static class Pojo {
  private int id = 1;
  private List<String> list = Arrays.asList("A", "B");
  //getters etc.
}

That code outputs:

{
  "id" : 1,
  "list" : [ "A", "B" ]
}
assylias
  • 321,522
  • 82
  • 660
  • 783
  • This looks promising but unfortunately for the example use case it gave the following error: `com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle (through reference chain: java.util.ArrayList[0]->org.eclipse.jgit.transport.PushResult["advertisedRefs"]->java.util.Collections$UnmodifiableCollection[0]->org.eclipse.jgit.lib.ObjectIdRef$PeeledNonTag["leaf"])` – Steve Chambers Apr 12 '17 at 15:26
  • 1
    @SteveChambers Cyclical references are when you have: `class A { private A parent; }` for example. Whichever solution you find, it is unlikely that it will cope with those situations without a bit of help. In Jackson you have the [JsonIdentityInfo annotation](http://stackoverflow.com/a/9673890/829571). – assylias Apr 12 '17 at 16:03
3

You can use GSON to convert your object to string. This will work for all the objects,

Gson gson = new Gson();
System.out.println(gson.toJson(objectYouWantToPrint).toString());
Max von Hippel
  • 2,856
  • 3
  • 29
  • 46
Vijayakumar
  • 303
  • 4
  • 10
2

One possible way to do this for any object without the use of an external library would be to use reflection of a generic type. In the following snippet, we simply access each field (including private fields) and print their name and value:

public static <T> String printObject(T t) {
    StringBuilder sb = new StringBuilder();

    for (Field field : t.getClass().getDeclaredFields()) {
        field.setAccessible(true);

        try {
            sb.append(field.getName()).append(": ").append(field.get(t)).append('\n');
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    return sb.toString();
}

This method could be placed in a utility class for easy access.

If any of the object's fields do not override Object#toString it will simply print the object's type and its hashCode.

Example:

public class Test {

    private int x = 5;

    private int y = 10;

    private List<List<Integer>> list = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));

}

>> printObject(new Test());
>>
>> x: 5
>> y: 10
>> list: [[1, 2, 3], [4, 5, 6]]
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • This currently won't recurse into collections or fields that are themselves objects. Ideally I'd prefer a library method as don't want the overhead of unit tests etc. and would also like to be able to use it in the Display window whenever necessary. – Steve Chambers Apr 12 '17 at 14:10
  • @SteveChambers I've tested it with nested `Collection`s and it works fine; I've altered the example to prove it as well! – Jacob G. Apr 12 '17 at 14:13
  • 1
    Have tested this here: http://rextester.com/GXUV44108 Looks like I stand corrected on the collections part (at least for lists) but unfortunately it doesn't recurse into objects (e.g. `test2: Rextester$Test2@6d06d69c`). – Steve Chambers Apr 12 '17 at 15:40
  • 1
    @SteveChambers Ah, I see what you mean regarding objects. I'll see if I can find a fix for that! – Jacob G. Apr 12 '17 at 15:41