~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/ikvm/internal/AnnotationAttributeBase.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (C) 2005-2011 Jeroen Frijters
 
3
 
 
4
  This software is provided 'as-is', without any express or implied
 
5
  warranty.  In no event will the authors be held liable for any damages
 
6
  arising from the use of this software.
 
7
 
 
8
  Permission is granted to anyone to use this software for any purpose,
 
9
  including commercial applications, and to alter it and redistribute it
 
10
  freely, subject to the following restrictions:
 
11
 
 
12
  1. The origin of this software must not be misrepresented; you must not
 
13
     claim that you wrote the original software. If you use this software
 
14
     in a product, an acknowledgment in the product documentation would be
 
15
     appreciated but is not required.
 
16
  2. Altered source versions must be plainly marked as such, and must not be
 
17
     misrepresented as being the original software.
 
18
  3. This notice may not be removed or altered from any source distribution.
 
19
 
 
20
  Jeroen Frijters
 
21
  jeroen@frijters.net
 
22
  
 
23
*/
 
24
package ikvm.internal;
 
25
 
 
26
import cli.System.Reflection.BindingFlags;
 
27
import ikvm.lang.CIL;
 
28
import java.io.Serializable;
 
29
import java.lang.annotation.Annotation;
 
30
import java.lang.reflect.Array;
 
31
import java.lang.reflect.InvocationHandler;
 
32
import java.lang.reflect.InvocationTargetException;
 
33
import java.lang.reflect.Method;
 
34
import java.lang.reflect.Proxy;
 
35
import java.util.Arrays;
 
36
import java.util.Iterator;
 
37
import java.util.Map;
 
38
import java.util.HashMap;
 
39
 
 
40
public abstract class AnnotationAttributeBase
 
41
    extends cli.System.Attribute
 
42
    implements Annotation, Serializable
 
