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