[DEV] 기록

[SpringBoot] 디버깅 목적으로 자바 객체 출력하는 방법

꾸준함. 2021. 2. 21. 18:35

개요

Rest API를 통해 반환받은 Java Object를 로그로 찍어보는데 예상과 달리 "패키지명@난수"와 같은 형태로 출력되는 문제가 발생했습니다.

다행히도 stackoverflow에 이와 관련되어 잘 정리된 글이 있어 해당 내용을 정리해보고자 합니다.

 

배경지식

모든 Java 객체에는 객체를 출력할 때 호출되는 toString() 메서드가 있습니다.

System.out.println(myObject);  // myObject.toString()를 호출

이 메서드는 Object 클래스(모든 Java 객체의 슈퍼 클래스)에 정의되어 있습니다.

Object.toString() 메서드는 클래스 이름, @ 기호 및 16진수로 구성된 상당히 보기 흉한 문자열을 반환합니다.

 

이에 대한 코드는 아래와 같습니다.

// Object.toString()의 구현코드
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

따라서, 자바 객체를 출력했을 때 나오는 결과물 com.tistory.com.ExampleObject@2f92e0f4 는 아래와 같이 설명이 가능합니다.

  • com.tistory.jaimemin.ExampleObject - 클래스의 이름, 즉 com.tistory.jaimemin 패키지 내에 있는 ExampleObject 클래스입니다.
  • @ - 문자열을 함께 결합합니다.
  • 2f92e0f4 객체의 해시 코드입니다.

 

배열 클래스의 이름은 조금 다르게 생겼으며, JavaDocs 문서 내 Class.getName() 항목에서 잘 설명되어있습니다.

 

예를 들어 [Ljava.lang.String 이 출력되었다면,

  • [ - 일차원 배열 ([[는 이차원 배열, [[[는 삼차원 배열, 등등)
  • L - 배열에 클래스 또는 인터페이스가 포함되어 있다는 뜻
  • java.lang.String - 배열 타입 유형

 

출력 결과를 커스터마이징하기

System.out.println(myObject)을 호출할 때 출력 결과가 바뀌길 원한다면 toString() 메서드를 오버라이딩해야 합니다.아래는 간단한 예시입니다.

public class Person {

  private String name;
  
  // 생성자 및 다른 함수 중략
  
  @Override
  public String toString() {
    return name;
  }
}

이제 Person 객체를 출력하면 com.tistory.jaimemin.Person@12345678이 출력되는 대신 name 필드가 출력될 것입니다.

주의할 점: ToString() 메서드는 객체를 문자열로 변환하는 여러 가지 방법 중 한 가지 방법일 뿐입니다. 일반적으로 toString() 메서드는 객체를 명확하고 간결하게 설명하면서 완벽하게 설명해줘야 합니다.

따라서, 보다 나은 예제는 아래와 같습니다.

@Override
public String toString() {
  return getClass().getSimpleName() + "[name=" + name + "]";
}

위와 같은 예제를 적용하면 Person 객체를 출력했을 때 Person [name=jaimemin]과 같이 출력될 것이고 이는 디버깅/테스트에 정말 유용한 자료가 될 것입니다.

 

출력 자동생성

많은 IDE는 클래스의 필드를 기반으로  toString() 메서드를 자동 생성할 수 있도록 지원합니다. (보다 많은 내용은 Eclipse 혹은 Intellij 문서를 확인해주시기 바랍니다.)

 

몇몇 인기 있는 자바 라이브러리들도 이 기능을 제공하는데 아래에 몇 가지 예시를 들도록 하겠습니다.

  • Apache Commons Lang의 ToStringBuilder
  • Google Guava의 MoreObjects.ToStringHelper
  • Lombok의 @ToString

 

배열에 속해있는 자바 객체들을 출력하는 방법

객체 배열이 있는 경우 Arrays.toString()을 호출하여 배열 내용을 간단히 표시할 수 있습니다.

Person 타입 배열을 예시로 들자면 아래와 같습니다.

public class Person {

  private String name;
  
  // 생성자 및 다른 함수 중략
  
  @Override
  public String toString() {
    return name;
  }
}

Person[] people = { new Person("Fred"), new Person("Mike") };
System.out.println(Arrays.toString(people));

// 출력 결과: [Fred, Mike]

 

참고: 위 예시는 Arrays 클래스의 정적 메서드인 toString()을 호출한 예시입니다. 이 메서드는 앞서 설명한 toString 메서드와 다를 메서드입니다.
다차원 배열일 경우 Arrays.deepToString() 메서드를 통해 동일한 종류의 출력을 얻을 수 있습니다.

 

Collections

대부분의 컬렉션은 모든 객체에 대해 .toString() 호출을 기반으로 한 예쁜 출력을 지원합니다. (여기서 말하는 예쁜 출력은 com.tistory.com.ExampleObject@2f92e0f4 와 같이 못생긴 출력이 아니라는 뜻입니다.)

public class Person {

  private String name;
  
  // 생성자 및 다른 함수 중략
  
  @Override
  public String toString() {
    return name;
  }
}

List<Person> people = new ArrayList<>();
people.add(new Person("Alice"));
people.add(new Person("Bob"));    
System.out.println(people);

// 출력결과: [Alice, Bob]

따라서 위에서 설명한 대로 자바 객체에 toString() 메서드가 원하는 대로 출력하는지만 확인하면 됩니다.

 

[출처]stackoverflow.com/questions/29140402/how-do-i-print-my-java-object-without-getting-sometype2f92e0f4

 

How do I print my Java object without getting "SomeType@2f92e0f4"?

I have a class defined as follows: public class Person { private String name; // constructor and getter/setter omitted } I tried to print an instance of my class: System.out.println(myPerso...

stackoverflow.com

 

반응형