43
{
 
44
    private final HashMap values = new HashMap();
 
45
    private final Class annotationType;
 
46
    private boolean frozen;
 
47
 
 
48
    protected AnnotationAttributeBase(Class annotationType)
 
49
    {
 
50
        this.annotationType = annotationType;
 
51
    }
 
52
 
 
53
    protected final Object getValue(String name)
 
54
    {
 
55
        freeze();
 
56
        return values.get(name);
 
57
    }
 
58
 
 
59
    protected final byte getByteValue(String name)
 
60
    {
 
61
        freeze();
 
62
        return ((Byte)values.get(name)).byteValue();
 
63
    }
 
64
 
 
65
    protected final boolean getBooleanValue(String name)
 
66
    {
 
67
        freeze();
 
68
        return ((Boolean)values.get(name)).booleanValue();
 
69
    }
 
70
 
 
71
    protected final short getShortValue(String name)
 
72
    {
 
73
        freeze();
 
74
        return ((Short)values.get(name)).shortValue();
 
75
    }
 
76
 
 
77
    protected final char getCharValue(String name)
 
78
    {
 
79
        freeze();
 
80
        return ((Character)values.get(name)).charValue();
 
81
    }
 
82
 
 
83
    protected final int getIntValue(String name)
 
84
    {
 
85
        freeze();
 
86
        return ((Integer)values.get(name)).intValue();
 
87
    }
 
88
 
 
89
    protected final float getFloatValue(String name)
 
90
    {
 
91
        freeze();
 
92
        return ((Float)values.get(name)).floatValue();
 
93
    }
 
94
 
 
95
    protected final long getLongValue(String name)
 
96
    {
 
97
        freeze();
 
98
        return ((Long)values.get(name)).longValue();
 
99
    }
 
100
 
 
101
    protected final double getDoubleValue(String name)
 
102
    {
 
103
        freeze();
 
104
        return ((Double)values.get(name)).doubleValue();
 
105
    }
 
106
 
 
107
    protected final synchronized void setValue(String name, Object value)
 
108
    {
 
109
        if(frozen)
 
110
        {
 
111
            throw new IllegalStateException("Annotation properties have already been defined");
 
112
        }
 
113
        try
 
114
        {
 
115
            Class type = annotationType.getMethod(name).getReturnType();
 
116
            if(type.isEnum())
 
117
            {
 
118
                value = type.getMethod("valueOf", String.class).invoke(null, value.toString());
 
119
            }
 
120
            else if(type == Class.class)
 
121
            {
 
122
                value = ikvm.runtime.Util.getFriendlyClassFromType((cli.System.Type)value);
 
123
            }
 
124
            else if(type == boolean.class)
 
125
            {
 
126
                value = ikvm.lang.CIL.unbox_boolean(value);
 
127
            }
 
128
            else if(type == byte.class)
 
129
            {
 
130
                value = ikvm.lang.CIL.unbox_byte(value);
 
131
            }
 
132
            else if(type == short.class)
 
133
            {
 
134
                value = ikvm.lang.CIL.unbox_short(value);
 
135
            }
 
136
            else if(type == char.class)
 
137
            {
 
138
                value = ikvm.lang.CIL.unbox_char(value);
 
139
            }
 
140
            else if(type == int.class)
 
141
            {
 
142
                value = ikvm.lang.CIL.unbox_int(value);
 
143
            }
 
144
            else if(type == long.class)
 
145
            {
 
146
                value = ikvm.lang.CIL.unbox_long(value);
 
147
            }
 
148
            else if(type == float.class)
 
149
            {
 
150
                value = ikvm.lang.CIL.unbox_float(value);
 
151
            }
 
152
            else if(type == double.class)
 
153
            {
 
154
                value = ikvm.lang.CIL.unbox_double(value);
 
155
            }
 
156
            else if(type == String.class)
 
157
            {
 
158
                // no conversion needed
 
159
            }
 
160
            else if(type.isArray())
 
161
            {
 
162
                type = type.getComponentType();
 
163
                if(type.isEnum())
 
164
                {
 
165
                    Method valueOf = type.getMethod("valueOf", String.class);
 
166
                    cli.System.Array orgarray = (cli.System.Array)value;
 
167
                    Object[] array = (Object[])Array.newInstance(type, orgarray.get_Length());
 
168
                    for(int i = 0; i < array.length; i++)
 
169
                    {
 
170
                        array[i] = valueOf.invoke(null, orgarray.GetValue(i).toString());
 
171
                    }
 
172
                    value = array;
 
173
                }
 
174
                else if(type == Class.class)
 
175
                {
 
176
                    cli.System.Type[] orgarray = (cli.System.Type[])value;
 
177
                    Class[] array = new Class[orgarray.length];
 
178
                    for(int i = 0; i < array.length; i++)
 
179
                    {
 
180
                        array[i] = ikvm.runtime.Util.getFriendlyClassFromType(orgarray[i]);
 
181
                    }
 
182
                    value = array;
 
183
                }
 
184
                else
 
185
                {
 
186
                    // no conversion needed
 
187
                }
 
188
            }
 
189
            else
 
190
            {
 
191
                throw new InternalError("Invalid annotation type: " + type);
 
192
            }
 
193
            values.put(name, value);
 
194
        }
 
195
        catch (NoSuchMethodException x)
 
196
        {
 
197
            throw (NoSuchMethodError)new NoSuchMethodError().initCause(x);
 
198
        }
 
199
        catch (IllegalAccessException x)
 
200
        {
 
201
            throw (IllegalAccessError)new IllegalAccessError().initCause(x);
 
202
        }
 
203
        catch (InvocationTargetException x)
 
204
        {
 
205
            throw (InternalError)new InternalError().initCause(x);
 
206
        }
 
207
    }
 
208
 
 
209
    protected final synchronized void setDefinition(Object[] array)
 
210
    {
 
211
        if(frozen)
 
212
        {
 
213
            throw new IllegalStateException("Annotation properties have already been defined");
 
214
        }
 
215
        frozen = true;
 
216
        // TODO consider checking that the type matches
 
217
        // (or better yet (?), remove the first two redundant elements from the array)
 
218
        decodeValues(values, annotationType, annotationType.getClassLoader(), array);
 
219
    }
 
220
 
 
221
    @ikvm.lang.Internal
 
222
    public Map getValues()
 
223
    {
 
224
        return values;
 
225
    }
 
226
 
 
227
    @ikvm.lang.Internal
 
228
    public synchronized void freeze()
 
229
    {
 
230
        if(!frozen)
 
231
        {
 
232
            frozen = true;
 
233
            setDefaults(values, annotationType);
 
234
        }
 
235
    }
 
236
 
 
237
    private static void decodeValues(HashMap map, Class annotationClass, ClassLoader loader, Object[] array)
 
238
    {
 
239
        for (int i = 2; i < array.length; i += 2)
 
240
        {
 
241
            String name = (String)array[i];
 
242
            try
 
243
            {
 
244
                Method method = annotationClass.getDeclaredMethod(name, new Class[0]);
 
245
                map.put(name, decodeElementValue(array[i + 1], method.getReturnType(), loader));
 
246
            }
 
247
            catch (IllegalAccessException x)
 
248
            {
 
249
                // TODO this probably isn't the right exception
 
250
                throw new IncompatibleClassChangeError();
 
251
            }
 
252
            catch (NoSuchMethodException x)
 
253
            {
 
254
                // TODO this probably isn't the right exception
 
255
                throw new IncompatibleClassChangeError("Method " + name + " is missing in annotation " + annotationClass.getName());
 
256
            }
 
257
        }
 
258
        setDefaults(map, annotationClass);
 
259
    }
 
260
 
 
261
    private static void setDefaults(HashMap map, Class annotationClass)
 
262
    {
 
263
        for (Method m : annotationClass.getDeclaredMethods())
 
264
        {
 
265
            Object defaultValue = m.getDefaultValue();
 
266
            // TODO throw exception if default is missing for method that doesn't yet have a value
 
267
            if (defaultValue != null && !map.containsKey(m.getName()))
 
268
            {
 
269
                map.put(m.getName(), defaultValue);
 
270
            }
 
271
        }
 
272
    }
 
273
 
 
274
    private static Class classFromSig(ClassLoader loader, String name)
 
275
    {
 
276
        if (name.startsWith("L") && name.endsWith(";"))
 
277
        {
 
278
            name = name.substring(1, name.length() - 1).replace('/', '.');
 
279
        }
 
280
        else if (name.startsWith("["))
 
281
        {
 
282
            name = name.replace('/', '.');
 
283
        }
 
284
        else if (name.length() == 1)
 
285
        {
 
286
            switch (name.charAt(0))
 
287
            {
 
288
                case 'Z':
 
289
                    return Boolean.TYPE;
 
290
                case 'B':
 
291
                    return Byte.TYPE;
 
292
                case 'C':
 
293
                    return Character.TYPE;
 
294
                case 'S':
 
295
                    return Short.TYPE;
 
296
                case 'I':
 
297
                    return Integer.TYPE;
 
298
                case 'F':
 
299
                    return Float.TYPE;
 
300
                case 'J':
 
301
                    return Long.TYPE;
 
302
                case 'D':
 
303
                    return Double.TYPE;
 
304
                case 'V':
 
305
                    return Void.TYPE;
 
306
                default:
 
307
                    throw new TypeNotPresentException(name, null);
 
308
            }
 
309
        }
 
310
        try
 
311
        {
 
312
            return Class.forName(name, false, loader);
 
313
        }
 
314
        catch (ClassNotFoundException x)
 
315
        {
 
316
            throw new TypeNotPresentException(name, x);
 
317
        }
 
318
    }
 
319
 
 
320
    public static Object newAnnotation(ClassLoader loader, Object definition)
 
321
    {
 
322
        Object[] array = (Object[])definition;
 
323
        byte tag = CIL.unbox_byte(array[0]);
 
324
        if (tag != '@')
 
325
            throw new ClassCastException();
 
326
        Object classNameOrClass = array[1];
 
327
        Class annotationClass;
 
328
        if (classNameOrClass instanceof String)
 
329
        {
 
330
            annotationClass = classFromSig(loader, (String)classNameOrClass);
 
331
            array[1] = annotationClass;
 
332
        }
 
333
        else
 
334
        {
 
335
            annotationClass = (Class)classNameOrClass;
 
336
        }
 
337
        HashMap map = new HashMap();
 
338
        decodeValues(map, annotationClass, loader, array);
 
339
        return Proxy.newProxyInstance(annotationClass.getClassLoader(), new Class<?>[] { annotationClass }, newAnnotationInvocationHandler(annotationClass, map));
 
340
    }
 
341
 
 
342
    public static Object decodeElementValue(Object obj, Class type, ClassLoader loader)
 
343
        throws IllegalAccessException
 
344
    {
 
345
        if (obj instanceof Object[] && CIL.unbox_byte(((Object[])obj)[0]) == '?')
 
346
        {
 
347
            Throwable t;
 
348
            try
 
349
            {
 
350
                Object[] error = (Object[])obj;
 
351
                t = (Throwable)Class.forName((String)error[1]).getConstructor(String.class).newInstance(error[2]);
 
352
            }
 
353
            catch (Exception x)
 
354
            {
 
355
                t = x;
 
356
            }
 
357
            sun.misc.Unsafe.getUnsafe().throwException(t);
 
358
        }
 
359
        if (type == Byte.TYPE)
 
360
        {
 
361
            return new Byte(CIL.unbox_byte(obj));
 
362
        }
 
363
        else if (type == Boolean.TYPE)
 
364
        {
 
365
            return new Boolean(CIL.unbox_boolean(obj));
 
366
        }
 
367
        else if (type == Short.TYPE)
 
368
        {
 
369
            return new Short(CIL.unbox_short(obj));
 
370
        }
 
371
        else if (type == Character.TYPE)
 
372
        {
 
373
            return new Character(CIL.unbox_char(obj));
 
374
        }
 
375
        else if (type == Integer.TYPE)
 
376
        {
 
377
            return new Integer(CIL.unbox_int(obj));
 
378
        }
 
379
        else if (type == Float.TYPE)
 
380
        {
 
381
            return new Float(CIL.unbox_float(obj));
 
382
        }
 
383
        else if (type == Long.TYPE)
 
384
        {
 
385
            return new Long(CIL.unbox_long(obj));
 
386
        }
 
387
        else if (type == Double.TYPE)
 
388
        {
 
389
            return new Double(CIL.unbox_double(obj));
 
390
        }
 
391
        else if (type == String.class)
 
392
        {
 
393
            return (String)obj;
 
394
        }
 
395
        else if (type == Class.class)
 
396
        {
 
397
            Object[] array = (Object[])obj;
 
398
            byte tag = CIL.unbox_byte(array[0]);
 
399
            if (tag != 'c')
 
400
                throw new ClassCastException();
 
401
            return classFromSig(loader, (String)array[1]);
 
402
        }
 
403
        else if (type.isArray())
 
404
        {
 
405
            Object[] array = (Object[])obj;
 
406
            byte tag = CIL.unbox_byte(array[0]);
 
407
            if (tag != '[')
 
408
                throw new ClassCastException();
 
409
            type = type.getComponentType();
 
410
            Object dst = Array.newInstance(type, array.length - 1);
 
411
            for (int i = 0; i < array.length - 1; i++)
 
412
            {
 
413
                Array.set(dst, i, decodeElementValue(array[i + 1], type, loader));
 
414
            }
 
415
            return dst;
 
416
        }
 
417
        else if (type.isAnnotation())
 
418
        {
 
419
            return type.cast(newAnnotation(loader, obj));
 
420
        }
 
421
        else if (type.isEnum())
 
422
        {
 
423
            Object[] array = (Object[])obj;
 
424
            byte tag = CIL.unbox_byte(array[0]);
 
425
            if (tag != 'e')
 
426
                throw new ClassCastException();
 
427
            Class enumClass = classFromSig(loader, (String)array[1]);
 
428
            try
 
429
            {
 
430
                return Enum.valueOf(enumClass, (String)array[2]);
 
431
            }
 
432
            catch (IllegalArgumentException x)
 
433
            {
 
434
                throw new EnumConstantNotPresentException(enumClass, (String)array[2]);
 
435
            }
 
436
        }
 
437
        else
 
438
        {
 
439
            throw new ClassCastException();
 
440
        }
 
441
    }
 
442
 
 
443
    protected final Object writeReplace()
 
444
    {
 
445
        return Proxy.newProxyInstance(annotationType.getClassLoader(),
 
446
            new Class[] { annotationType },
 
447
            newAnnotationInvocationHandler(annotationType, values));
 
448
    }
 
449
 
 
450
    private static cli.System.Reflection.ConstructorInfo annotationInvocationHandlerConstructor;
 
451
 
 
452
    private static InvocationHandler newAnnotationInvocationHandler(Class type, Map memberValues)
 
453
    {
 
454
        if (annotationInvocationHandlerConstructor == null)
 
455
        {
 
456
            cli.System.Type typeofClass = cli.System.Type.GetType("java.lang.Class");
 
457
            cli.System.Type typeofMap = cli.System.Type.GetType("java.util.Map");
 
458
            annotationInvocationHandlerConstructor = cli.System.Type.GetType("sun.reflect.annotation.AnnotationInvocationHandler")
 
459
                .GetConstructor(BindingFlags.wrap(BindingFlags.Instance | BindingFlags.NonPublic), null, new cli.System.Type[] { typeofClass, typeofMap }, null);
 
460
        }
 
461
        return (InvocationHandler)annotationInvocationHandlerConstructor.Invoke(new Object[] { type, memberValues });
 
462
    }
 
463
 
 
464
    public final Class<? extends Annotation> annotationType()
 
465
    {
 
466
        return annotationType;
 
467
    }
 
468
 
 
469
    public final boolean Equals(Object o)
 
470
    {
 
471
        return equals(annotationType, values, o);
 
472
    }
 
473
 
 
474
    public final int GetHashCode()
 
475
    {
 
476
        return hashCode(annotationType, values);
 
477
    }
 
478
 
 
479
    public final String ToString()
 
480
    {
 
481
        return toString(annotationType, values);
 
482
    }
 
483
 
 
484
    private static boolean equals(Class type, Map memberValues, Object other)
 
485
    {
 
486
        if (type.isInstance(other))
 
487
        {
 
488
            try
 
489
            {
 
490
                Method[] methods = type.getDeclaredMethods();
 
491
                if (methods.length == memberValues.size())
 
492
                {
 
493
                    for (int i = 0; i < methods.length; i++)
 
494
                    {
 
495
                        String key = methods[i].getName();
 
496
                        Object val = methods[i].invoke(other, new Object[0]);
 
497
                        if (! deepEquals(memberValues.get(key), val))
 
498
                        {
 
499
                            return false;
 
500
                        }
 
501
                    }
 
502
                    return true;
 
503
                }
 
504
            }
 
505
            catch (IllegalAccessException _)
 
506
            {
 
507
                // Ignore exception, like the JDK
 
508
            }
 
509
            catch (InvocationTargetException _)
 
510
            {
 
511
                // Ignore exception, like the JDK
 
512
            }
 
513
        }
 
514
        return false;
 
515
    }
 
516
 
 
517
    private static boolean deepEquals(Object o1, Object o2)
 
518
    {
 
519
        if (o1 == o2)
 
520
            return true;
 
521
 
 
522
        if (o1 == null || o2 == null)
 
523
            return false;
 
524
 
 
525
        if (o1 instanceof boolean[] && o2 instanceof boolean[])
 
526
            return Arrays.equals((boolean[]) o1, (boolean[]) o2);
 
527
 
 
528
        if (o1 instanceof byte[] && o2 instanceof byte[])
 
529
            return Arrays.equals((byte[]) o1, (byte[]) o2);
 
530
 
 
531
        if (o1 instanceof char[] && o2 instanceof char[])
 
532
            return Arrays.equals((char[]) o1, (char[]) o2);
 
533
 
 
534
        if (o1 instanceof short[] && o2 instanceof short[])
 
535
            return Arrays.equals((short[]) o1, (short[]) o2);
 
536
 
 
537
        if (o1 instanceof int[] && o2 instanceof int[])
 
538
            return Arrays.equals((int[]) o1, (int[]) o2);
 
539
 
 
540
        if (o1 instanceof float[] && o2 instanceof float[])
 
541
            return Arrays.equals((float[]) o1, (float[]) o2);
 
542
 
 
543
        if (o1 instanceof long[] && o2 instanceof long[])
 
544
            return Arrays.equals((long[]) o1, (long[]) o2);
 
545
 
 
546
        if (o1 instanceof double[] && o2 instanceof double[])
 
547
            return Arrays.equals((double[]) o1, (double[]) o2);
 
548
 
 
549
        if (o1 instanceof Object[] && o2 instanceof Object[])
 
550
            return Arrays.equals((Object[]) o1, (Object[]) o2);
 
551
 
 
552
        return o1.equals(o2);
 
553
    }
 
554
 
 
555
    private static int deepHashCode(Object obj)
 
556
    {
 
557
        if (obj instanceof boolean[])
 
558
            return Arrays.hashCode((boolean[]) obj);
 
559
 
 
560
        if (obj instanceof byte[])
 
561
            return Arrays.hashCode((byte[]) obj);
 
562
 
 
563
        if (obj instanceof char[])
 
564
            return Arrays.hashCode((char[]) obj);
 
565
 
 
566
        if (obj instanceof short[])
 
567
            return Arrays.hashCode((short[]) obj);
 
568
 
 
569
        if (obj instanceof int[])
 
570
            return Arrays.hashCode((int[]) obj);
 
571
 
 
572
        if (obj instanceof float[])
 
573
            return Arrays.hashCode((float[]) obj);
 
574
 
 
575
        if (obj instanceof long[])
 
576
            return Arrays.hashCode((long[]) obj);
 
577
 
 
578
        if (obj instanceof double[])
 
579
            return Arrays.hashCode((double[]) obj);
 
580
 
 
581
        if (obj instanceof Object[])
 
582
            return Arrays.hashCode((Object[]) obj);
 
583
 
 
584
        return obj.hashCode();
 
585
    }
 
586
 
 
587
    private static int hashCode(Class type, Map memberValues)
 
588
    {
 
589
        int h = 0;
 
590
        Iterator iter = memberValues.keySet().iterator();
 
591
        while (iter.hasNext())
 
592
        {
 
593
            Object key = iter.next();
 
594
            Object val = memberValues.get(key);
 
595
            h += deepHashCode(val) ^ 127 * key.hashCode();
 
596
        }
 
597
        return h;
 
598
    }
 
599
 
 
600
    private static String deepToString(Object obj)
 
601
    {
 
602
        if (obj instanceof boolean[])
 
603
            return Arrays.toString((boolean[]) obj);
 
604
 
 
605
        if (obj instanceof byte[])
 
606
            return Arrays.toString((byte[]) obj);
 
607
 
 
608
        if (obj instanceof char[])
 
609
            return Arrays.toString((char[]) obj);
 
610
 
 
611
        if (obj instanceof short[])
 
612
            return Arrays.toString((short[]) obj);
 
613
 
 
614
        if (obj instanceof int[])
 
615
            return Arrays.toString((int[]) obj);
 
616
 
 
617
        if (obj instanceof float[])
 
618
            return Arrays.toString((float[]) obj);
 
619
 
 
620
        if (obj instanceof long[])
 
621
            return Arrays.toString((long[]) obj);
 
622
 
 
623
        if (obj instanceof double[])
 
624
            return Arrays.toString((double[]) obj);
 
625
 
 
626
        if (obj instanceof Object[])
 
627
            return Arrays.toString((Object[]) obj);
 
628
 
 
629
        return obj.toString();
 
630
    }
 
631
 
 
632
    private static String toString(Class type, Map memberValues)
 
633
    {
 
634
        StringBuffer sb = new StringBuffer();
 
635
        sb.append('@').append(type.getName()).append('(');
 
636
        String sep = "";
 
637
        Iterator iter = memberValues.keySet().iterator();
 
638
        while (iter.hasNext())
 
639
        {
 
640
            Object key = iter.next();
 
641
            Object val = memberValues.get(key);
 
642
            sb.append(sep).append(key).append('=').append(deepToString(val));
 
643
            sep = ", ";
 
644
        }
 
645
        sb.append(')');
 
646
        return sb.toString();
 
647
    }
 
648
}