blob: 036696b20868375b01f490652ef817df57b14605 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.lang.reflect;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.apache.harmony.lang.AnnotatedElementTestFrame;
import org.apache.harmony.lang.AnnotatedElementTestFrame.MissingClassValAntn;
import org.apache.harmony.lang.AnnotatedElementTestFrame.MissingTypeAntn;
import org.apache.harmony.lang.AnnotatedElementTestFrame.TagAntn;
import org.apache.harmony.lang.AnnotatedElementTestFrame.ValAntn;
/**
* @author Alexey V. Varlamov
*/
public class Method5Test extends AnnotatedElementTestFrame {
protected @Override AnnotatedElement getElement1() throws Throwable {
return AnnotatedMethod.class.getMethod("foo");
}
protected @Override AnnotatedElement getElement2() throws Throwable {
return AnnotatedMethod.class.getMethod("bar");
}
protected @Override AnnotatedElement getElement3() throws Throwable {
return AnnotatedMethod.class.getMethod("buz", String.class);
}
/**
* Provides an instance to be tested. The instance must be annotated
* by the notfound.MissingAntn.
*/
protected @Override AnnotatedElement getElement4() throws Throwable {
return AnnotatedMethod.class.getMethod("i", int.class);
}
/**
* Provides an instance to be tested. The instance must be annotated
* by the MissingClassValAntn.
*/
protected @Override AnnotatedElement getElement5() throws Throwable {
return AnnotatedMethod.class.getMethod("l", long.class);
}
/**
* Provides an instance to be tested. The instance must be annotated
* by the MissingTypeAntn.
*/
protected @Override AnnotatedElement getElement6() throws Throwable {
return AnnotatedMethod.class.getMethod("ch", char.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(Method5Test.class);
}
protected final Annotation[][] getParamAnnotations(Member obj) throws Throwable {
assertTrue("illegal argument: " + obj,
(obj instanceof Method) || (obj instanceof Constructor));
Method m = obj.getClass().getMethod("getParameterAnnotations");
return (Annotation[][])m.invoke(obj);
}
protected Member getParamElement1() throws Throwable {
return AnnotatedParamMethod.class.getMethod("foo");
}
protected Member getParamElement2() throws Throwable {
return AnnotatedParamMethod.class.getMethod("bar",
Object.class, Class.class, boolean.class);
}
protected Member getParamElement3() throws Throwable {
return AnnotatedParamMethod.class.getMethod("buz",
String.class, int.class);
}
/**
* getParameterAnnotations() should return empty array
* if member has no parameters.
*/
public void testGetParameterAnnotations1() throws Throwable {
Annotation[][] an = getParamAnnotations(getParamElement1());
assertNotNull(an);
assertEquals(0, an.length);
}
/**
* getParameterAnnotations() should return array of annotation
* arrays for member parameters, in declaration order.
*/
public void testGetParameterAnnotations2() throws Throwable {
Annotation[][] an = getParamAnnotations(getParamElement2());
assertNotNull(an);
assertEquals("param num", 3, an.length);
assertEquals("1st param annotation num", 1, an[0].length);
assertSame("1st param annotation type", P1Antn.class,
an[0][0].annotationType());
assertEquals("2nd param annotation num", 1, an[1].length);
assertSame("2nd param annotation type", P2Antn.class,
an[1][0].annotationType());
assertEquals("2nd param annotation value", 123, ((P2Antn)an[1][0]).value());
assertEquals("3rd param annotation num", 2, an[2].length);
assertSame("3rd param annotation 1 type", P3Antn.class,
an[2][0].annotationType());
assertSame("3rd param annotation 2 type", ValAntn.class,
an[2][1].annotationType());
assertEquals("3rd param annotation 2 value", "xyz", ((ValAntn)an[2][1]).value());
}
/**
* For each parameter having no annotations,
* getParameterAnnotations() should return corresponding
* nested arrays with zero size.
*/
public void testGetParameterAnnotations3() throws Throwable {
Annotation[][] an = getParamAnnotations(getParamElement3());
assertNotNull(an);
assertEquals("param num", 2, an.length);
assertEquals("1st param annotation num", 0, an[0].length);
assertEquals("2nd param annotation num", 1, an[1].length);
assertSame("2nd param annotation type", TagAntn.class,
an[1][0].annotationType());
}
/**
* getParameterAnnotations() should return cloned arrays
* which can be safely modified by a caller.
*/
public void testGetParameterAnnotationsImmutable() throws Throwable {
Member m = getParamElement2();
Annotation[][] an0 = getParamAnnotations(m);
assertNotNull(an0);
assertEquals("param num", 3, an0.length);
an0[1] = an0[2];
an0[1][1] = null;
an0[2] = new Annotation[0];
Annotation[][] an = getParamAnnotations(m);
assertEquals("1st param annotation num", 1, an[0].length);
assertSame("1st param annotation type", P1Antn.class,
an[0][0].annotationType());
assertEquals("2nd param annotation num", 1, an[1].length);
assertSame("2nd param annotation type", P2Antn.class,
an[1][0].annotationType());
assertEquals("2nd param annotation value", 123, ((P2Antn)an[1][0]).value());
assertEquals("3rd param annotation num", 2, an[2].length);
assertSame("3rd param annotation 1 type", P3Antn.class,
an[2][0].annotationType());
assertSame("3rd param annotation 2 type", ValAntn.class,
an[2][1].annotationType());
assertEquals("3rd param annotation 2 value", "xyz", ((ValAntn)an[2][1]).value());
}
static class A {
private Object obj;
class InA {
Object o = obj;
}
}
enum E { E1, E2, E3}
static class B1 {
public Object foo() { return null;}
public Object bar(int i, Object... o) { return null;}
public static void main1(String... s){}
public static void main2(String[] s){}
}
static class B2 extends B1 {
public String foo() { return "";}
public String bar(int i, Object... o) { return "";}
}
/**
* isSynthetic() should return true if and only if
* the target method does not appear in the source code.
*/
public void testIsSynthetic() throws Exception {
assertFalse("case1.1: ordinary method",
AnnotatedMethod.class.getMethod("foo").isSynthetic());
assertFalse("case1.2: ordinary vararg method",
B1.class.getMethod("main1", String[].class).isSynthetic());
Method[] ms = A.class.getDeclaredMethods();
assertTrue(ms != null && ms.length > 0);
for (Method m : ms){
assertTrue("case2: " + m, m.isSynthetic());
}
// XXX bug in compiler?
//assertTrue("case3: EnumType.values()",
// E.class.getMethod("values").isSynthetic());
}
/**
* isBridge() should return true if and only if
* the target method does not appear in the source code
* and overrides covariant return type method.
*/
public void testIsBridge() throws Exception {
assertFalse("case1.1: ordinary method",
AnnotatedMethod.class.getMethod("foo").isBridge());
assertFalse("case1.2: ordinary vararg method",
B1.class.getMethod("main1", String[].class).isBridge());
Method[] ms = B1.class.getMethods();
assertTrue(ms != null && ms.length > 0);
for (Method m : ms){
assertFalse("case2.1: " + m, m.isBridge());
}
ms = B2.class.getDeclaredMethods();
assertTrue(ms != null && ms.length > 0);
for (Method m : ms){
//System.out.println("case2.2 " + m);
assertTrue("case2.2: " + m,
m.getReturnType() != Object.class ^ m.isBridge());
}
assertFalse("case3: EnumType.values()",
E.class.getMethod("values").isBridge());
}
/**
* isVarArgs() should return true if and only if
* the target method is declared with varargs.
*/
public void testIsVarargs() throws Exception {
assertFalse("case1: ordinary method",
AnnotatedMethod.class.getMethod("foo").isVarArgs());
assertTrue("case2: varargs method",
B1.class.getMethod("main1", String[].class).isVarArgs());
assertFalse("case3: ordinary method",
B1.class.getMethod("main2", String[].class).isVarArgs());
}
static abstract class C {
protected abstract <T extends Throwable>
OneParamType<? extends T> go(T t) throws T, Error;
}
/**
* toGenericString() should return a string exactly matching
* the API specification.
*/
public void testToGenericString() throws Exception {
String s = C.class.getDeclaredMethod("go",
Throwable.class).toGenericString();
System.out.println(s);
assertEquals(
// Should method type parameter be followed by a type bound? It is unspecified.
// The known reference implementation doesn't do it as well:
//"protected abstract <T extends java.lang.Throwable>"
"protected abstract <T>"
+ " java.lang.reflect.OneParamType<? extends T>"
+ " java.lang.reflect.Method5Test$C.go(T)"
+ " throws T,java.lang.Error",
s);
}
/**
* toGenericString() should return a string exactly matching
* the API specification.
*/
public void testToGenericString2() throws Exception {
String s = B2.class.getDeclaredMethod("bar",
int.class, Object[].class).toGenericString();
// it is unspecified which method should be returned:
// original (overriden with covariant return) or
// compiler-generated bridge.
// different implementations behave differently,
// so relaxed this check to allow both variants.
assertTrue("start: " + s, s.startsWith("public java.lang.")); // String or Object
assertTrue("end: " + s,
s.endsWith(" java.lang.reflect.Method5Test$B2."
+ "bar(int,java.lang.Object[])"));
}
}
abstract class AnnotatedMethod {
@TagAntn public abstract void foo();
@TagAntn @ValAntn public Object[] bar() {return null;}
public String buz(String s){return s;}
@notfound.MissingAntn public void i(int i) {}
@MissingClassValAntn public void l(long l){}
@MissingTypeAntn public void ch(char ch){}
}
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface P1Antn {}
@Retention(RetentionPolicy.RUNTIME)
@interface P2Antn {
int value();
}
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface P3Antn {
String[] meta1() default {};
P1Antn meta2() default @P1Antn;
}
class AnnotatedParamMethod {
@TagAntn public void foo(){}
@ValAntn("abc") public void bar(@P1Antn Object p1,
@P2Antn(123) Class p2, @P3Antn @ValAntn("xyz") boolean p3){}
public void buz(String s, @TagAntn int i){}
}