SHARE
Facebook X Pinterest WhatsApp

Implement a Dynamic toString() using JavaBeans Introspection

Written By
thumbnail
Rob Gravelle
Rob Gravelle
Sep 24, 2015

Implement a Dynamic toString() using JavaBeans Introspection

In the Building a Better toString() Method tutorial, we learned about the importance of overriding the default toString() method in our Java classes. Using Java’s powerful Reflection API, we were able to create a generic toString() that displayed an object’s declared fields and their values. Another way to achieve the same result is to use the JavaBeans API. It supplies a set of classes and interfaces that provide introspection, much in the same way that Java Reflection does. Originally meant to be utilized by builder tools and other automated environments to provide information on a bean, we can make use of them to reveal details about any class. In today’s article, we’ll construct a dynamic toString() method using the BeanInfo class’s getPropertyDescriptors() method.

Obtaining Information about a Bean or Class

Information about a bean or class may be obtained by invoking the Introspector’s static getBeanInfo() method. It has a few different signatures, but the one that we are using accepts two arguments: the object Class and that of the stopClass. The method returns a BeanInfo object that holds details about the class’s properties and exposed methods, but only up to the supplied stopClass, which is the ancestor class at which to stop.

The getBeanInfo() may throw an IntrospectionException so you have to handle it by either throwing it back to the caller or surrounding it with a try/catch block. I chose the latter because I would hate to force every method that calls my function to have to handle the exception.

Here is a class that contains the static objToStringUsingBeanIntrospector() delegate method. When invoked, the method returns the class details produced by the Bean Introspector’s getBeanInfo() method. In the event of an IntrospectionException, our method returns the supplied class name along with the exception message:

package com.robgravelle.tostring;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;

public class ToStringTests {

  public static String objToStringUsingBeanIntrospector(Object obj) {
      BeanInfo info;
      try {
          info = Introspector.getBeanInfo(obj.getClass(), Object.class);
      } catch (IntrospectionException e) {
          return e.getClass().getSimpleName() + ": " + e.getMessage();
      }
      //...

Obtaining Field Names and Types

From a bean perspective, a PropertyDescriptor describes one property that the bean may expose via an accessor (getter) and/or mutator (setter) method. If that sounds like a class field, it’s because it is! Hence, calling the BeanInfo instance’s getPropertyDescriptors() retrieves all of the declared fields of a class. From there we can get individual fields’ names and types within a for loop:

PropertyDescriptor[] props = info.getPropertyDescriptors();
for (PropertyDescriptor pd : props) {
    String name = pd.getName();
    Class<?> type = pd.getPropertyType();
}

Obtaining a Field’s Value

The PropertyDescriptor has an instance method called getReadMethod() that returns a reference to the field’s getter(). We can invoke it to obtain the field’s value. Just make sure to check that there is a getter for that particular field and to surround the invoke() call with a try/catch block because it could throw a few different types of exceptions.

for (PropertyDescriptor pd : props) {
   String name = pd.getName();
   Class<?> type = pd.getPropertyType();
   Method getter = pd.getReadMethod();
   
   if (getter != null) {
      Object value;
      try {
          value = getter.invoke(obj);
      } catch (IllegalAccessException | IllegalArgumentException
               | InvocationTargetException e) {
          return e.getClass().getSimpleName() + ": " + e.getMessage();
      }
   }
}

The objToStringUsingBeanIntrospector() Method

Here is the full source for the objToStringUsingBeanIntrospector() method, including output formatting:

public static String objToStringUsingBeanIntrospector(Object obj) {
        StringBuilder result = new StringBuilder();
        String newLine = System.getProperty("line.separator");

        result.append(obj.getClass().getName());
        result.append(" Object {");
        result.append(newLine);
         
        BeanInfo info;
        try {
            info = Introspector.getBeanInfo(obj.getClass(), Object.class);
        } catch (IntrospectionException e) {
            return e.getClass().getSimpleName() + ": " + e.getMessage();
        }
  PropertyDescriptor[] props = info.getPropertyDescriptors();
  for (PropertyDescriptor pd : props) {
      String name = pd.getName();
      Method getter = pd.getReadMethod();
      Class<?> type = pd.getPropertyType();
    
      if (getter != null) {
        Object value;
        try {
            value = getter.invoke(obj);
        } catch (IllegalAccessException | IllegalArgumentException
              | InvocationTargetException e) {
            return e.getClass().getSimpleName() + ": " + e.getMessage();
        }

        result.append("    " + name);
        result.append(": ");
        result.append(value);
        result.append(", type: ");
        result.append(type);
        result.append(newLine);
     }
  }
  result.append("}");

  return result.toString();
}

Calling the objToStringUsingBeanIntrospector() Method

This example uses the same BankAccount class that we tested in the Building a Better toString() Method tutorial. Just pass the class instance to the function and it returns a nicely formatted string!

public static void main(String[] args) {
  Account account = new BankAccount(1234, "Money Baggs", 1000000);
  System.out.println( objToStringUsingBeanIntrospector( account ) );
}

And here is the output:

ca.gc.cbsa.banking.models.BankAccount Object {
    accountHolderName: Money Baggs, type: class java.lang.String
    accountNumber: 1234, type: int
    balance: 1000000.0, type: double
}

Conclusion

Now that we’ve covered a couple of ways of coding our own generic toString() method, we’ll explore some of the outstanding libraries that others have produced.

Recommended for you...

The Revolutionary ES6 Rest and Spread Operators
Rob Gravelle
Aug 23, 2022
Ahead of Time (AOT) Compilation in Angular
Tariq Siddiqui
Aug 16, 2022
Converting a JavaScript Object to a String
Rob Gravelle
Aug 14, 2022
Understanding Primitive Type Coercion in JavaScript
Rob Gravelle
Jul 28, 2022
HTML Goodies Logo

The original home of HTML tutorials. HTMLGoodies is a website dedicated to publishing tutorials that cover every aspect of being a web developer. We cover programming and web development tutorials on languages and technologies such as HTML, JavaScript, and CSS. In addition, our articles cover web frameworks like Angular and React.JS, as well as popular Content Management Systems (CMS) that include WordPress, Drupal, and Joomla. Website development platforms like Shopify, Squarespace, and Wix are also featured. Topics related to solid web design and Internet Marketing also find a home on HTMLGoodies, as we discuss UX/UI Design, Search Engine Optimization (SEO), and web dev best practices.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.