001 /* 002 * JBoss DNA (http://www.jboss.org/dna) 003 * See the COPYRIGHT.txt file distributed with this work for information 004 * regarding copyright ownership. Some portions may be licensed 005 * to Red Hat, Inc. under one or more contributor license agreements. 006 * See the AUTHORS.txt file in the distribution for a full listing of 007 * individual contributors. 008 * 009 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA 010 * is licensed to you under the terms of the GNU Lesser General Public License as 011 * published by the Free Software Foundation; either version 2.1 of 012 * the License, or (at your option) any later version. 013 * 014 * JBoss DNA is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 017 * Lesser General Public License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this software; if not, write to the Free 021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 023 */ 024 package org.jboss.dna.common.util; 025 026 import java.lang.reflect.AccessibleObject; 027 import java.lang.reflect.Field; 028 import java.lang.reflect.Modifier; 029 import java.security.AccessController; 030 import java.security.PrivilegedAction; 031 import java.text.CharacterIterator; 032 import java.text.StringCharacterIterator; 033 034 /** 035 * Static utilities for working with classes. 036 * 037 * @author John Verhaeg 038 */ 039 public final class ClassUtil { 040 041 private static void addObjectString( Object object, 042 int includeInheritedFieldDepth, 043 Class<?> clazz, 044 StringBuffer text ) { 045 046 // Add class's name 047 text.append(nonPackageQualifiedName(clazz)); 048 049 text.append('('); 050 051 // Add class's field names and object's corresponding values 052 Field[] flds = clazz.getDeclaredFields(); 053 boolean separatorNeeded = false; 054 for (int ndx = 0, len = flds.length; ndx < len; ++ndx) { 055 Field fld = flds[ndx]; 056 try { 057 058 // Attempt to ensure fields is accessible. Getting the value will throw an exception if the attempt failed. 059 makeAccessible(fld); 060 Object val = fld.get(object); 061 062 // Skip static fields 063 if ((fld.getModifiers() & Modifier.STATIC) != 0) { 064 continue; 065 } 066 067 // Skip synthetic fields 068 String name = fld.getName(); 069 if (name.indexOf('$') >= 0) { 070 continue; 071 } 072 073 // Add separator in text between fields 074 separatorNeeded = addSeparator(separatorNeeded, text); 075 076 // Add field's name and value to text 077 text.append(fld.getName()); 078 text.append('='); 079 text.append(val); 080 081 } catch (Exception err) { 082 } 083 } 084 085 // Add inheritied fields if requested 086 if (includeInheritedFieldDepth > 0) { 087 separatorNeeded = addSeparator(separatorNeeded, text); 088 addObjectString(object, includeInheritedFieldDepth - 1, clazz.getSuperclass(), text); 089 } 090 091 text.append(')'); 092 } 093 094 private static boolean addSeparator( boolean separatorNeeded, 095 StringBuffer text ) { 096 if (separatorNeeded) { 097 text.append(", "); //$NON-NLS-1$ 098 } 099 return true; 100 } 101 102 /** 103 * @param object 104 */ 105 public static void makeAccessible( final AccessibleObject object ) { 106 if (!object.isAccessible()) { 107 if (System.getSecurityManager() == null) { 108 object.setAccessible(true); 109 } else { 110 AccessController.doPrivileged(new PrivilegedAction<Object>() { 111 112 public Object run() { 113 object.setAccessible(true); 114 return null; 115 } 116 }); 117 } 118 } 119 } 120 121 /** 122 * @param clazz A class. 123 * @return The non-package-qualified name of the specified class. Note, inner class names will still be qualified by their 124 * enclosing class names and a "$" delimiter. 125 */ 126 public static String nonPackageQualifiedName( final Class<?> clazz ) { 127 // if (clazz == null) { 128 // throw new IllegalArgumentException(I18n.format(CommonI18n.mustNotBeNull, "Class")); //$NON-NLS-1$ 129 // } 130 String name = clazz.getName(); 131 return name.substring(name.lastIndexOf('.') + 1); 132 } 133 134 /** 135 * @param object An object. 136 * @return The non-package-qualified name of the class of the specified object. Note, inner class names will still be 137 * qualified by their enclosing class names and a "$" delimiter. 138 */ 139 public static String nonPackageQualifiedName( final Object object ) { 140 // if (object == null) { 141 // throw new IllegalArgumentException(I18n.format(CommonI18n.mustNotBeNull, "Object")); //$NON-NLS-1$ 142 // } 143 return nonPackageQualifiedName(object.getClass()); 144 } 145 146 /** 147 * @param object 148 * @param includeInheritedFieldDepth 149 * @return A string representation of the specified object, consisting of its class name, properties, and property values. 150 */ 151 public static String toString( Object object, 152 int includeInheritedFieldDepth ) { 153 StringBuffer text = new StringBuffer(); 154 addObjectString(object, includeInheritedFieldDepth, object.getClass(), text); 155 return text.toString(); 156 } 157 158 /** 159 * Determine whether the supplied string represents a well-formed fully-qualified Java classname. This utility method enforces 160 * no conventions (e.g., packages are all lowercase) nor checks whether the class is available on the classpath. 161 * 162 * @param classname 163 * @return true if the string is a fully-qualified class name 164 */ 165 public static boolean isFullyQualifiedClassname( String classname ) { 166 if (classname == null) return false; 167 String[] parts = classname.split("[\\.]"); 168 if (parts.length == 0) return false; 169 for (String part : parts) { 170 CharacterIterator iter = new StringCharacterIterator(part); 171 // Check first character (there should at least be one character for each part) ... 172 char c = iter.first(); 173 if (c == CharacterIterator.DONE) return false; 174 if (!Character.isJavaIdentifierStart(c) && !Character.isIdentifierIgnorable(c)) return false; 175 c = iter.next(); 176 // Check the remaining characters, if there are any ... 177 while (c != CharacterIterator.DONE) { 178 if (!Character.isJavaIdentifierPart(c) && !Character.isIdentifierIgnorable(c)) return false; 179 c = iter.next(); 180 } 181 } 182 return true; 183 } 184 185 private ClassUtil() { 186 } 187 }