]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/ClassInfo.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/ClassInfo.java
new file mode 100644 (file)
index 0000000..7dff4ea
--- /dev/null
@@ -0,0 +1,176 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.databoard.binding.reflection;\r
+\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.Method;\r
+import java.lang.reflect.Modifier;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.LinkedList;\r
+\r
+import org.simantics.databoard.binding.error.BindingConstructionException;\r
+\r
+public class ClassInfo {\r
+\r
+       public Constructor<?> argsConstructor, noArgsConstructor, beanConstructor;\r
+       public Class<?> clazz;\r
+       public Field[] fields;\r
+       public Method[] getters, setters;\r
+       public boolean[] writable;\r
+       public boolean partialConstructionPossible; // set to true, if partial construction is possible\r
+       \r
+       public static ClassInfo getInfo(Class<?> clazz)\r
+       throws BindingConstructionException\r
+       {\r
+               boolean isAbstract = (clazz.getModifiers() & Modifier.ABSTRACT) != 0; \r
+//             if ( isAbstract )\r
+//                     throw new BindingConstructionException("Cannot create reflection binding to abstract class "+clazz);\r
+               \r
+               ClassInfo ci = new ClassInfo();\r
+               ci.clazz = clazz;\r
+               try {\r
+                       ci.fields = getFields(clazz);\r
+                       for (Field f : ci.fields)\r
+                               f.setAccessible(true);\r
+\r
+                       int c = ci.fields.length;\r
+                       ci.getters = new Method[ c ];\r
+                       ci.setters = new Method[ c ];\r
+                       ci.writable = new boolean[ c ];\r
+                       for (int i=0; i<ci.fields.length; i++)\r
+                       {\r
+                               Field f = ci.fields[i];\r
+                               \r
+                               boolean isPublic = (f.getModifiers() & (Modifier.PUBLIC)) > 0;\r
+                               boolean isFinal = (f.getModifiers() & (Modifier.FINAL)) > 0;\r
+                               boolean isPrimitive = (f.getType().getName().length()=='1');\r
+                               \r
+                               ci.writable[i] = isPublic && (!isFinal || isPrimitive); \r
+                               String name = f.getName();\r
+                               try {\r
+                                       String getterName = "get"+name.substring(0, 1).toUpperCase()+name.substring(1, name.length());\r
+                                       Method getter = clazz.getMethod(getterName);\r
+                                       if (getter.getReturnType().equals(f.getType()))\r
+                                               ci.getters[i] = getter;\r
+                               } catch (NoSuchMethodException e) {\r
+                               }\r
+                               \r
+                               try {\r
+                                       String setterName = "set"+name.substring(0, 1).toUpperCase()+name.substring(1, name.length());\r
+                                       Method setter = clazz.getMethod(setterName, f.getType());\r
+                                       if (setter.getReturnType().equals(void.class)) {\r
+                                               ci.setters[i] = setter;\r
+                                               ci.writable[i] = true;\r
+                                       }\r
+                                       \r
+                               } catch (NoSuchMethodException e) {                                     \r
+                               }\r
+                               \r
+                       }\r
+                       \r
+                       // Prepare constuctor for case 2)\r
+                       if (!isAbstract) {\r
+                               Class<?>[] constructorArgs = new Class<?>[ci.fields.length];\r
+                               for (int i=0; i<ci.fields.length; i++) {\r
+                                       constructorArgs[i] = ci.fields[i].getType();\r
+                               }\r
+                               \r
+                               try {\r
+                                       ci.argsConstructor = clazz.getDeclaredConstructor(constructorArgs);\r
+                                       ci.argsConstructor.setAccessible(true);\r
+                               } catch (NoSuchMethodException e) {}\r
+       \r
+                               try {\r
+                                       ci.noArgsConstructor = clazz.getDeclaredConstructor();\r
+                                       ci.noArgsConstructor.setAccessible(true);                               \r
+                               } catch (NoSuchMethodException e) {}\r
+       \r
+                               \r
+                               try {\r
+                                       ci.beanConstructor = clazz.getDeclaredConstructor(org.simantics.databoard.binding.Binding.class);\r
+                                       ci.beanConstructor.setAccessible(true);\r
+                               } catch (NoSuchMethodException e) {}\r
+                       }\r
+                                               \r
+                       boolean allWritable = true;\r
+                       for (boolean b : ci.writable) allWritable &= b;\r
+                       \r
+                       ci.partialConstructionPossible = allWritable;\r
+                       \r
+                       return ci;\r
+               } catch (SecurityException e1) {\r
+                       throw new BindingConstructionException(e1);\r
+               }\r
+               \r
+       }\r
+       \r
+       /**\r
+        * Get all, including inherited, public, protected and default \r
+        * non-transient, non-static, non-final fields. All returned fields have access.\r
+        * \r
+        * @param clazz\r
+        * @return\r
+        */\r
+       static Field[] getFields(Class<?> clazz)\r
+       {\r
+               // TODO Sort as order is not guaranteed\r
+               // Sort priority 1-class, 2-modifiers, 3-name, 4-signature\r
+               Field[] fields = getAllFields(clazz);\r
+               \r
+               ArrayList<Field> result = new ArrayList<Field>(fields.length);\r
+               for (Field f : fields) {\r
+                       if (Modifier.isStatic(f.getModifiers())) continue;\r
+//                     if (Modifier.isFinal(f.getModifiers())) continue;\r
+            if (Modifier.isTransient(f.getModifiers())) continue;           \r
+            if (Modifier.isVolatile(f.getModifiers())) continue;           \r
+                       f.setAccessible(true);\r
+                       result.add(f);\r
+               }\r
+               return result.toArray( new Field[result.size()] );\r
+       }\r
+       \r
+       // Get all fields except fields of Throwable\r
+       static Field[] getAllFields(Class<?> clazz)\r
+       {\r
+               LinkedList<Class<?>> classes = new LinkedList<Class<?>>();\r
+               while (clazz!=null) {\r
+                       classes.addFirst(clazz);\r
+                       clazz = clazz.getSuperclass();\r
+                       if (clazz==Throwable.class) clazz=null;\r
+               }\r
+               \r
+               ArrayList<Field> result = new ArrayList<Field>();\r
+               for (Class<?> _class : classes) {\r
+                       _getAllFields(_class, result);\r
+               }\r
+               \r
+               return result.toArray(new Field[result.size()]);\r
+       }\r
+       \r
+       public static void _getAllFields(Class<?> clazz, Collection<Field> result)\r
+       {\r
+               for (Field m : clazz.getDeclaredFields())\r
+                       result.add(m);\r
+       }           \r
+\r
+       @Override\r
+       public boolean equals(Object arg0) {\r
+               return this == arg0 || (arg0.getClass().equals(this.getClass()) && ((ClassInfo)arg0).clazz.equals(clazz));\r
+       }\r
+\r
+       @Override\r
+       public int hashCode() {\r
+               return clazz.hashCode();\r
+       };\r
+}\r