Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
patterntesting.runtime.util.ObjectInspector Maven / Gradle / Ivy
Go to download
PatternTesting Runtime (patterntesting-rt) is the runtime component for
the PatternTesting framework. It provides the annotations and base classes
for the PatternTesting testing framework (e.g. patterntesting-check,
patterntesting-concurrent or patterntesting-exception) but can be also
used standalone for classpath monitoring or profiling.
It uses AOP and AspectJ to perform this feat.
/*
* $Id: ObjectInspector.java,v 1.10 2013/12/19 21:53:57 oboehm Exp $
*
* Copyright (c) 2012 by Oliver Boehm
*
* 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 orimplied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* (c)reated 24.01.2012 by oliver ([email protected] )
*/
package patterntesting.runtime.util;
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Pattern;
import org.slf4j.*;
/**
* This class lets you examine an object and dump its internal attributes.
* It was introduced to find some secrets of IBM's classloader.
*
* @author oboehm
* @since 1.2.10-YEARS (24.01.2012)
*/
public final class ObjectInspector {
/** The value for "nothing found". */
public static final String NOTHING_FOUND = null;
private static final Logger log = LoggerFactory.getLogger(ObjectInspector.class);
private final Object inspected;
private final Set visited = new HashSet();
/**
* Instantiates a new object inspector.
*
* @param obj the object to be inspected
*/
public ObjectInspector(final Object obj) {
this.inspected = obj;
}
/**
* Gets the type (class) of the stored object.
*
* @return the type
*/
public Class> getType() {
return this.inspected.getClass();
}
/**
* Find the value in of the attributes of the inspected object. You can
* give a {@link Pattern} as parameter if you want to use wildcards for
* the search.
*
* @param value the value or the pattern you want to look for
* @return the string
* @throws ValueNotFoundException the value not found exception
*/
public String findValue(final Object value) throws ValueNotFoundException {
try {
return findValue(value, this.inspected, this.inspected.getClass().getName());
} finally {
this.visited.clear();
}
}
private String findValue(final Object value, final Object where, final String path)
throws ValueNotFoundException {
for (Field field : getAllFields(where.getClass())) {
field.setAccessible(true);
try {
Object obj = field.get(where);
String fieldPath = path + "." + field.getName();
if (isEquals(obj, value)) {
return fieldPath;
}
if (alreadyVisited(obj)) {
continue;
}
if (isArrayType(obj)) {
return findArrayValue(value, obj, fieldPath);
} else if (isIterable(obj)) {
return findValue(value, getIterator(obj), fieldPath);
} else if (isComplexType(obj)) {
try {
return findValue(value, obj, fieldPath);
} catch (ValueNotFoundException vnfe) {
log.trace("value not found in {}.{}", path, field);
}
}
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("can't access " + field + " in "
+ where.getClass());
}
}
throw new ValueNotFoundException(value);
}
private String findArrayValue(final Object value, final Object where, final String path)
throws ValueNotFoundException {
try {
Object[] objects = (Object[]) where;
for (int i = 0; i < objects.length; i++) {
String arrayPath = path + "[" + i + "]";
if (isEquals(value, objects[i])) {
return arrayPath;
}
if (objects[i] == null) {
continue;
}
try {
return findValue(value, objects[i], path + ".");
} catch (ValueNotFoundException vnfe) {
log.trace("value not found in {}.", arrayPath);
}
}
} catch (ClassCastException cce) {
log.trace("Do not look in native array {} for {}.", where, value);
}
throw new ValueNotFoundException(value);
}
private String findValue(final Object value, final Iterator> where, final String path)
throws ValueNotFoundException {
int i = 0;
while (where.hasNext()) {
Object obj = where.next();
String arrayPath = path + "[" + i + "]";
if (isEquals(value, obj)) {
return arrayPath;
}
try {
return findValue(value, obj, arrayPath);
} catch (ValueNotFoundException vnfe) {
log.trace("value not found in {}.", arrayPath);
}
}
throw new ValueNotFoundException(value);
}
private static boolean isEquals(final Object one, final Object two) {
if (one == null) {
return two == null;
}
if (two == null) {
return false;
}
if (one.equals(two)) {
return true;
}
try {
Pattern pattern = (Pattern) one;
return pattern.matcher(two.toString()).matches();
} catch (ClassCastException cce) {
return false;
}
}
/**
* Gets all fields of the wrapped object. Not only the (public) class
* fields but also the private and protected fields of the superclass.
*
* @return the all fields
*/
public Collection getAllFields() {
return getAllFields(this.inspected.getClass());
}
private static Collection getAllFields(final Class> clazz) {
Collection fields = new ArrayList();
addFields(fields, clazz);
return fields;
}
private static void addFields(final Collection fields, final Class> clazz) {
Class> superclass = clazz.getSuperclass();
if (superclass != null) {
addFields(fields, superclass);
}
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
}
/**
* Dump the inspected class.
*
* @param writer the writer
* @throws IOException Signals that an I/O exception has occurred.
*/
public synchronized void dump(final Writer writer) throws IOException {
writer.append("=== Dump of " + this.inspected.getClass() + " ===\n");
dump(writer, this.inspected, this.inspected.getClass().getName());
this.visited.clear();
}
private void dump(final Writer writer, final Object obj, final String prefix)
throws IOException {
if (obj == null) {
writer.append(prefix + "(null)\n");
return;
}
Collection fields = getAllFields(obj.getClass());
for (Field field : fields) {
dump(writer, field, obj, prefix);
try {
Object value = field.get(obj);
if ((value == null) || alreadyVisited(value)) {
continue;
}
if (isArrayType(value)) {
dumpArray(writer, value, prefix);
} else if (isIterable(value)) {
try {
Iterator> iterator = getIterator(value);
int i = 0;
while (iterator.hasNext()) {
Object next = iterator.next();
dump(writer, next, prefix + "[" + i + "]");
i++;
}
} catch (ConcurrentModificationException cme) {
log.warn("Houston, we have a problem with iterator of " + value, cme);
writer.append(prefix + "[..]");
writer.append(" = ??? (" + cme + ")\n");
ThreadUtil.sleep();
}
} else if (isComplexType(value)) {
dump(writer, value, prefix + "." + field.getName());
}
} catch (IllegalAccessException iae) {
throw new IllegalArgumentException("can't access " + field, iae);
}
}
}
private static void dump(final Writer writer, final Field field, final Object obj,
final String prefix) throws IOException {
field.setAccessible(true);
writer.append(prefix);
writer.append('.');
writer.append(field.getName());
writer.append(" = (");
writer.append(field.getType().getSimpleName());
writer.append(") ");
try {
writer.append(Converter.toString(field.get(obj)));
} catch (IllegalAccessException iae) {
log.debug("can't access field {}", field, iae);
writer.append("??? (");
writer.append(iae.getLocalizedMessage());
writer.append(")");
}
writer.append("\n");
}
private void dumpArray(final Writer writer, final Object value, final String prefix)
throws IOException {
try {
Object[] array = (Object[]) value;
for (int i = 0; i < array.length; i++) {
dump(writer, array[i], prefix + "[" + i + "]");
}
} catch (ClassCastException cce) {
log.trace("Native array {} is not dumped with each element.", value);
}
}
/**
* Checks if the wrapped object is complex type.
*
* @return true, if is complex type
*/
public boolean isComplexType() {
return isComplexType(this.inspected);
}
/**
* Checks if the given object is of complex type. These are all types which
*
* are not a primitive type (like int, char, ...)
* are not a String class
* are not of subtype Numer (like Long, Short, ...)
*
*
* @param obj the obj
* @return true, if is complex type
*/
public static boolean isComplexType(final Object obj) {
if (obj == null) {
return false;
}
Class> clazz = obj.getClass();
if (clazz.isPrimitive()) {
return false;
}
if (String.class.equals(clazz)) {
return false;
}
if (Number.class.isAssignableFrom(clazz)) {
return false;
}
if (Character.class.isAssignableFrom(clazz)) {
return false;
}
return true;
}
/**
* Checks if the wrapped object is an array type.
*
* @return true, if is array type
*/
public boolean isArrayType() {
return isArrayType(this.inspected);
}
/**
* Checks if the given object is an array.
*
* @param obj the obj
* @return true, if is array type
*/
public static boolean isArrayType(final Object obj) {
if (obj == null) {
return false;
}
Class> clazz = obj.getClass();
return clazz.isArray();
}
/**
* Checks if the type of the wrapped object could be iterated. This is the
* case e.g. for Collections and its subclasses.
*
* @return true, if is iterable
*/
public boolean isIterable() {
return isIterable(this.inspected);
}
/**
* Checks if the type of the given object could be iterated. This is the
* case e.g. for Collections and its subclasses.
*
* @param obj the object
* @return true, if is iterable
*/
public static boolean isIterable(final Object obj) {
if (obj == null) {
return false;
}
Class> clazz = obj.getClass();
try {
clazz.getMethod("iterator");
return true;
} catch (SecurityException e) {
throw new IllegalArgumentException("can't access methods for " + clazz, e);
} catch (NoSuchMethodException e) {
return false;
}
}
private static Iterator> getIterator(final Object value) {
return (Iterator>) ReflectionHelper.invokeMethod(value, "iterator");
}
private boolean alreadyVisited(final Object value) {
try {
if (visited.contains(value)) {
return true;
}
visited.add(value);
} catch (RuntimeException ex) {
log.debug("can't store \"{}\"", value, ex);
}
return false;
}
/**
* Dumps all attributes of the inspected object in the form
* attribute=value
.
*
* @return the string
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return this.getClass().getSimpleName() + " for " + this.inspected.getClass();
}
/**
* To long string.
*
* @return the string
*/
public String toLongString() {
StringBuilder buffer = new StringBuilder();
Class> clazz = this.inspected.getClass();
while(clazz != null) {
buffer.insert(0, toString(clazz.getDeclaredFields()));
clazz = clazz.getSuperclass();
}
return buffer.toString();
}
private String toString(final Field[] fields) {
return toString(fields, this.inspected);
}
private static String toString(final Field[] fields, final Object obj) {
StringWriter buffer = new StringWriter();
try {
for (int i = 0; i < fields.length; i++) {
dump(buffer, fields[i], obj, "");
}
buffer.close();
} catch (IOException canthappen) {
log.info("I have some problems dumping fields {}.", fields, canthappen);
}
return buffer.toString();
}
}