aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/gnunet/construct/ReflectUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/gnunet/construct/ReflectUtil.java')
-rw-r--r--src/main/java/org/gnunet/construct/ReflectUtil.java297
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
21package org.gnunet.construct;
22
23
24import java.lang.Integer;
25import java.lang.reflect.Array;
26import java.lang.reflect.Field;
27import java.lang.reflect.InvocationTargetException;
28import java.math.BigInteger;
29import java.util.ArrayList;
30import java.util.List;
31
32/**
33 * Utilities for convenient use of the java reflection API.
34 * All methods only throw non-checked exceptions.
35 */
36public 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}