/* * Copyright 2014-2015 JKOOL, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jkoolcloud.tnt4j.dump; import java.lang.ref.WeakReference; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Map; import com.jkoolcloud.tnt4j.utils.SizeOf; /** * <p> * This class dumps the contents of a given object using reflection. All fields and their values are reported as part of * the <code>DumpCollection</code> collection. * </p> * * @see DumpCollection * * @version $Revision: 6 $ * */ public class ObjectDumpProvider extends DefaultDumpProvider { WeakReference<Object> ref = null; private int max_size = 1000; private boolean shallowSizeOf = true, deepSizeOf = true; /** * Create a new java object dump provider with a given name and user specified object * *@param name * provider name *@param obj * object to be dumped */ public ObjectDumpProvider(String name, Object obj) { this(name, "Objects", obj); } /** * Create a new java object dump provider with a given name and user specified object * *@param name * provider name *@param cat * provider category *@param obj * object to be dumped */ public ObjectDumpProvider(String name, String cat, Object obj) { super(name, cat); ref = new WeakReference<Object>(obj); } /** * Enable/disable shallow, deep memory size of the object associated with this * dump provider. * *@param shallow * enable shallow sizeOf object reporting *@param deep * enable deep sizeOf object reporting */ public void setMemorySizeOf(boolean shallow, boolean deep) { shallowSizeOf = shallow; deepSizeOf = deep; } /** * Set the maximum collection, map size limit for which to report collection value. This is done to avoid dumping of large * collections. Collections, maps at or below the max will be dumped as a collection value otherwise just collection * size is reported * *@param max * maximum collection, map size limit */ public void setMaxCollectionLimit(int max) { max_size = max; } /** * Obtain maximum collection, map size limit for which to report collection value. This is done to avoid dumping of large * collections. Collections, maps at or below the max will be dumped as a collection value otherwise just collection * size is reported * *@return max maximum collection, map size limit */ public int getMaxCollectionLimit() { return max_size; } private Dump getFields(Class<?> clazz, Object dObj, Dump dump) { Field[] fields = clazz.getDeclaredFields(); for (Field fld: fields) { fld.setAccessible(true); try { dump.add(clazz.getName() + "." + fld.getName() + ".$type", fld.getType().getName()); dump.add(clazz.getName() + "." + fld.getName() + ".$modifiers", Modifier.toString(fld.getModifiers())); Object fHandle = fld.get(dObj); boolean dumpValue = true; if (fHandle instanceof Collection<?>) { int size = ((Collection<?>) fHandle).size(); dumpValue = size <= max_size; dump.add(clazz.getName() + "." + fld.getName() + ".$size", size); } else if (fHandle instanceof Map<?, ?>) { int size = ((Map<?, ?>) fHandle).size(); dumpValue = size <= max_size; dump.add(clazz.getName() + "." + fld.getName() + ".$size", size); } else if (clazz.isArray()) { int size = Array.getLength(dObj); dumpValue = size <= max_size; dump.add(clazz.getName() + "." + fld.getName() + ".$size", size); } if (dumpValue) dump.add(clazz.getName() + "." + fld.getName() + ".$value", String.valueOf(fHandle)); if (fHandle != null) { dump.add(clazz.getName() + "." + fld.getName() + ".$class", fHandle.getClass().getName()); long sizeOf = SizeOf.sizeOf(fHandle); if (sizeOf > 0) { dump.add(clazz.getName() + "." + fld.getName() + ".$sizeOf", sizeOf); } sizeOf = fld.getType().isPrimitive()? 0: SizeOf.deepSizeOf(fHandle); if (sizeOf > 0) { dump.add(clazz.getName() + "." + fld.getName() + ".$deepSizeOf", sizeOf); } } } catch (Throwable e) { dump.add(clazz.getName() + "." + fld.getName() + ".$exception", e); } } Class<?> superClass = clazz.getSuperclass(); if (superClass != null) { return getFields(superClass, dObj, dump); } return dump; } @Override public DumpCollection getDump() { Dump dump = null; Object dObj = ref.get(); if (dObj != null) { dump = new Dump(dObj.toString(), this); Class<?> clazz = dObj.getClass(); if (shallowSizeOf) { long size = SizeOf.sizeOf(dObj); if (size > 0) dump.add(clazz.getName() + ".$sizeOf", size); } if (deepSizeOf) { long size = SizeOf.deepSizeOf(dObj); if (size > 0) dump.add(clazz.getName() + ".$deepSizeOf", size); } dump.add(clazz.getName() + ".$classloader", String.valueOf(clazz.getClassLoader())); getFields(clazz, dObj, dump); } return dump; } }