1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.databoard.binding.reflection;
\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
22 import org.simantics.databoard.binding.error.BindingConstructionException;
\r
24 public class ClassInfo {
\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
33 public static ClassInfo getInfo(Class<?> clazz)
\r
34 throws BindingConstructionException
\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
40 ClassInfo ci = new ClassInfo();
\r
43 ci.fields = getFields(clazz);
\r
44 for (Field f : ci.fields)
\r
45 f.setAccessible(true);
\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
53 Field f = ci.fields[i];
\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
59 ci.writable[i] = isPublic && (!isFinal || isPrimitive);
\r
60 String name = f.getName();
\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
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
77 } catch (NoSuchMethodException e) {
\r
82 // Prepare constuctor for case 2)
\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
90 ci.argsConstructor = clazz.getDeclaredConstructor(constructorArgs);
\r
91 ci.argsConstructor.setAccessible(true);
\r
92 } catch (NoSuchMethodException e) {}
\r
95 ci.noArgsConstructor = clazz.getDeclaredConstructor();
\r
96 ci.noArgsConstructor.setAccessible(true);
\r
97 } catch (NoSuchMethodException e) {}
\r
101 ci.beanConstructor = clazz.getDeclaredConstructor(org.simantics.databoard.binding.Binding.class);
\r
102 ci.beanConstructor.setAccessible(true);
\r
103 } catch (NoSuchMethodException e) {}
\r
106 boolean allWritable = true;
\r
107 for (boolean b : ci.writable) allWritable &= b;
\r
109 ci.partialConstructionPossible = allWritable;
\r
112 } catch (SecurityException e1) {
\r
113 throw new BindingConstructionException(e1);
\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
125 static Field[] getFields(Class<?> clazz)
\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
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
140 return result.toArray( new Field[result.size()] );
\r
143 // Get all fields except fields of Throwable
\r
144 static Field[] getAllFields(Class<?> clazz)
\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
153 ArrayList<Field> result = new ArrayList<Field>();
\r
154 for (Class<?> _class : classes) {
\r
155 _getAllFields(_class, result);
\r
158 return result.toArray(new Field[result.size()]);
\r
161 public static void _getAllFields(Class<?> clazz, Collection<Field> result)
\r
163 for (Field m : clazz.getDeclaredFields())
\r
168 public boolean equals(Object arg0) {
\r
169 return this == arg0 || (arg0.getClass().equals(this.getClass()) && ((ClassInfo)arg0).clazz.equals(clazz));
\r
173 public int hashCode() {
\r
174 return clazz.hashCode();
\r