Sunday, December 26, 2010

How to Dump/Inspect Object or Variable in Java

Scala (console) has a very useful feature to inspect or dump variables / object values :

scala> def b = Map("name" -> "Yudha", "age" -> 27)
b: scala.collection.immutable.Map[java.lang.String,Any]

scala> b
res1: scala.collection.immutable.Map[java.lang.String,Any] = Map((name,Yudha), (age,27))

Inside our application, especially in Java programming language (although the techniques below obviously works with any JVM language like Scala and Groovy) sometimes we want to inspect/dump the content of an object/value. Probably for debugging or logging purposes.

My two favorite techniques is just to serialize the Java object to JSON and/or XML. An added benefit is that it's possible to deserialize the dumped object representation back to an actual object if you want.

JSON Serialization with Jackson

Depend on Jackson (using Maven):
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.6.3</version>
</dependency>
Then use it:
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

..
Logger logger = LoggerFactory.getLogger(getClass());

@Test
public void level() throws ServiceException, JsonGenerationException, JsonMappingException, IOException {
MagentoServiceLocator locator = new MagentoServiceLocator();
Mage_Api_Model_Server_HandlerPortType port = locator.getMage_Api_Model_Server_HandlerPort();
String sessionId = port.login("...", "...");
logger.info(String.format("Session ID = %s", sessionId));
Map[] categories = (Map[]) port.call(sessionId, "catalog_category.level", new Object[] { null, null, 2 } );
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
logger.info( mapper.writeValueAsString(categories) );
}

Example output :

6883 [main] INFO id.co.bippo.shop.magentoclient.AppTest - [ {
  "position" : "1",
  "level" : "2",
  "is_active" : "1",
  "name" : "Gamis",
  "category_id" : "3",
  "parent_id" : 2
}, {
  "position" : "2",
  "level" : "2",
  "is_active" : "1",
  "name" : "Celana",
  "category_id" : "5",
  "parent_id" : 2
} ]

XML Serialization with XStream

As a pre-note, XStream can also handle JSON with either Jettison or its own JSON driver, however people usually prefer Jackson than XStream for JSON serialization.

Maven dependency for XStream:
<dependency>
<groupId>xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.2.2</version>
</dependency>
Use it:
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.Map;

import javax.xml.rpc.ServiceException;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.thoughtworks.xstream.XStream;
...
@Test
public void infoXml() throws ServiceException, RemoteException {
MagentoServiceLocator locator = new MagentoServiceLocator();
Mage_Api_Model_Server_HandlerPortType port = locator.getMage_Api_Model_Server_HandlerPort();
String sessionId = port.login("...", "...");
logger.info(String.format("Session ID = %s", sessionId));
Map category = (Map) port.call(sessionId, "catalog_category.info",
new Object[] { 3 } );
XStream xstream = new XStream();
logger.info( xstream.toXML(category) );
}

Sample output:

5949 [main] INFO id.co.bippo.shop.magentoclient.AppTest - <map>
  <entry>
    <string>position</string>
    <string>1</string>
  </entry>
  <entry>
    <string>custom_design</string>
    <string></string>
  </entry>
  <entry>
    <string>custom_use_parent_settings</string>
    <string>0</string>
  </entry>
  <entry>
    <string>custom_layout_update</string>
    <string></string>
  </entry>
  <entry>
    <string>include_in_menu</string>
    <string>1</string>
  </entry>
  <entry>
    <string>custom_apply_to_products</string>
    <string>0</string>
  </entry>
  <entry>
    <string>meta_keywords</string>
    <string>gamis, busana muslim</string>
  </entry>
  <entry>
    <string>available_sort_by</string>
    <string></string>
  </entry>
  <entry>
    <string>url_path</string>
    <string>gamis.html</string>
  </entry>
  <entry>
    <string>children</string>
    <string></string>
  </entry>
  <entry>
    <string>landing_page</string>
    <null/>
  </entry>
  <entry>
    <string>display_mode</string>
    <string>PRODUCTS</string>
  </entry>
  <entry>
    <string>level</string>
    <string>2</string>
  </entry>
  <entry>
    <string>description</string>
    <string>Gamis untuk muslimah</string>
  </entry>
  <entry>
    <string>name</string>
    <string>Gamis</string>
  </entry>
  <entry>
    <string>path</string>
    <string>1/2/3</string>
  </entry>
  <entry>
    <string>created_at</string>
    <string>2010-12-24 11:37:41</string>
  </entry>
  <entry>
    <string>children_count</string>
    <string>0</string>
  </entry>
  <entry>
    <string>is_anchor</string>
    <string>1</string>
  </entry>
  <entry>
    <string>url_key</string>
    <string>gamis</string>
  </entry>
  <entry>
    <string>parent_id</string>
    <int>2</int>
  </entry>
  <entry>
    <string>filter_price_range</string>
    <null/>
  </entry>
  <entry>
    <string>all_children</string>
    <string>3</string>
  </entry>
  <entry>
    <string>is_active</string>
    <string>1</string>
  </entry>
  <entry>
    <string>page_layout</string>
    <string></string>
  </entry>
  <entry>
    <string>image</string>
    <null/>
  </entry>
  <entry>
    <string>category_id</string>
    <string>3</string>
  </entry>
  <entry>
    <string>default_sort_by</string>
    <null/>
  </entry>
  <entry>
    <string>custom_design_from</string>
    <null/>
  </entry>
  <entry>
    <string>updated_at</string>
    <string>2010-12-24 11:37:41</string>
  </entry>
  <entry>
    <string>meta_description</string>
    <string>Jual baju gamis untuk muslim</string>
  </entry>
  <entry>
    <string>custom_design_to</string>
    <null/>
  </entry>
  <entry>
    <string>path_in_store</string>
    <null/>
  </entry>
  <entry>
    <string>meta_title</string>
    <string>Gamis</string>
  </entry>
  <entry>
    <string>increment_id</string>
    <null/>
  </entry>
</map>

Which one is better?

I personally prefer JSON, but fortunately, you always have a choice. :-)