diff options
Diffstat (limited to 'src/main/java/org/gnunet/construct/ReflectUtil.java')
-rw-r--r-- | src/main/java/org/gnunet/construct/ReflectUtil.java | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/src/main/java/org/gnunet/construct/ReflectUtil.java b/src/main/java/org/gnunet/construct/ReflectUtil.java new file mode 100644 index 0000000..1115641 --- /dev/null +++ b/src/main/java/org/gnunet/construct/ReflectUtil.java | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2011, 2012 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | package org.gnunet.construct; | ||
22 | |||
23 | |||
24 | import java.lang.Integer; | ||
25 | import java.lang.reflect.Array; | ||
26 | import java.lang.reflect.Field; | ||
27 | import java.lang.reflect.InvocationTargetException; | ||
28 | import java.math.BigInteger; | ||
29 | import java.util.ArrayList; | ||
30 | import java.util.List; | ||
31 | |||
32 | /** | ||
33 | * Utilities for convenient use of the java reflection API. | ||
34 | * All methods only throw non-checked exceptions. | ||
35 | */ | ||
36 | public class ReflectUtil { | ||
37 | public static <T> T justInstantiate(Class<T> c) { | ||
38 | try { | ||
39 | return c.getConstructor().newInstance(); | ||
40 | } catch (InstantiationException e) { | ||
41 | throw new AssertionError("Cannot instantiate " + c); | ||
42 | } catch (IllegalAccessException e) { | ||
43 | throw new AssertionError( | ||
44 | String.format("Cannot instantiate Message %s (illegal access)", c)); | ||
45 | } catch (NoSuchMethodException e) { | ||
46 | if (c.isMemberClass()) { | ||
47 | throw new AssertionError(String.format("Can not instantiate non-static member class %s", c)); | ||
48 | } else { | ||
49 | throw new AssertionError( | ||
50 | String.format("No suitable default constructor for class %s", c)); | ||
51 | } | ||
52 | } catch (InvocationTargetException e) { | ||
53 | throw new AssertionError( | ||
54 | String.format("Exception thrown while constructing object of class %s", c)); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | public static void justSetArray(Object arr, int i, long v) { | ||
59 | Class t = arr.getClass().getComponentType(); | ||
60 | if (t.equals(Long.TYPE)) { | ||
61 | Array.setLong(arr, i, v); | ||
62 | } else if (t.equals(Integer.TYPE)) { | ||
63 | Array.setInt(arr, i, (int) v); | ||
64 | } else if (t.equals(Short.TYPE)) { | ||
65 | Array.setShort(arr, i, (short) v); | ||
66 | } else if (t.equals(Byte.TYPE)) { | ||
67 | Array.setByte(arr, i, (byte) v); | ||
68 | } else if (t.equals(Character.TYPE)) { | ||
69 | Array.setChar(arr, i, (char) v); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | public static long justGetArrayLong(Object arr, int i) { | ||
74 | return Array.getLong(arr, i); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * An enumeration of all built-in type that can store integers. | ||
79 | */ | ||
80 | public enum NumFieldType { | ||
81 | BIGNUM, BYTE_PRIM, SHORT_PRIM, INT_PRIM, LONG_PRIM, CHAR_PRIM | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * Convenience wrapper for a field that stores a numeric value. | ||
86 | */ | ||
87 | public static class NumField { | ||
88 | final private Field targetField; | ||
89 | final private NumFieldType targetType; | ||
90 | |||
91 | |||
92 | public NumFieldType getNumFieldType() { | ||
93 | return targetType; | ||
94 | } | ||
95 | |||
96 | public NumField(Field f) { | ||
97 | this.targetField = f; | ||
98 | if (f.getType().equals(Long.TYPE)) { | ||
99 | targetType = NumFieldType.LONG_PRIM; | ||
100 | } else if (f.getType().equals(Integer.TYPE)) { | ||
101 | targetType = NumFieldType.INT_PRIM; | ||
102 | } else if (f.getType().equals(Short.TYPE)) { | ||
103 | targetType = NumFieldType.SHORT_PRIM; | ||
104 | } else if (f.getType().equals(Byte.TYPE)) { | ||
105 | targetType = NumFieldType.BYTE_PRIM; | ||
106 | } else if (f.getType().equals(Character.TYPE)) { | ||
107 | targetType = NumFieldType.CHAR_PRIM; | ||
108 | } else if (f.getType().equals(BigInteger.class)) { | ||
109 | targetType = NumFieldType.BIGNUM; | ||
110 | } else { | ||
111 | throw new AssertionError( | ||
112 | "expected numeric type, got: " + f.getType()); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | public void set(Object obj, long val) { | ||
117 | try { | ||
118 | switch (targetType) { | ||
119 | case LONG_PRIM: | ||
120 | targetField.setLong(obj, val); | ||
121 | break; | ||
122 | case INT_PRIM: | ||
123 | targetField.setInt(obj, (int) val); | ||
124 | break; | ||
125 | case SHORT_PRIM: | ||
126 | targetField.setShort(obj, (short) val); | ||
127 | break; | ||
128 | case BYTE_PRIM: | ||
129 | targetField.setByte(obj, (byte) val); | ||
130 | break; | ||
131 | case CHAR_PRIM: | ||
132 | targetField.setChar(obj, (char) val); | ||
133 | break; | ||
134 | case BIGNUM: | ||
135 | targetField.set(obj, BigInteger.valueOf(val)); | ||
136 | break; | ||
137 | } | ||
138 | } catch (IllegalArgumentException e) { | ||
139 | throw new AssertionError("cannot access field"); | ||
140 | } catch (IllegalAccessException e) { | ||
141 | throw new AssertionError("cannot access field"); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | public void set(Object obj, BigInteger val) { | ||
146 | try { | ||
147 | targetField.set(obj, val); | ||
148 | } catch (IllegalAccessException e) { | ||
149 | throw new AssertionError("cannot access field"); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | public long get(Object obj) { | ||
154 | try { | ||
155 | switch (targetType) { | ||
156 | case LONG_PRIM: | ||
157 | return targetField.getLong(obj); | ||
158 | case INT_PRIM: | ||
159 | return targetField.getInt(obj); | ||
160 | case SHORT_PRIM: | ||
161 | return targetField.getShort(obj); | ||
162 | case BYTE_PRIM: | ||
163 | return targetField.getByte(obj); | ||
164 | case CHAR_PRIM: | ||
165 | return targetField.getChar(obj); | ||
166 | case BIGNUM: | ||
167 | throw new RuntimeException("get() called on NumField that is a BigInteger"); | ||
168 | default: | ||
169 | throw new AssertionError("unreachable"); | ||
170 | } | ||
171 | } catch (IllegalAccessException e) { | ||
172 | throw new AssertionError("cannot access field"); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | public BigInteger getBig(Object obj) { | ||
177 | if (isBig()) { | ||
178 | return (BigInteger) justGet(obj, targetField); | ||
179 | } else { | ||
180 | return BigInteger.valueOf(this.get(obj)); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | public boolean isBig() { | ||
185 | return targetType.equals(NumFieldType.BIGNUM); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | |||
190 | public static Object followFieldPath(List<Field> fl, Object obj, | ||
191 | int depth) { | ||
192 | for (int i = 0; i < depth; ++i) { | ||
193 | try { | ||
194 | obj = fl.get(i).get(obj); | ||
195 | } catch (IllegalArgumentException e) { | ||
196 | throw new RuntimeException(e); | ||
197 | } catch (IllegalAccessException e) { | ||
198 | throw new AssertionError("cannot access field " + fl.get(i) | ||
199 | + " of " + obj.getClass()); | ||
200 | } | ||
201 | } | ||
202 | return obj; | ||
203 | } | ||
204 | |||
205 | public static Object followFieldPath(List<Field> fl, Object obj) { | ||
206 | return followFieldPath(fl, obj, fl.size()); | ||
207 | } | ||
208 | |||
209 | public static Object followFieldPathToParent(List<Field> fl, Object obj) { | ||
210 | return followFieldPath(fl, obj, fl.size() - 1); | ||
211 | } | ||
212 | |||
213 | public static Object justGet(Object obj, Field f) { | ||
214 | try { | ||
215 | return f.get(obj); | ||
216 | } catch (IllegalAccessException e) { | ||
217 | throw new AssertionError( | ||
218 | String.format("Cannot access private field '%s' in class %s", f, obj.getClass())); | ||
219 | } catch (IllegalArgumentException e) { | ||
220 | throw new AssertionError("Cannot access field '" + f.getName() + "' in class " + obj.getClass()); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | public static void justSet(Object obj, Field f, Object val) { | ||
225 | try { | ||
226 | f.set(obj, val); | ||
227 | } catch (IllegalAccessException e) { | ||
228 | throw new AssertionError( | ||
229 | String.format("Cannot access private field %s in class %s", f, obj.getClass())); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | |||
234 | public static int justGetInt(Object obj, List<Field> path) { | ||
235 | for (int i = 0; i < path.size() - 1; ++i) { | ||
236 | try { | ||
237 | obj = path.get(i).get(obj); | ||
238 | } catch (IllegalArgumentException e) { | ||
239 | throw new RuntimeException(e); | ||
240 | } catch (IllegalAccessException e) { | ||
241 | throw new AssertionError("cannot access field " + path.get(i) | ||
242 | + " of " + obj.getClass()); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | try { | ||
247 | return path.get(path.size() - 1).getInt(obj); | ||
248 | } catch (IllegalAccessException e) { | ||
249 | throw new AssertionError("cannot access field " + path.get(path.size() - 1) | ||
250 | + " of " + obj.getClass()); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | public static void justSetInt(Object obj, List<Field> path, int val) { | ||
255 | for (int i = 0; i < path.size() - 1; ++i) { | ||
256 | try { | ||
257 | obj = path.get(i).get(obj); | ||
258 | |||
259 | } catch (IllegalArgumentException e) { | ||
260 | throw new RuntimeException(e); | ||
261 | } catch (IllegalAccessException e) { | ||
262 | throw new AssertionError("cannot access field " + path.get(i) | ||
263 | + " of " + obj.getClass()); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | try { | ||
268 | path.get(path.size() - 1).setInt(obj, val); | ||
269 | } catch (IllegalAccessException e) { | ||
270 | throw new AssertionError("cannot access field " + path.get(path.size() - 1) | ||
271 | + " of " + obj.getClass()); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | |||
276 | public static List<Field> getFieldPathFromString(final String p, final Class root) { | ||
277 | Class current = root; | ||
278 | |||
279 | String[] components = p.split("[.]"); | ||
280 | |||
281 | List<Field> fp = new ArrayList<Field>(components.length); | ||
282 | for (String member : components) { | ||
283 | Field f; | ||
284 | try { | ||
285 | f = current.getField(member); | ||
286 | } catch (NoSuchFieldException e) { | ||
287 | throw new AssertionError("invalid field path, component " + member + " not found"); | ||
288 | } | ||
289 | |||
290 | fp.add(f); | ||
291 | |||
292 | current = f.getType(); | ||
293 | } | ||
294 | |||
295 | return fp; | ||
296 | } | ||
297 | } | ||