001/* 002 GRANITE DATA SERVICES 003 Copyright (C) 2013 GRANITE DATA SERVICES S.A.S. 004 005 This file is part of Granite Data Services. 006 007 Granite Data Services is free software; you can redistribute it and/or modify 008 it under the terms of the GNU Library General Public License as published by 009 the Free Software Foundation; either version 2 of the License, or (at your 010 option) any later version. 011 012 Granite Data Services is distributed in the hope that it will be useful, but 013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License 015 for more details. 016 017 You should have received a copy of the GNU Library General Public License 018 along with this library; if not, see <http://www.gnu.org/licenses/>. 019*/ 020 021package org.granite.messaging.jmf.reflect; 022 023import java.lang.reflect.Constructor; 024import java.lang.reflect.Field; 025import java.lang.reflect.InvocationTargetException; 026import java.lang.reflect.Modifier; 027import java.util.ArrayList; 028import java.util.Collections; 029import java.util.Comparator; 030import java.util.List; 031import java.util.concurrent.ConcurrentHashMap; 032import java.util.concurrent.ConcurrentMap; 033 034/** 035 * @author Franck WOLFF 036 */ 037public class Reflection { 038 039 protected static final int STATIC_TRANSIENT_MASK = Modifier.STATIC | Modifier.TRANSIENT; 040 041 protected final ClassLoader classLoader; 042 protected final ConstructorFactory constructorFactory; 043 protected final Comparator<Field> lexicalFieldComparator; 044 protected final ConcurrentMap<Class<?>, List<Field>> serializableFieldsCache; 045 046 public Reflection(ClassLoader classLoader) { 047 this.classLoader = classLoader; 048 049 this.constructorFactory = new SunConstructorFactory(); 050 051 this.lexicalFieldComparator = new Comparator<Field>() { 052 public int compare(Field f1, Field f2) { 053 return f1.getName().compareTo(f2.getName()); 054 } 055 }; 056 057 this.serializableFieldsCache = new ConcurrentHashMap<Class<?>, List<Field>>(); 058 } 059 060 public ClassLoader getClassLoader() { 061 return (classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader()); 062 } 063 064 public Class<?> loadClass(String className) throws ClassNotFoundException { 065 return getClassLoader().loadClass(className); 066 } 067 068 public <T> T newInstance(Class<T> cls) 069 throws InstantiationException, IllegalAccessException, IllegalArgumentException, 070 InvocationTargetException, SecurityException, NoSuchMethodException { 071 072 return findDefaultContructor(cls).newInstance(); 073 } 074 075 @SuppressWarnings("unchecked") 076 public <T> T newInstance(String className) 077 throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, 078 InvocationTargetException, SecurityException, NoSuchMethodException { 079 080 return newInstance((Class<T>)loadClass(className)); 081 } 082 083 084 @SuppressWarnings("unchecked") 085 public <T> Constructor<T> findDefaultContructor(Class<T> cls) throws SecurityException, NoSuchMethodException { 086 087 try { 088 return cls.getConstructor(); 089 } 090 catch (NoSuchMethodException e) { 091 return (Constructor<T>)constructorFactory.newConstructorForSerialization(cls); 092 } 093 } 094 095 public List<Field> findSerializableFields(Class<?> cls) throws SecurityException { 096 List<Field> serializableFields = serializableFieldsCache.get(cls); 097 098 if (serializableFields == null) { 099 List<Class<?>> hierarchy = new ArrayList<Class<?>>(); 100 for (Class<?> c = cls; c != null && c != Object.class; c = c.getSuperclass()) 101 hierarchy.add(c); 102 103 serializableFields = new ArrayList<Field>(); 104 for (int i = hierarchy.size() - 1; i >= 0; i--) { 105 Class<?> c = hierarchy.get(i); 106 serializableFields.addAll(findSerializableDeclaredFields(c)); 107 } 108 serializableFields = Collections.unmodifiableList(serializableFields); 109 List<Field> previous = serializableFieldsCache.putIfAbsent(cls, serializableFields); 110 if (previous != null) 111 serializableFields = previous; 112 } 113 114 return serializableFields; 115 } 116 117 protected List<Field> findSerializableDeclaredFields(Class<?> cls) throws SecurityException { 118 119 if (!isRegularClass(cls)) 120 throw new IllegalArgumentException("Not a regular class: " + cls); 121 122 Field[] declaredFields = cls.getDeclaredFields(); 123 List<Field> serializableFields = new ArrayList<Field>(declaredFields.length); 124 for (int i = 0; i < declaredFields.length; i++) { 125 Field field = declaredFields[i]; 126 127 int modifiers = field.getModifiers(); 128 if ((modifiers & STATIC_TRANSIENT_MASK) == 0) { 129 declaredFields[i].setAccessible(true); 130 serializableFields.add(field); 131 } 132 } 133 134 Collections.sort(serializableFields, lexicalFieldComparator); 135 136 return serializableFields; 137 } 138 139 public boolean isRegularClass(Class<?> cls) { 140 return cls != Class.class && !cls.isAnnotation() && !cls.isArray() && 141 !cls.isEnum() && !cls.isInterface() && !cls.isPrimitive(); 142 } 143} 144