]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/ClassInfo.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / binding / reflection / ClassInfo.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard.binding.reflection;\r
13 \r
14 import java.lang.reflect.Constructor;\r
15 import java.lang.reflect.Field;\r
16 import java.lang.reflect.Method;\r
17 import java.lang.reflect.Modifier;\r
18 import java.util.ArrayList;\r
19 import java.util.Collection;\r
20 import java.util.LinkedList;\r
21 \r
22 import org.simantics.databoard.binding.error.BindingConstructionException;\r
23 \r
24 public class ClassInfo {\r
25 \r
26         public Constructor<?> argsConstructor, noArgsConstructor, beanConstructor;\r
27         public Class<?> clazz;\r
28         public Field[] fields;\r
29         public Method[] getters, setters;\r
30         public boolean[] writable;\r
31         public boolean partialConstructionPossible; // set to true, if partial construction is possible\r
32         \r
33         public static ClassInfo getInfo(Class<?> clazz)\r
34         throws BindingConstructionException\r
35         {\r
36                 boolean isAbstract = (clazz.getModifiers() & Modifier.ABSTRACT) != 0; \r
37 //              if ( isAbstract )\r
38 //                      throw new BindingConstructionException("Cannot create reflection binding to abstract class "+clazz);\r
39                 \r
40                 ClassInfo ci = new ClassInfo();\r
41                 ci.clazz = clazz;\r
42                 try {\r
43                         ci.fields = getFields(clazz);\r
44                         for (Field f : ci.fields)\r
45                                 f.setAccessible(true);\r
46 \r
47                         int c = ci.fields.length;\r
48                         ci.getters = new Method[ c ];\r
49                         ci.setters = new Method[ c ];\r
50                         ci.writable = new boolean[ c ];\r
51                         for (int i=0; i<ci.fields.length; i++)\r
52                         {\r
53                                 Field f = ci.fields[i];\r
54                                 \r
55                                 boolean isPublic = (f.getModifiers() & (Modifier.PUBLIC)) > 0;\r
56                                 boolean isFinal = (f.getModifiers() & (Modifier.FINAL)) > 0;\r
57                                 boolean isPrimitive = (f.getType().getName().length()=='1');\r
58                                 \r
59                                 ci.writable[i] = isPublic && (!isFinal || isPrimitive); \r
60                                 String name = f.getName();\r
61                                 try {\r
62                                         String getterName = "get"+name.substring(0, 1).toUpperCase()+name.substring(1, name.length());\r
63                                         Method getter = clazz.getMethod(getterName);\r
64                                         if (getter.getReturnType().equals(f.getType()))\r
65                                                 ci.getters[i] = getter;\r
66                                 } catch (NoSuchMethodException e) {\r
67                                 }\r
68                                 \r
69                                 try {\r
70                                         String setterName = "set"+name.substring(0, 1).toUpperCase()+name.substring(1, name.length());\r
71                                         Method setter = clazz.getMethod(setterName, f.getType());\r
72                                         if (setter.getReturnType().equals(void.class)) {\r
73                                                 ci.setters[i] = setter;\r
74                                                 ci.writable[i] = true;\r
75                                         }\r
76                                         \r
77                                 } catch (NoSuchMethodException e) {                                     \r
78                                 }\r
79                                 \r
80                         }\r
81                         \r
82                         // Prepare constuctor for case 2)\r
83                         if (!isAbstract) {\r
84                                 Class<?>[] constructorArgs = new Class<?>[ci.fields.length];\r
85                                 for (int i=0; i<ci.fields.length; i++) {\r
86                                         constructorArgs[i] = ci.fields[i].getType();\r
87                                 }\r
88                                 \r
89                                 try {\r
90                                         ci.argsConstructor = clazz.getDeclaredConstructor(constructorArgs);\r
91                                         ci.argsConstructor.setAccessible(true);\r
92                                 } catch (NoSuchMethodException e) {}\r
93         \r
94                                 try {\r
95                                         ci.noArgsConstructor = clazz.getDeclaredConstructor();\r
96                                         ci.noArgsConstructor.setAccessible(true);                               \r
97                                 } catch (NoSuchMethodException e) {}\r
98         \r
99                                 \r
100                                 try {\r
101                                         ci.beanConstructor = clazz.getDeclaredConstructor(org.simantics.databoard.binding.Binding.class);\r
102                                         ci.beanConstructor.setAccessible(true);\r
103                                 } catch (NoSuchMethodException e) {}\r
104                         }\r
105                                                 \r
106                         boolean allWritable = true;\r
107                         for (boolean b : ci.writable) allWritable &= b;\r
108                         \r
109                         ci.partialConstructionPossible = allWritable;\r
110                         \r
111                         return ci;\r
112                 } catch (SecurityException e1) {\r
113                         throw new BindingConstructionException(e1);\r
114                 }\r
115                 \r
116         }\r
117         \r
118         /**\r
119          * Get all, including inherited, public, protected and default \r
120          * non-transient, non-static, non-final fields. All returned fields have access.\r
121          * \r
122          * @param clazz\r
123          * @return\r
124          */\r
125         static Field[] getFields(Class<?> clazz)\r
126         {\r
127                 // TODO Sort as order is not guaranteed\r
128                 // Sort priority 1-class, 2-modifiers, 3-name, 4-signature\r
129                 Field[] fields = getAllFields(clazz);\r
130                 \r
131                 ArrayList<Field> result = new ArrayList<Field>(fields.length);\r
132                 for (Field f : fields) {\r
133                         if (Modifier.isStatic(f.getModifiers())) continue;\r
134 //                      if (Modifier.isFinal(f.getModifiers())) continue;\r
135             if (Modifier.isTransient(f.getModifiers())) continue;           \r
136             if (Modifier.isVolatile(f.getModifiers())) continue;           \r
137                         f.setAccessible(true);\r
138                         result.add(f);\r
139                 }\r
140                 return result.toArray( new Field[result.size()] );\r
141         }\r
142         \r
143         // Get all fields except fields of Throwable\r
144         static Field[] getAllFields(Class<?> clazz)\r
145         {\r
146                 LinkedList<Class<?>> classes = new LinkedList<Class<?>>();\r
147                 while (clazz!=null) {\r
148                         classes.addFirst(clazz);\r
149                         clazz = clazz.getSuperclass();\r
150                         if (clazz==Throwable.class) clazz=null;\r
151                 }\r
152                 \r
153                 ArrayList<Field> result = new ArrayList<Field>();\r
154                 for (Class<?> _class : classes) {\r
155                         _getAllFields(_class, result);\r
156                 }\r
157                 \r
158                 return result.toArray(new Field[result.size()]);\r
159         }\r
160         \r
161         public static void _getAllFields(Class<?> clazz, Collection<Field> result)\r
162         {\r
163                 for (Field m : clazz.getDeclaredFields())\r
164                         result.add(m);\r
165         }           \r
166 \r
167         @Override\r
168         public boolean equals(Object arg0) {\r
169                 return this == arg0 || (arg0.getClass().equals(this.getClass()) && ((ClassInfo)arg0).clazz.equals(clazz));\r
170         }\r
171 \r
172         @Override\r
173         public int hashCode() {\r
174                 return clazz.hashCode();\r
175         };\r
176 }\r