Created
August 19, 2010 16:53
-
-
Save jawspeak/538350 to your computer and use it in GitHub Desktop.
BeanDumper useful for printing java objects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.utility; | |
import com.google.common.base.Predicate; | |
import com.google.common.collect.ImmutableList; | |
import static com.google.common.collect.Iterables.*; | |
import org.joda.time.LocalDate; | |
import org.joda.time.LocalDateTime; | |
import org.joda.time.LocalTime; | |
import java.beans.BeanInfo; | |
import static java.beans.Introspector.*; | |
import java.beans.PropertyDescriptor; | |
import java.io.ByteArrayOutputStream; | |
import java.io.PrintStream; | |
import static java.lang.String.*; | |
import java.io.PrintWriter; | |
import java.lang.reflect.Array; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.math.BigDecimal; | |
import java.math.BigInteger; | |
import java.util.Date; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
public class BeanDumper { | |
private interface Processor { | |
boolean canProcess(Object value); | |
void dump(Object value, String context, BeanDumper dumper) throws Throwable; | |
} | |
private class PrimitiveProcessor implements Processor { | |
private List<Class> types = ImmutableList.<Class>builder(). | |
add(BigDecimal.class). | |
add(BigInteger.class). | |
add(Boolean.class). | |
add(Boolean.TYPE). | |
add(Byte.class). | |
add(Byte.TYPE). | |
add(Character.class). | |
add(Character.TYPE). | |
add(Class.class). | |
add(Date.class). | |
add(Double.class). | |
add(Double.TYPE). | |
add(Float.class). | |
add(Float.TYPE). | |
add(Integer.class). | |
add(Integer.TYPE). | |
add(LocalDate.class). | |
add(LocalDateTime.class). | |
add(LocalTime.class). | |
add(Long.class). | |
add(Long.TYPE). | |
add(Short.class). | |
add(Short.TYPE). | |
add(String.class). | |
build(); | |
public boolean canProcess(Object value) { | |
return value == null || value.getClass().isEnum() || types.contains(value.getClass()); | |
} | |
public void dump(Object value, String context, BeanDumper dumper) throws Exception { | |
out.printf("%s=%s\n", context, value); | |
} | |
} | |
private class MapProcessor implements Processor { | |
public boolean canProcess(Object value) { | |
return value instanceof Map; | |
} | |
public void dump(Object value, String context, BeanDumper dumper) throws Exception { | |
for (Map.Entry item : (Set<Map.Entry>) ((Map) value).entrySet()) { | |
dumper.dump(item.getValue(), format("%s[%s]", context, item.getKey())); | |
} | |
} | |
} | |
private class ArrayProcessor implements Processor { | |
public boolean canProcess(Object value) { | |
return value.getClass().isArray(); | |
} | |
public void dump(Object value, String context, BeanDumper dumper) throws Exception { | |
int length = Array.getLength(value); | |
for (int index = 0; index < length; index++) { | |
Object item = Array.get(value, index); | |
dumper.dump(item, format("%s[%s]", context, index)); | |
} | |
} | |
} | |
private class IterableProcessor implements Processor { | |
public boolean canProcess(Object value) { | |
return value instanceof Iterable; | |
} | |
public void dump(Object value, String context, BeanDumper dumper) throws Exception { | |
int index = 0; | |
for (Object item : (Iterable) value) { | |
dumper.dump(item, format("%s[%s]", context, index++)); | |
} | |
} | |
} | |
private class BeanProcessor implements Processor { | |
public boolean canProcess(Object value) { | |
return true; | |
} | |
public void dump(Object value, String context, BeanDumper dumper) throws Throwable { | |
BeanInfo beanInfo = getBeanInfo(value.getClass()); | |
for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) { | |
Method readMethod = descriptor.getReadMethod(); | |
if (readMethod == null) continue; | |
try { | |
dumper.dump(readMethod.invoke(value), format("%s.%s", context, descriptor.getName())); | |
} catch (InvocationTargetException e) { | |
throw e.getCause(); | |
} | |
} | |
} | |
} | |
private static class CanProcess implements Predicate<Processor> { | |
private final Object value; | |
public CanProcess(Object value) { | |
this.value = value; | |
} | |
public boolean apply(Processor processor) { | |
return processor.canProcess(value); | |
} | |
} | |
private List<Processor> processors = ImmutableList.<Processor>builder(). | |
add(new PrimitiveProcessor()). | |
add(new MapProcessor()). | |
add(new IterableProcessor()). | |
add(new ArrayProcessor()). | |
add(new BeanProcessor()). | |
build(); | |
private PrintStream out = System.out; | |
public BeanDumper() { | |
} | |
public static String dumpToString(Object value, String context) { | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
BeanDumper beanDumper = new BeanDumper(new PrintStream(baos)); | |
beanDumper.dump(value, context); | |
return baos.toString(); | |
} | |
public BeanDumper(PrintStream out) { | |
this.out = out; | |
} | |
public void dump(Object value, String context) { | |
try { | |
find(processors, new CanProcess(value)).dump(value, context, this); | |
} catch (Throwable e) { | |
e.printStackTrace(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.utility; | |
import com.google.common.collect.Lists; | |
import org.junit.Test; | |
import static junit.framework.Assert.assertEquals; | |
public class BeanDumperTest { | |
@Test | |
public void dumpList() { | |
String expected = "list[0]=null\n" + | |
"list[1]=null\n"; | |
assertEquals(expected, BeanDumper.dumpToString(Lists.newArrayList(null, null), "list")); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment