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
021 package org.granite.messaging.jmf.reflect;
022
023 import java.lang.reflect.Constructor;
024 import java.lang.reflect.Field;
025 import java.lang.reflect.InvocationTargetException;
026 import java.lang.reflect.Modifier;
027 import java.util.ArrayList;
028 import java.util.Collections;
029 import java.util.Comparator;
030 import java.util.List;
031 import java.util.concurrent.ConcurrentHashMap;
032 import java.util.concurrent.ConcurrentMap;
033
034 /**
035 * @author Franck WOLFF
036 */
037 public 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