2017-04-12 97 views
3

我正在尋找一個庫函數(理想情況下,從一個常用的框架,例如Spring,Guava,Apache Commons等)這將很好地打印任何Java對象的值。如何漂亮地打印複雜的Java對象(例如,具有對象集合的字段)?

這是一個普遍的問題,而不是一個特定的問題。在StackOverflow上看到類似的問題,其中一個常見的答案是「在類上實現你自己的toString()方法」,但這個選項並不總是實用的 - 我正在尋找一種通用的方式來處理我遇到的任何對象,這可能源於來自第三方代碼。另一項建議是使用RefectionToStringBuilder從Apache的百科全書,e.g:

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

但這限制了使用 - 例如當它遇到一個集合它往往輸出是這樣的:

[email protected][size=1] 

的實際使用情況實例是記錄一個Iterable<PushResult>從JGit的pushCommand.call()方法返回 - 如果張貼的答案,請確保將這項工作作爲以及任何其他複雜的對象。

+3

可能不是你想要什麼,但你可以使用JSON庫序列化到JSON和漂亮打印的JSON(或YAML或任何格式你喜歡) – assylias

+0

感謝@assylias,這可能有幫助。你能否提供一個示例用法? –

+1

我以前從來沒有用過'ReflectionToStringBuilder',所以我不會將它作爲答案發布,但它看起來像你可以做一些事情,比如重寫'getValue'方法來返回一個數組,當'Collection'作爲字段給出(或者甚至只是你自己的那個集合的String類型)。 – Zircon

回答

0

您可以使用JSON(或其他格式)映射器來漂亮地打印對象。它應該處理大多數「標準」字段(原語,字符串,集合,地圖,數組等),如果不是,您可以隨時添加自定義序列化程序。

例如,對於傑克遜,也可能是這樣簡單:

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. 
} 

該代碼輸出:

{ 
    "id" : 1, 
    "list" : [ "A", "B" ] 
} 
+0

這看起來很有前途,但不幸的是,對於示例用例,它給出了以下錯誤:'com.fasterxml.jackson.databind.JsonMappingException:導致循環的直接自引用(通過引用鏈:java.util.ArrayList [0] - > org.eclipse.jgit.lib.ObjectIdRef $ PeeledNonTag [「leaf」])' –

+0

@SteveChambers Cyclical引用是當你有:class A {private一個父類; ''例如。無論您找到哪種解決方案,都無法在沒有幫助的情況下應對這些情況。在傑克遜你有[JsonIdentityInfo註釋](http://stackoverflow.com/a/9673890/829571)。 – assylias

1

你可以嘗試使用GSON。它也序列化數組,映射或任何....

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

反序列化使用:

gson.fromJson(MyObject.class); 

對於類型映射看到這樣的回答:Gson: Is there an easier way to serialize a map

0

您可以使用GSON你的對象轉換串起來。這將爲所有對象的工作,

Gson gson = new Gson(); 
System.out.println(gson.toJson(objectYouWantToPrint).toString()); 
+0

糟糕!感謝您的更正。 @JacobG。 – Vijayakumar

0

您可以使用ObjectMapper類是利用與JSON數據綁定。你可以用它象下面這樣:

ObjectMapper mapper = new ObjectMapper(); 

可以節省JSON對象變成像下面

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

你可以寫在字符串變量

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

它應該工作的罰款。

+0

請您可以擴展''Iterable '示例的mapper.readValue'調用 - 正在使用哪個重載以及應該傳入哪些內容? –

0

對於任何對象而不使用外部庫的情況下執行此操作的一種可能方法是使用泛型類型的反射。在下面的片段中,我們簡單地訪問各領域(包括私人領域)和打印他們的名字和值:

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(); 
} 

這種方法可以被放置在便於訪問的工具類。

如果任何對象的字段沒有覆蓋Object#toString它只會打印對象的類型及其hashCode。

例子:

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]] 
+0

這目前不會遞歸到本身是對象的集合或字段中。理想情況下,我更喜歡庫方法,因爲不希望單元測試等開銷,並且還希望能夠在必要時在「顯示」窗口中使用它。 –

+0

@SteveChambers我用嵌套'集合'測試了它,它工作正常;我已經改變了這個例子來證明它! –

+0

已經在這裏測試過了:http://rextester.com/GXUV44108看起來像我在收集部分糾正(至少對於列表),但不幸的是它不遞歸到對象(例如'test2:Rextester $ Test2 @ 6d06d69c' )。 –