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.
package com.cloudhopper.commons.util;
/*
* #%L
* ch-commons-util
* %%
* Copyright (C) 2012 Cloudhopper by Twitter
* %%
* 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.
* #L%
*/
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cloudhopper.commons.util.annotation.MetaField;
/**
* Utility class for generating an array of MetaFieldInfo objects at runtime by
* reflecting a class and searching for the MetaField annotation.
*
* NOTE: This automatically handles unwrapping certain types such as an AtomicReference
* where the actual values you'd want to validate is the one contained within.
*
* @author joelauer (twitter: @jjlauer or http://twitter.com/jjlauer)
*/
public class MetaFieldUtil {
private static Logger logger = LoggerFactory.getLogger(MetaFieldUtil.class);
/**
* Creates a string for an object based on the MetaField annotations.
* @param obj The object to search
* @return A string representing the current values of any MetaFields
*/
public static String toMetaFieldInfoString(Object obj) {
StringBuffer buf = new StringBuffer(100);
MetaFieldInfo[] fields = toMetaFieldInfoArray(obj, null, true);
for (int i = 0; i < fields.length; i++) {
MetaFieldInfo field = fields[i];
buf.append(field.name);
buf.append("=");
// if the field's actual value is non-null and of type String
if (field.actualValue != null && field.actualValue.getClass().equals(String.class)) {
buf.append('"');
buf.append(field.value);
buf.append('"');
} else {
buf.append(field.value);
}
// if not last element, delimit with a comma
if (i+1 < fields.length)
buf.append(",");
}
return buf.toString();
}
/**
* Returns a new MetaFieldInfo array of all Fields annotated with MetaField
* in the runtime object type. If the object is null, this method will
* return null. Will use the default "null" string representation of
* null values. NOTE: This method recursively searches the object.
* @param obj The runtime instance of the object to search. It must be an
* instance of the type. If its a subclass of the type, this method
* will only return MetaFields of the type passed in.
* @return The MetaFieldInfo array
*/
public static MetaFieldInfo[] toMetaFieldInfoArray(Object obj) {
return toMetaFieldInfoArray(obj, null);
}
/**
* Returns a new MetaFieldInfo array of all Fields annotated with MetaField
* in the runtime object type. If the object is null, this method will
* return null. NOTE: This method recursively searches the object.
* @param obj The runtime instance of the object to search. It must be an
* instance of the type. If its a subclass of the type, this method
* will only return MetaFields of the type passed in.
* @param stringForNullValues If a field is null, this is the string to swap
* in as the String value vs. "null" showing up.
* @return The MetaFieldInfo array
*/
public static MetaFieldInfo[] toMetaFieldInfoArray(Object obj, String stringForNullValues) {
return toMetaFieldInfoArray(obj, stringForNullValues, false);
}
/**
* Returns a new MetaFieldInfo array of all Fields annotated with MetaField
* in the runtime object type. If the object is null, this method will
* return null. NOTE: This method recursively searches the object.
* @param obj The runtime instance of the object to search. It must be an
* instance of the type. If its a subclass of the type, this method
* will only return MetaFields of the type passed in.
* @param stringForNullValues If a field is null, this is the string to swap
* in as the String value vs. "null" showing up.
* @param ignoreAnnotatedName Whether to ignore the name of the MetaField
* and always return the field name instead. If false, this method will
* use the annotated name if it exists, otherwise it'll use the field name.
* @return The MetaFieldInfo array
*/
public static MetaFieldInfo[] toMetaFieldInfoArray(Object obj, String stringForNullValues, boolean ignoreAnnotatedName) {
return toMetaFieldInfoArray((obj != null ? obj.getClass() : null), obj, stringForNullValues, ignoreAnnotatedName, true);
}
/**
* Returns a new MetaFieldInfo array of all Fields annotated with MetaField
* in the object type. The object must be an instance of the type, otherwise
* this method may throw a runtime exception. Optionally, this method can
* recursively search the object to provide a deep view of the entire class.
* @param type The class type of the object
* @param obj The runtime instance of the object to search. It must be an
* instance of the type. If its a subclass of the type, this method
* will only return MetaFields of the type passed in.
* @param stringForNullValues If a field is null, this is the string to swap
* in as the String value vs. "null" showing up.
* @param ignoreAnnotatedName Whether to ignore the name of the MetaField
* and always return the field name instead. If false, this method will
* use the annotated name if it exists, otherwise it'll use the field name.
* @param recursive If true, this method will recursively search any fields
* to see if they also contain MetaField annotations. If they do, this
* method will include those in its returned array.
* @return The MetaFieldInfo array
*/
public static MetaFieldInfo[] toMetaFieldInfoArray(Class type, Object obj, String stringForNullValues, boolean ignoreAnnotatedName, boolean recursive) {
return internalToMetaFieldInfoArray(type, obj, null, null, stringForNullValues, ignoreAnnotatedName, recursive);
}
/**
* Optionally, recursively returns a new MetaFieldInfo array of all Fields
* annotated with MetaField in the object. If recursive is true, this will
* also search any fields in each class and add them in their order as well.
* @param type The class type of the obj (in case obj is null)
* @param obj The object to search. If this is null, will default values for each field to null.
* @param appendFieldName Will append this value to the name of the field (really for subfields)
* @param stringForNullValues If a field is null, this is the string to swap
* in as the String value vs. "null" showing up.
* @return The new MetaFieldInfo array
*/
protected static MetaFieldInfo[] internalToMetaFieldInfoArray(Class type, Object obj, String preFieldName,
String postFieldName, String stringForNullValues, boolean ignoreAnnotatedName, boolean recursive) {
// get the class hierarchy
Class[] hierarchy = ClassUtil.getClassHierarchy(type);
// if the class hierarchy is 0 (there are definitely no meta fields to process
if (hierarchy == null || hierarchy.length == 0)
return null;
// create the array we'll return
ArrayList infos = new ArrayList();
// make sure appendFieldName is always an empty String
if (preFieldName == null)
preFieldName = "";
if (postFieldName == null)
postFieldName = "";
// keep searching up until we reach an Object class type
for (Class classType : hierarchy) {
// begin search for each field (variable)
for (Field f : classType.getDeclaredFields()) {
// is this field marked as a MetaField?
if (f.isAnnotationPresent(MetaField.class)) {
// get the annotation
MetaField metaField = f.getAnnotation(MetaField.class);
// create the new counter info object we'll store
// now, this class may actually still represent a class we want to recursively search
// we'll create the new info object for now, but this may change
MetaFieldInfo info = new MetaFieldInfo();
// save the field name
info.fieldName = f.getName();
// save the field class
info.fieldClass = f.getType();
// save the level
info.level = metaField.level();
// is there an annotated name? if not we'll default to the field name
info.name = preFieldName + (!metaField.name().equals("") && !ignoreAnnotatedName ? metaField.name() : f.getName()) + postFieldName;
// default the recursive pre field names
String recursivePreFieldName = preFieldName + f.getName() + ".";
String recursivePostFieldName = "";
// if this had an actual name, not using the field name, slightly diff format
if (!metaField.name().equals("") && !ignoreAnnotatedName) {
// only add [ and ] if this is not the first
if (!preFieldName.equals("")) {
recursivePreFieldName = preFieldName + metaField.name() + "][";
recursivePostFieldName = "]";
} else {
recursivePreFieldName = metaField.name() + "[";
recursivePostFieldName = "]";
}
}
// required to read private variables
f.setAccessible(true);
// read the actual value if the obj isn't null
if (obj != null) {
// get the actual value
try {
info.actualValue = f.get(obj);
} catch (Exception e) {
logger.error("impossible case if run outside of an applet");
}
//
// handle "unwrapping" objects -- AtomicReference
//
if (info.actualValue != null && f.getType().equals(AtomicReference.class)) {
//logger.debug("AtomicReference found, going to unwrap it");
AtomicReference ref = (AtomicReference)info.actualValue;
// get the actual underlying value
info.actualValue = ref.get();
// if not null, we can get its type too
if (info.actualValue != null) {
info.fieldClass = info.actualValue.getClass();
}
}
} else {
info.actualValue = null;
}
// get a proper string value of this counter
if (info.actualValue == null) {
info.value = stringForNullValues;
} else {
info.value = info.actualValue.toString();
}
// add our annotated description
info.description = metaField.description();
// if this is recursive, we need to check of the subvalues are actually wanted instead...
// if the actual value is null though, we know the sub-values are null...
if (recursive) {
// see if there are any MetaFields in the sub-object
MetaFieldInfo[] subInfos = internalToMetaFieldInfoArray(info.fieldClass, info.actualValue, recursivePreFieldName, recursivePostFieldName, stringForNullValues, ignoreAnnotatedName, recursive);
// was anything returned
if (subInfos == null || subInfos.length == 0) {
infos.add(info);
} else {
// otherwise, add everything
// if there were any, also add these
for (MetaFieldInfo subInfo : subInfos) {
infos.add(subInfo);
}
}
} else {
// add this to our array
infos.add(info);
}
}
}
}
// return our array
return infos.toArray(new MetaFieldInfo[0]);
}
}