1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import java.lang.reflect.Array;
18 import java.lang.reflect.Field;
19 import java.lang.reflect.Method;
20 
21 public class Main {
main(String[] args)22   public static void main(String[] args) throws Exception {
23     arrayAccess();
24     arrayStore();
25     classCast();
26     classNotFound();
27     negativeArraySize();
28     nullPointers();
29     reflection();
30     stringIndex();
31   }
32 
assertEquals(String expected, String actual)33   private static void assertEquals(String expected, String actual) {
34     if (expected == null && actual == null) {
35       return;
36     }
37     if (expected != null && expected.equals(actual)) {
38       return;
39     }
40     throw new AssertionError("not equal\n" +
41                                  "expected: " + expected + "\n" +
42                                  "actual:   " + actual);
43   }
44 
fail()45   private static void fail() {
46     throw new AssertionError();
47   }
48 
arrayAccess()49   private static void arrayAccess() throws Exception {
50     byte[] bs = new byte[1];
51     double[] ds = new double[1];
52     Object[] os = new Object[1];
53 
54     // aput
55     try {
56       bs[2] = 0;
57       fail();
58     } catch (ArrayIndexOutOfBoundsException ex) {
59       assertEquals("length=1; index=2", ex.getMessage());
60     }
61 
62     // aget
63     try {
64       byte b = bs[2];
65       fail();
66     } catch (ArrayIndexOutOfBoundsException ex) {
67       assertEquals("length=1; index=2", ex.getMessage());
68     }
69 
70     // aput-wide
71     try {
72       ds[2] = 0.0;
73       fail();
74     } catch (ArrayIndexOutOfBoundsException ex) {
75       assertEquals("length=1; index=2", ex.getMessage());
76     }
77 
78     // aget-wide
79     try {
80       double d = ds[2];
81       fail();
82     } catch (ArrayIndexOutOfBoundsException ex) {
83       assertEquals("length=1; index=2", ex.getMessage());
84     }
85 
86     // aput-object
87     try {
88       os[2] = null;
89       fail();
90     } catch (ArrayIndexOutOfBoundsException ex) {
91       assertEquals("length=1; index=2", ex.getMessage());
92     }
93 
94     // aget-object
95     try {
96       Object o = os[2];
97       fail();
98     } catch (ArrayIndexOutOfBoundsException ex) {
99       assertEquals("length=1; index=2", ex.getMessage());
100     }
101   }
102 
arrayStore()103   private static void arrayStore() throws Exception {
104     try {
105       Object[] array = new String[10];
106       Object o = new Exception();
107       array[0] = o;
108       fail();
109     } catch (ArrayStoreException ex) {
110       assertEquals("java.lang.Exception cannot be stored in an array of type java.lang.String[]",
111                    ex.getMessage());
112     }
113 
114     try {
115       Object[] array = new C[10][];
116       Object o = new Integer(5);
117       array[0] = o;
118       fail();
119     } catch (ArrayStoreException ex) {
120       assertEquals("java.lang.Integer cannot be stored in an array of type Main$C[][]",
121                    ex.getMessage());
122     }
123 
124     try {
125       Object[] array = new Float[10][];
126       Object o = new C[4];
127       array[0] = o;
128       fail();
129     } catch (ArrayStoreException ex) {
130       assertEquals("Main$C[] cannot be stored in an array of type java.lang.Float[][]",
131                    ex.getMessage());
132     }
133 
134     try {
135       String[] src = new String[] { null, null, null, null, "hello", "goodbye" };
136       Integer[] dst = new Integer[10];
137       System.arraycopy(src, 1, dst, 0, 5);
138     } catch (ArrayStoreException ex) {
139       assertEquals("source[4] of type java.lang.String cannot be stored in destination array of type java.lang.Integer[]",
140                    ex.getMessage());
141     }
142 
143     try {
144       String[] src = new String[1];
145       int[] dst = new int[1];
146       System.arraycopy(src, 0, dst, 0, 1);
147     } catch (ArrayStoreException ex) {
148       assertEquals("Incompatible types: src=java.lang.String[], dst=int[]", ex.getMessage());
149     }
150 
151     try {
152       float[] src = new float[1];
153       Runnable[] dst = new Runnable[1];
154       System.arraycopy(src, 0, dst, 0, 1);
155     } catch (ArrayStoreException ex) {
156       assertEquals("Incompatible types: src=float[], dst=java.lang.Runnable[]", ex.getMessage());
157     }
158 
159     try {
160       boolean[] src = new boolean[1];
161       double[][] dst = new double[1][];
162       System.arraycopy(src, 0, dst, 0, 1);
163     } catch (ArrayStoreException ex) {
164       assertEquals("Incompatible types: src=boolean[], dst=double[][]", ex.getMessage());
165     }
166 
167     try {
168       String src = "hello";
169       Object[] dst = new Object[1];
170       System.arraycopy(src, 0, dst, 0, 1);
171     } catch (ArrayStoreException ex) {
172       assertEquals("source of type java.lang.String is not an array", ex.getMessage());
173     }
174 
175     try {
176       Object[] src = new Object[1];
177       Integer dst = new Integer(5);
178       System.arraycopy(src, 0, dst, 0, 1);
179     } catch (ArrayStoreException ex) {
180       assertEquals("destination of type java.lang.Integer is not an array", ex.getMessage());
181     }
182 
183     // This test demonstrates that the exception message complains
184     // about the source in cases where neither source nor
185     // destination is an array.
186     try {
187       System.arraycopy(new C(), 0, "hello", 0, 1);
188     } catch (ArrayStoreException ex) {
189       assertEquals("source of type Main$C is not an array", ex.getMessage());
190     }
191   }
192 
classCast()193   private static void classCast() throws Exception {
194     // Reference types.
195     try {
196       Object o = new Exception();
197       String s = (String) o;
198       fail();
199     } catch (ClassCastException ex) {
200       assertEquals("java.lang.Exception cannot be cast to java.lang.String", ex.getMessage());
201     }
202 
203     // Arrays of reference types.
204     try {
205       Object o = (C) makeArray(String.class);
206       fail();
207     } catch (ClassCastException ex) {
208       assertEquals("java.lang.String[] cannot be cast to Main$C", ex.getMessage());
209     }
210 
211     // Arrays of primitives.
212     try {
213       Object o = (C) makeArray(float.class);
214       fail();
215     } catch (ClassCastException ex) {
216       assertEquals("float[] cannot be cast to Main$C", ex.getMessage());
217     }
218 
219     // Multi-dimensional arrays of primitives.
220     try {
221       Object o = (C) makeArray(char[].class);
222       fail();
223     } catch (ClassCastException ex) {
224       assertEquals("char[][] cannot be cast to Main$C", ex.getMessage());
225     }
226 
227     // Multi-dimensional arrays of references.
228     try {
229       Object o = (Object[][][]) makeInteger();
230       fail();
231     } catch (ClassCastException ex) {
232       assertEquals("java.lang.Integer cannot be cast to java.lang.Object[][][]", ex.getMessage());
233     }
234   }
235 
236   static class C { }
237 
238   /**
239    * Helper for testCastOperator and testCastOperatorWithArrays. It's important that the
240    * return type is Object, since otherwise the compiler will just reject the code.
241    */
makeInteger()242   private static Object makeInteger() {
243     return new Integer(5);
244   }
245 
246   /**
247    * Helper for testCastOperatorWithArrays. It's important that
248    * the return type is Object.
249    */
makeArray(Class c)250   private static Object makeArray(Class c) {
251     return Array.newInstance(c, 1);
252   }
253 
classNotFound()254   private static void classNotFound() throws Exception {
255     try {
256       // There is no such thing as an array of void.
257       Class.forName("[V");
258       fail();
259     } catch (ClassNotFoundException ex) {
260       assertEquals("Invalid name: [V", ex.getMessage());
261     }
262 
263     try {
264       // This class name is valid, but doesn't exist.
265       Class.forName("package.Class");
266       fail();
267     } catch (ClassNotFoundException ex) {
268       assertEquals("package.Class", ex.getMessage());
269     }
270 
271     try {
272       // This array class name is valid, but the type doesn't exist.
273       Class.forName("[[Lpackage.Class;");
274       fail();
275     } catch (ClassNotFoundException ex) {
276       assertEquals("[[Lpackage.Class;", ex.getMessage());
277     }
278   }
279 
negativeArraySize()280   private static void negativeArraySize() throws Exception {
281     try {
282       int[] is = new int[-123];
283       fail();
284     } catch (NegativeArraySizeException ex) {
285       assertEquals("-123", ex.getMessage());
286     }
287   }
288 
289   // Defeat the fact that null's are untyped for precise detail message creation with quickening.
returnNullObject()290   private static Object returnNullObject() {
291     return null;
292   }
293 
returnNullA()294   private static A returnNullA() {
295     return null;
296   }
297 
nullPointers()298   private static void nullPointers() throws Exception {
299     // Invoke method.
300     try {
301       Object o = returnNullObject();
302       o.hashCode();
303       fail();
304     } catch (NullPointerException ex) {
305       assertEquals("Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference", ex.getMessage());
306     }
307 
308     // Read field.
309     try {
310       A a = returnNullA();
311       int i = a.i;
312       fail();
313     } catch (NullPointerException ex) {
314       assertEquals("Attempt to read from field 'int A.i' on a null object reference", ex.getMessage());
315     }
316 
317     // Write field.
318     try {
319       A a = returnNullA();
320       a.i = 1;
321       fail();
322     } catch (NullPointerException ex) {
323       assertEquals("Attempt to write to field 'int A.i' on a null object reference", ex.getMessage());
324     }
325 
326     // Read array.
327     try {
328       int[] is = null;
329       int i = is[0];
330       fail();
331     } catch (NullPointerException ex) {
332       assertEquals("Attempt to read from null array", ex.getMessage());
333     }
334 
335     // Write array.
336     try {
337       int[] is = null;
338       is[0] = 1;
339       fail();
340     } catch (NullPointerException ex) {
341       assertEquals("Attempt to write to null array", ex.getMessage());
342     }
343 
344     // Array length.
345     try {
346       int[] is = null;
347       int i = is.length;
348       fail();
349     } catch (NullPointerException ex) {
350       assertEquals("Attempt to get length of null array", ex.getMessage());
351     }
352   }
353 
reflection()354   private static void reflection() throws Exception {
355     // Can't assign Integer to a String field.
356     try {
357       Field field = A.class.getField("b");
358       field.set(new A(), 5);
359       fail();
360     } catch (IllegalArgumentException expected) {
361       assertEquals("field A.b has type java.lang.String, got java.lang.Integer",
362           expected.getMessage());
363     }
364 
365     // Can't unbox null to a primitive.
366     try {
367       Field field = A.class.getField("i");
368       field.set(new A(), null);
369       fail();
370     } catch (IllegalArgumentException expected) {
371       assertEquals("field A.i has type int, got null", expected.getMessage());
372     }
373 
374     // Can't unbox String to a primitive.
375     try {
376       Field field = A.class.getField("i");
377       field.set(new A(), "hello, world!");
378       fail();
379     } catch (IllegalArgumentException expected) {
380       assertEquals("field A.i has type int, got java.lang.String", expected.getMessage());
381     }
382 
383     // Can't pass an Integer as a String.
384     try {
385       Method m = A.class.getMethod("m", int.class, String.class);
386       m.invoke(new A(), 2, 2);
387       fail();
388     } catch (IllegalArgumentException expected) {
389       assertEquals("method A.m argument 2 has type java.lang.String, got java.lang.Integer",
390           expected.getMessage());
391     }
392 
393     // Can't pass null as an int.
394     try {
395       Method m = A.class.getMethod("m", int.class, String.class);
396       m.invoke(new A(), null, "");
397       fail();
398     } catch (IllegalArgumentException expected) {
399       assertEquals("method A.m argument 1 has type int, got null", expected.getMessage());
400     }
401 
402     try {
403       Method m = String.class.getMethod("charAt", int.class);
404       m.invoke("hello"); // Wrong number of arguments.
405       fail();
406     } catch (IllegalArgumentException iae) {
407       assertEquals("Wrong number of arguments; expected 1, got 0", iae.getMessage());
408     }
409     try {
410       Method m = String.class.getMethod("charAt", int.class);
411       m.invoke("hello", "world"); // Wrong type.
412       fail();
413     } catch (IllegalArgumentException iae) {
414       assertEquals("method java.lang.String.charAt! argument 1 has type int, got java.lang.String",
415           iae.getMessage());
416     }
417     try {
418       Method m = String.class.getMethod("charAt", int.class);
419       m.invoke("hello", (Object) null); // Null for a primitive argument.
420       fail();
421     } catch (IllegalArgumentException iae) {
422       assertEquals("method java.lang.String.charAt! argument 1 has type int, got null",
423           iae.getMessage());
424     }
425     try {
426       Method m = String.class.getMethod("charAt", int.class);
427       m.invoke(new Integer(5)); // Wrong type for 'this'.
428       fail();
429     } catch (IllegalArgumentException iae) {
430       assertEquals("Expected receiver of type java.lang.String, but got java.lang.Integer",
431           iae.getMessage());
432     }
433     try {
434       Method m = String.class.getMethod("charAt", int.class);
435       m.invoke(null); // Null for 'this'.
436       fail();
437     } catch (NullPointerException npe) {
438       assertEquals("null receiver", npe.getMessage());
439     }
440   }
441 
stringIndex()442   private static void stringIndex() throws Exception {
443     // charAt too small.
444     try {
445       "hello".charAt(-1);
446       fail();
447     } catch (StringIndexOutOfBoundsException ex) {
448       assertEquals("length=5; index=-1", ex.getMessage());
449     }
450 
451     // charAt too big.
452     try {
453       "hello".charAt(7);
454       fail();
455     } catch (StringIndexOutOfBoundsException ex) {
456       assertEquals("length=5; index=7", ex.getMessage());
457     }
458 
459     // substring too big.
460     try {
461       "hello there".substring(9,14);
462       fail();
463     } catch (StringIndexOutOfBoundsException ex) {
464       assertEquals("length=11; regionStart=9; regionLength=5", ex.getMessage());
465     }
466   }
467 }
468 
469 class A {
470   public String b;
471   public int i;
m(int i, String s)472   public void m(int i, String s) {}
473 }
474