Java tutorial
// // Copyright (C) 2010-2016 Micromata GmbH // // 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 de.micromata.genome.util.strings; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.IdentityHashMap; import java.util.Map; import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; /** * The Class ReducedReflectionToStringBuilder. * * @author roger@micromata.de */ public class ReducedReflectionToStringBuilder extends ReflectionToStringBuilder { /** * Instantiates a new reduced reflection to string builder. * * @param object the object */ public ReducedReflectionToStringBuilder(Object object) { super(object); } /** * Instantiates a new reduced reflection to string builder. * * @param object the object * @param style the style * @param buffer the buffer * @param reflectUpToClass the reflect up to class * @param outputTransients the output transients * @param outputStatics the output statics */ public <T> ReducedReflectionToStringBuilder(T object, ToStringStyle style, StringBuffer buffer, Class<? super T> reflectUpToClass, boolean outputTransients, boolean outputStatics) { super(object, style, buffer, reflectUpToClass, outputTransients, outputStatics); } /** * Instantiates a new reduced reflection to string builder. * * @param object the object * @param style the style * @param buffer the buffer */ public ReducedReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) { super(object, style, buffer); } /** * Instantiates a new reduced reflection to string builder. * * @param object the object * @param style the style */ public ReducedReflectionToStringBuilder(Object object, ToStringStyle style) { super(object, style); } /** * Reflection to string. * * @param object the object * @param style the style * @param outputTransients the output transients * @param reflectUpToClass the reflect up to class * @return the string */ @SuppressWarnings("rawtypes") public static String reflectionToString(Object object, ToStringStyle style, boolean outputTransients, Class reflectUpToClass) { return ReducedReflectionToStringBuilder.toString(object, style, outputTransients, false, reflectUpToClass); } /** * To string. * * @param object the object * @param style the style * @param outputTransients the output transients * @param outputStatics the output statics * @param reflectUpToClass the reflect up to class * @return the string */ @SuppressWarnings("rawtypes") public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics, Class reflectUpToClass) { return new ReducedReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics).toString(); } /** * The Class Registry. */ public static class Registry { /** * The level. */ public int level = 0; /** * The visited. */ public Map<Object, Object> visited = new IdentityHashMap<Object, Object>(); } /** * The registry. */ private static ThreadLocal<Registry> registry = new ThreadLocal<Registry>() { @Override protected synchronized Registry initialValue() { return new Registry(); } }; /** * Push registry. */ public static void pushRegistry() { Registry r = registry.get(); ++r.level; } /** * Pop registry. */ public static void popRegistry() { Registry r = registry.get(); if (--r.level == 0) { r.visited.clear(); } } static public Map<Object, Object> getRegistry() { return registry.get().visited; } static public Registry getRegistryObject() { return registry.get(); } /** * Checks if is object registered. * * @param value the value * @return true, if is object registered */ static public boolean isObjectRegistered(Object value) { return getRegistry().containsKey(value); } /** * Register object. * * @param value the value */ static public void registerObject(Object value) { getRegistry().put(value, null); } /** * Super to string. * * @return the string */ public String superToString() { if (this.getObject() == null) { this.getStringBuffer().append("<null>"); } else { getStyle().appendEnd(this.getStringBuffer(), this.getObject()); } return this.getStringBuffer().toString(); } @Override public String toString() { if (this.getObject() == null) { return super.toString(); } if (isObjectRegistered(this.getObject()) == true) { // The object has already been appended, therefore we have an // object cycle. // Append a simple Object.toString style string. The field name is // already appended at this point. this.appendAsObjectToString(this.getObject()); // return superToString(); return getStringBuffer().toString(); // } String ret = ""; pushRegistry(); try { Class<?> clazz = this.getObject().getClass(); if (this.appendFieldsInInternal(clazz) == true) { while (clazz.getSuperclass() != null && clazz != this.getUpToClass()) { clazz = clazz.getSuperclass(); this.appendFieldsInInternal(clazz); } } // getStyle().appendEnd(this.getStringBuffer(), this.getObject()); ret = superToString(); // ret = getStringBuffer().toString(); } finally { popRegistry(); } return ret; } @Override public ToStringBuilder appendAsObjectToString(Object object) { this.getStringBuffer().append(object.getClass().getSimpleName()).append('@') .append(Integer.toHexString(System.identityHashCode(object))); if (object instanceof ShortDisplayable) { this.getStringBuffer().append("[").append(((ShortDisplayable) object).toShortString()).append("]"); } return this; } @Override protected boolean accept(Field field) { // if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) { // // Reject field from inner class. // return false; // } if (field.getAnnotation(NoStringifyAnnotation.class) != null) { return false; } if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) { // transients. return false; } if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) { // transients. return false; } return true; } @SuppressWarnings("unchecked") @Override protected void appendFieldsIn(Class clazz) { appendFieldsInInternal(clazz); } /** * Append fields in internal. * * @param clazz the clazz * @return true, if successful */ protected boolean appendFieldsInInternal(Class<?> clazz) { registerObject(getObject()); if (clazz.isArray()) { this.reflectionAppendArray(this.getObject()); return false; } Field[] fields = clazz.getDeclaredFields(); AccessibleObject.setAccessible(fields, true); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; String fieldName = field.getName(); if (this.accept(field) == false) { continue; } try { // Warning: Field.get(Object) creates wrappers objects // for primitive types. Object fieldValue = this.getValue(field); if (isObjectRegistered(fieldValue) == true && field.getType().isPrimitive() == false) { this.getStringBuffer().append(fieldName).append("="); this.appendAsObjectToString(fieldValue); this.getStringBuffer().append(","); } else { this.append(fieldName, fieldValue); } } catch (IllegalAccessException ex) { // this can't happen. Would get a Security exception // instead // throw a runtime exception in case the impossible // happens. throw new InternalError("Unexpected IllegalAccessException: " + ex.getMessage()); } } return true; } }