Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_hotspot
提交
d9cf0a49
D
dragonwell8_hotspot
项目概览
openanolis
/
dragonwell8_hotspot
通知
2
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_hotspot
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
d9cf0a49
编写于
10月 22, 2014
作者:
A
aeriksso
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8057043: Type annotations not retained during class redefine / retransform
Reviewed-by: coleenp, sspitsyn, jfranck
上级
35de3fa1
变更
4
展开全部
隐藏空白更改
内联
并排
Showing
4 changed file
with
1054 addition
and
17 deletion
+1054
-17
src/share/vm/prims/jvmtiClassFileReconstituter.cpp
src/share/vm/prims/jvmtiClassFileReconstituter.cpp
+22
-0
src/share/vm/prims/jvmtiRedefineClasses.cpp
src/share/vm/prims/jvmtiRedefineClasses.cpp
+605
-17
src/share/vm/prims/jvmtiRedefineClasses.hpp
src/share/vm/prims/jvmtiRedefineClasses.hpp
+17
-0
test/runtime/RedefineTests/RedefineAnnotations.java
test/runtime/RedefineTests/RedefineAnnotations.java
+410
-0
未找到文件。
src/share/vm/prims/jvmtiClassFileReconstituter.cpp
浏览文件 @
d9cf0a49
...
...
@@ -54,6 +54,7 @@
void
JvmtiClassFileReconstituter
::
write_field_infos
()
{
HandleMark
hm
(
thread
());
Array
<
AnnotationArray
*>*
fields_anno
=
ikh
()
->
fields_annotations
();
Array
<
AnnotationArray
*>*
fields_type_anno
=
ikh
()
->
fields_type_annotations
();
// Compute the real number of Java fields
int
java_fields
=
ikh
()
->
java_fields_count
();
...
...
@@ -68,6 +69,7 @@ void JvmtiClassFileReconstituter::write_field_infos() {
// int offset = ikh()->field_offset( index );
int
generic_signature_index
=
fs
.
generic_signature_index
();
AnnotationArray
*
anno
=
fields_anno
==
NULL
?
NULL
:
fields_anno
->
at
(
fs
.
index
());
AnnotationArray
*
type_anno
=
fields_type_anno
==
NULL
?
NULL
:
fields_type_anno
->
at
(
fs
.
index
());
// JVMSpec| field_info {
// JVMSpec| u2 access_flags;
...
...
@@ -93,6 +95,9 @@ void JvmtiClassFileReconstituter::write_field_infos() {
if
(
anno
!=
NULL
)
{
++
attr_count
;
// has RuntimeVisibleAnnotations attribute
}
if
(
type_anno
!=
NULL
)
{
++
attr_count
;
// has RuntimeVisibleTypeAnnotations attribute
}
write_u2
(
attr_count
);
...
...
@@ -110,6 +115,9 @@ void JvmtiClassFileReconstituter::write_field_infos() {
if
(
anno
!=
NULL
)
{
write_annotations_attribute
(
"RuntimeVisibleAnnotations"
,
anno
);
}
if
(
type_anno
!=
NULL
)
{
write_annotations_attribute
(
"RuntimeVisibleTypeAnnotations"
,
type_anno
);
}
}
}
...
...
@@ -550,6 +558,7 @@ void JvmtiClassFileReconstituter::write_method_info(methodHandle method) {
AnnotationArray
*
anno
=
method
->
annotations
();
AnnotationArray
*
param_anno
=
method
->
parameter_annotations
();
AnnotationArray
*
default_anno
=
method
->
annotation_default
();
AnnotationArray
*
type_anno
=
method
->
type_annotations
();
// skip generated default interface methods
if
(
method
->
is_overpass
())
{
...
...
@@ -585,6 +594,9 @@ void JvmtiClassFileReconstituter::write_method_info(methodHandle method) {
if
(
param_anno
!=
NULL
)
{
++
attr_count
;
// has RuntimeVisibleParameterAnnotations attribute
}
if
(
type_anno
!=
NULL
)
{
++
attr_count
;
// has RuntimeVisibleTypeAnnotations attribute
}
write_u2
(
attr_count
);
if
(
const_method
->
code_size
()
>
0
)
{
...
...
@@ -609,6 +621,9 @@ void JvmtiClassFileReconstituter::write_method_info(methodHandle method) {
if
(
param_anno
!=
NULL
)
{
write_annotations_attribute
(
"RuntimeVisibleParameterAnnotations"
,
param_anno
);
}
if
(
type_anno
!=
NULL
)
{
write_annotations_attribute
(
"RuntimeVisibleTypeAnnotations"
,
type_anno
);
}
}
// Write the class attributes portion of ClassFile structure
...
...
@@ -618,6 +633,7 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
u2
inner_classes_length
=
inner_classes_attribute_length
();
Symbol
*
generic_signature
=
ikh
()
->
generic_signature
();
AnnotationArray
*
anno
=
ikh
()
->
class_annotations
();
AnnotationArray
*
type_anno
=
ikh
()
->
class_type_annotations
();
int
attr_count
=
0
;
if
(
generic_signature
!=
NULL
)
{
...
...
@@ -635,6 +651,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if
(
anno
!=
NULL
)
{
++
attr_count
;
// has RuntimeVisibleAnnotations attribute
}
if
(
type_anno
!=
NULL
)
{
++
attr_count
;
// has RuntimeVisibleTypeAnnotations attribute
}
if
(
cpool
()
->
operands
()
!=
NULL
)
{
++
attr_count
;
}
...
...
@@ -656,6 +675,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if
(
anno
!=
NULL
)
{
write_annotations_attribute
(
"RuntimeVisibleAnnotations"
,
anno
);
}
if
(
type_anno
!=
NULL
)
{
write_annotations_attribute
(
"RuntimeVisibleTypeAnnotations"
,
type_anno
);
}
if
(
cpool
()
->
operands
()
!=
NULL
)
{
write_bootstrapmethod_attribute
();
}
...
...
src/share/vm/prims/jvmtiRedefineClasses.cpp
浏览文件 @
d9cf0a49
此差异已折叠。
点击以展开。
src/share/vm/prims/jvmtiRedefineClasses.hpp
浏览文件 @
d9cf0a49
...
...
@@ -457,6 +457,17 @@ class VM_RedefineClasses: public VM_Operation {
instanceKlassHandle
scratch_class
,
TRAPS
);
bool
rewrite_cp_refs_in_element_value
(
AnnotationArray
*
class_annotations
,
int
&
byte_i_ref
,
TRAPS
);
bool
rewrite_cp_refs_in_type_annotations_typeArray
(
AnnotationArray
*
type_annotations_typeArray
,
int
&
byte_i_ref
,
const
char
*
location_mesg
,
TRAPS
);
bool
rewrite_cp_refs_in_type_annotation_struct
(
AnnotationArray
*
type_annotations_typeArray
,
int
&
byte_i_ref
,
const
char
*
location_mesg
,
TRAPS
);
bool
skip_type_annotation_target
(
AnnotationArray
*
type_annotations_typeArray
,
int
&
byte_i_ref
,
const
char
*
location_mesg
,
TRAPS
);
bool
skip_type_annotation_type_path
(
AnnotationArray
*
type_annotations_typeArray
,
int
&
byte_i_ref
,
TRAPS
);
bool
rewrite_cp_refs_in_fields_annotations
(
instanceKlassHandle
scratch_class
,
TRAPS
);
void
rewrite_cp_refs_in_method
(
methodHandle
method
,
...
...
@@ -468,6 +479,12 @@ class VM_RedefineClasses: public VM_Operation {
instanceKlassHandle
scratch_class
,
TRAPS
);
bool
rewrite_cp_refs_in_methods_parameter_annotations
(
instanceKlassHandle
scratch_class
,
TRAPS
);
bool
rewrite_cp_refs_in_class_type_annotations
(
instanceKlassHandle
scratch_class
,
TRAPS
);
bool
rewrite_cp_refs_in_fields_type_annotations
(
instanceKlassHandle
scratch_class
,
TRAPS
);
bool
rewrite_cp_refs_in_methods_type_annotations
(
instanceKlassHandle
scratch_class
,
TRAPS
);
void
rewrite_cp_refs_in_stack_map_table
(
methodHandle
method
,
TRAPS
);
void
rewrite_cp_refs_in_verification_type_info
(
address
&
stackmap_addr_ref
,
address
stackmap_end
,
u2
frame_i
,
...
...
test/runtime/RedefineTests/RedefineAnnotations.java
0 → 100644
浏览文件 @
d9cf0a49
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /testlibrary
* @summary Test that type annotations are retained after a retransform
* @run main RedefineAnnotations buildagent
* @run main/othervm -javaagent:redefineagent.jar RedefineAnnotations
*/
import
static
com
.
oracle
.
java
.
testlibrary
.
Asserts
.
assertTrue
;
import
java.io.FileNotFoundException
;
import
java.io.PrintWriter
;
import
java.lang.NoSuchFieldException
;
import
java.lang.NoSuchMethodException
;
import
java.lang.RuntimeException
;
import
java.lang.annotation.Annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
java.lang.instrument.ClassFileTransformer
;
import
java.lang.instrument.IllegalClassFormatException
;
import
java.lang.instrument.Instrumentation
;
import
java.lang.instrument.UnmodifiableClassException
;
import
java.lang.reflect.AnnotatedArrayType
;
import
java.lang.reflect.AnnotatedParameterizedType
;
import
java.lang.reflect.AnnotatedType
;
import
java.lang.reflect.AnnotatedWildcardType
;
import
java.lang.reflect.Executable
;
import
java.lang.reflect.TypeVariable
;
import
java.security.ProtectionDomain
;
import
java.util.Arrays
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.Map
;
import
jdk.internal.org.objectweb.asm.ClassReader
;
import
jdk.internal.org.objectweb.asm.ClassVisitor
;
import
jdk.internal.org.objectweb.asm.ClassWriter
;
import
jdk.internal.org.objectweb.asm.FieldVisitor
;
import
static
jdk
.
internal
.
org
.
objectweb
.
asm
.
Opcodes
.
ASM5
;
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
ElementType
.
TYPE_USE
)
@interface
TestAnn
{
String
site
();
}
public
class
RedefineAnnotations
{
static
Instrumentation
inst
;
public
static
void
premain
(
String
agentArgs
,
Instrumentation
inst
)
{
RedefineAnnotations
.
inst
=
inst
;
}
static
class
Transformer
implements
ClassFileTransformer
{
public
byte
[]
asm
(
ClassLoader
loader
,
String
className
,
Class
<?>
classBeingRedefined
,
ProtectionDomain
protectionDomain
,
byte
[]
classfileBuffer
)
throws
IllegalClassFormatException
{
ClassWriter
cw
=
new
ClassWriter
(
0
);
ClassVisitor
cv
=
new
ReAddDummyFieldsClassVisitor
(
ASM5
,
cw
)
{
};
ClassReader
cr
=
new
ClassReader
(
classfileBuffer
);
cr
.
accept
(
cv
,
0
);
return
cw
.
toByteArray
();
}
public
class
ReAddDummyFieldsClassVisitor
extends
ClassVisitor
{
LinkedList
<
F
>
fields
=
new
LinkedList
<>();
public
ReAddDummyFieldsClassVisitor
(
int
api
,
ClassVisitor
cv
)
{
super
(
api
,
cv
);
}
@Override
public
FieldVisitor
visitField
(
int
access
,
String
name
,
String
desc
,
String
signature
,
Object
value
)
{
if
(
name
.
startsWith
(
"dummy"
))
{
// Remove dummy field
fields
.
addLast
(
new
F
(
access
,
name
,
desc
,
signature
,
value
));
return
null
;
}
return
cv
.
visitField
(
access
,
name
,
desc
,
signature
,
value
);
}
@Override
public
void
visitEnd
()
{
F
f
;
while
((
f
=
fields
.
pollFirst
())
!=
null
)
{
// Re-add dummy fields
cv
.
visitField
(
f
.
access
,
f
.
name
,
f
.
desc
,
f
.
signature
,
f
.
value
);
}
}
private
class
F
{
private
int
access
;
private
String
name
;
private
String
desc
;
private
String
signature
;
private
Object
value
;
F
(
int
access
,
String
name
,
String
desc
,
String
signature
,
Object
value
)
{
this
.
access
=
access
;
this
.
name
=
name
;
this
.
desc
=
desc
;
this
.
signature
=
signature
;
this
.
value
=
value
;
}
}
}
@Override
public
byte
[]
transform
(
ClassLoader
loader
,
String
className
,
Class
<?>
classBeingRedefined
,
ProtectionDomain
protectionDomain
,
byte
[]
classfileBuffer
)
throws
IllegalClassFormatException
{
if
(
className
.
contains
(
"TypeAnnotatedTestClass"
))
{
try
{
// Here we remove and re-add the dummy fields. This shuffles the constant pool
return
asm
(
loader
,
className
,
classBeingRedefined
,
protectionDomain
,
classfileBuffer
);
}
catch
(
Throwable
e
)
{
// The retransform native code that called this method does not propagate
// exceptions. Instead of getting an uninformative generic error, catch
// problems here and print it, then exit.
e
.
printStackTrace
();
System
.
exit
(
1
);
}
}
return
null
;
}
}
private
static
void
buildAgent
()
{
try
{
ClassFileInstaller
.
main
(
"RedefineAnnotations"
);
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"Could not write agent classfile"
,
e
);
}
try
{
PrintWriter
pw
=
new
PrintWriter
(
"MANIFEST.MF"
);
pw
.
println
(
"Premain-Class: RedefineAnnotations"
);
pw
.
println
(
"Agent-Class: RedefineAnnotations"
);
pw
.
println
(
"Can-Retransform-Classes: true"
);
pw
.
close
();
}
catch
(
FileNotFoundException
e
)
{
throw
new
RuntimeException
(
"Could not write manifest file for the agent"
,
e
);
}
sun
.
tools
.
jar
.
Main
jarTool
=
new
sun
.
tools
.
jar
.
Main
(
System
.
out
,
System
.
err
,
"jar"
);
if
(!
jarTool
.
run
(
new
String
[]
{
"-cmf"
,
"MANIFEST.MF"
,
"redefineagent.jar"
,
"RedefineAnnotations.class"
}))
{
throw
new
RuntimeException
(
"Could not write the agent jar file"
);
}
}
public
static
void
main
(
String
argv
[])
throws
NoSuchFieldException
,
NoSuchMethodException
{
if
(
argv
.
length
==
1
&&
argv
[
0
].
equals
(
"buildagent"
))
{
buildAgent
();
return
;
}
if
(
inst
==
null
)
{
throw
new
RuntimeException
(
"Instrumentation object was null"
);
}
RedefineAnnotations
test
=
new
RedefineAnnotations
();
test
.
testTransformAndVerify
();
}
// Class type annotations
private
Annotation
classTypeParameterTA
;
private
Annotation
extendsTA
;
private
Annotation
implementsTA
;
// Field type annotations
private
Annotation
fieldTA
;
private
Annotation
innerTA
;
private
Annotation
[]
arrayTA
=
new
Annotation
[
4
];
private
Annotation
[]
mapTA
=
new
Annotation
[
5
];
// Method type annotations
private
Annotation
returnTA
,
methodTypeParameterTA
,
formalParameterTA
,
throwsTA
;
private
void
testTransformAndVerify
()
throws
NoSuchFieldException
,
NoSuchMethodException
{
Class
<
TypeAnnotatedTestClass
>
c
=
TypeAnnotatedTestClass
.
class
;
Class
<?>
myClass
=
c
;
/*
* Verify that the expected annotations are where they should be before transform.
*/
verifyClassTypeAnnotations
(
c
);
verifyFieldTypeAnnotations
(
c
);
verifyMethodTypeAnnotations
(
c
);
try
{
inst
.
addTransformer
(
new
Transformer
(),
true
);
inst
.
retransformClasses
(
myClass
);
}
catch
(
UnmodifiableClassException
e
)
{
throw
new
RuntimeException
(
e
);
}
/*
* Verify that the expected annotations are where they should be after transform.
* Also verify that before and after are equal.
*/
verifyClassTypeAnnotations
(
c
);
verifyFieldTypeAnnotations
(
c
);
verifyMethodTypeAnnotations
(
c
);
}
private
void
verifyClassTypeAnnotations
(
Class
c
)
{
Annotation
anno
;
anno
=
c
.
getTypeParameters
()[
0
].
getAnnotations
()[
0
];
verifyTestAnn
(
classTypeParameterTA
,
anno
,
"classTypeParameter"
);
classTypeParameterTA
=
anno
;
anno
=
c
.
getAnnotatedSuperclass
().
getAnnotations
()[
0
];
verifyTestAnn
(
extendsTA
,
anno
,
"extends"
);
extendsTA
=
anno
;
anno
=
c
.
getAnnotatedInterfaces
()[
0
].
getAnnotations
()[
0
];
verifyTestAnn
(
implementsTA
,
anno
,
"implements"
);
implementsTA
=
anno
;
}
private
void
verifyFieldTypeAnnotations
(
Class
c
)
throws
NoSuchFieldException
,
NoSuchMethodException
{
verifyBasicFieldTypeAnnotations
(
c
);
verifyInnerFieldTypeAnnotations
(
c
);
verifyArrayFieldTypeAnnotations
(
c
);
verifyMapFieldTypeAnnotations
(
c
);
}
private
void
verifyBasicFieldTypeAnnotations
(
Class
c
)
throws
NoSuchFieldException
,
NoSuchMethodException
{
Annotation
anno
=
c
.
getDeclaredField
(
"typeAnnotatedBoolean"
).
getAnnotatedType
().
getAnnotations
()[
0
];
verifyTestAnn
(
fieldTA
,
anno
,
"field"
);
fieldTA
=
anno
;
}
private
void
verifyInnerFieldTypeAnnotations
(
Class
c
)
throws
NoSuchFieldException
,
NoSuchMethodException
{
AnnotatedType
at
=
c
.
getDeclaredField
(
"typeAnnotatedInner"
).
getAnnotatedType
();
Annotation
anno
=
at
.
getAnnotations
()[
0
];
verifyTestAnn
(
innerTA
,
anno
,
"inner"
);
innerTA
=
anno
;
}
private
void
verifyArrayFieldTypeAnnotations
(
Class
c
)
throws
NoSuchFieldException
,
NoSuchMethodException
{
Annotation
anno
;
AnnotatedType
at
;
at
=
c
.
getDeclaredField
(
"typeAnnotatedArray"
).
getAnnotatedType
();
anno
=
at
.
getAnnotations
()[
0
];
verifyTestAnn
(
arrayTA
[
0
],
anno
,
"array1"
);
arrayTA
[
0
]
=
anno
;
for
(
int
i
=
1
;
i
<=
3
;
i
++)
{
at
=
((
AnnotatedArrayType
)
at
).
getAnnotatedGenericComponentType
();
anno
=
at
.
getAnnotations
()[
0
];
verifyTestAnn
(
arrayTA
[
i
],
anno
,
"array"
+
(
i
+
1
));
arrayTA
[
i
]
=
anno
;
}
}
private
void
verifyMapFieldTypeAnnotations
(
Class
c
)
throws
NoSuchFieldException
,
NoSuchMethodException
{
Annotation
anno
;
AnnotatedType
atBase
;
AnnotatedType
atParameter
;
atBase
=
c
.
getDeclaredField
(
"typeAnnotatedMap"
).
getAnnotatedType
();
anno
=
atBase
.
getAnnotations
()[
0
];
verifyTestAnn
(
mapTA
[
0
],
anno
,
"map1"
);
mapTA
[
0
]
=
anno
;
atParameter
=
((
AnnotatedParameterizedType
)
atBase
).
getAnnotatedActualTypeArguments
()[
0
];
anno
=
((
AnnotatedWildcardType
)
atParameter
).
getAnnotations
()[
0
];
verifyTestAnn
(
mapTA
[
1
],
anno
,
"map2"
);
mapTA
[
1
]
=
anno
;
anno
=
((
AnnotatedWildcardType
)
atParameter
).
getAnnotatedUpperBounds
()[
0
].
getAnnotations
()[
0
];
verifyTestAnn
(
mapTA
[
2
],
anno
,
"map3"
);
mapTA
[
2
]
=
anno
;
atParameter
=
((
AnnotatedParameterizedType
)
atBase
).
getAnnotatedActualTypeArguments
()[
1
];
anno
=
((
AnnotatedParameterizedType
)
atParameter
).
getAnnotations
()[
0
];
verifyTestAnn
(
mapTA
[
3
],
anno
,
"map4"
);
mapTA
[
3
]
=
anno
;
anno
=
((
AnnotatedParameterizedType
)
atParameter
).
getAnnotatedActualTypeArguments
()[
0
].
getAnnotations
()[
0
];
verifyTestAnn
(
mapTA
[
4
],
anno
,
"map5"
);
mapTA
[
4
]
=
anno
;
}
private
void
verifyMethodTypeAnnotations
(
Class
c
)
throws
NoSuchFieldException
,
NoSuchMethodException
{
Annotation
anno
;
Executable
typeAnnotatedMethod
=
c
.
getDeclaredMethod
(
"typeAnnotatedMethod"
,
TypeAnnotatedTestClass
.
class
);
anno
=
typeAnnotatedMethod
.
getAnnotatedReturnType
().
getAnnotations
()[
0
];
verifyTestAnn
(
returnTA
,
anno
,
"return"
);
returnTA
=
anno
;
anno
=
typeAnnotatedMethod
.
getTypeParameters
()[
0
].
getAnnotations
()[
0
];
verifyTestAnn
(
methodTypeParameterTA
,
anno
,
"methodTypeParameter"
);
methodTypeParameterTA
=
anno
;
anno
=
typeAnnotatedMethod
.
getAnnotatedParameterTypes
()[
0
].
getAnnotations
()[
0
];
verifyTestAnn
(
formalParameterTA
,
anno
,
"formalParameter"
);
formalParameterTA
=
anno
;
anno
=
typeAnnotatedMethod
.
getAnnotatedExceptionTypes
()[
0
].
getAnnotations
()[
0
];
verifyTestAnn
(
throwsTA
,
anno
,
"throws"
);
throwsTA
=
anno
;
}
private
static
void
verifyTestAnn
(
Annotation
verifyAgainst
,
Annotation
anno
,
String
expectedSite
)
{
verifyTestAnnSite
(
anno
,
expectedSite
);
// When called before transform verifyAgainst will be null, when called
// after transform it will be the annotation from before the transform
if
(
verifyAgainst
!=
null
)
{
assertTrue
(
anno
.
equals
(
verifyAgainst
),
"Annotations do not match before and after."
+
" Before: \""
+
verifyAgainst
+
"\", After: \""
+
anno
+
"\""
);
}
}
private
static
void
verifyTestAnnSite
(
Annotation
testAnn
,
String
expectedSite
)
{
String
expectedAnn
=
"@TestAnn(site="
+
expectedSite
+
")"
;
assertTrue
(
testAnn
.
toString
().
equals
(
expectedAnn
),
"Expected \""
+
expectedAnn
+
"\", got \""
+
testAnn
+
"\""
);
}
public
static
class
TypeAnnotatedTestClass
<
@TestAnn
(
site
=
"classTypeParameter"
)
S
,
T
>
extends
@TestAnn
(
site
=
"extends"
)
Thread
implements
@TestAnn
(
site
=
"implements"
)
Runnable
{
public
@TestAnn
(
site
=
"field"
)
boolean
typeAnnotatedBoolean
;
public
RedefineAnnotations
.
@TestAnn
(
site
=
"inner"
)
TypeAnnotatedTestClass
typeAnnotatedInner
;
public
@TestAnn
(
site
=
"array4"
)
boolean
@TestAnn
(
site
=
"array1"
)
[]
@TestAnn
(
site
=
"array2"
)
[]
@TestAnn
(
site
=
"array3"
)
[]
typeAnnotatedArray
;
public
@TestAnn
(
site
=
"map1"
)
Map
<
@TestAnn
(
site
=
"map2"
)
?
extends
@TestAnn
(
site
=
"map3"
)
String
,
@TestAnn
(
site
=
"map4"
)
List
<
@TestAnn
(
site
=
"map5"
)
Object
>>
typeAnnotatedMap
;
public
int
dummy1
;
public
int
dummy2
;
public
int
dummy3
;
@TestAnn
(
site
=
"return"
)
<
@TestAnn
(
site
=
"methodTypeParameter"
)
U
,
V
>
Class
typeAnnotatedMethod
(
@TestAnn
(
site
=
"formalParameter"
)
TypeAnnotatedTestClass
arg
)
throws
@TestAnn
(
site
=
"throws"
)
ClassNotFoundException
{
@TestAnn
(
site
=
"local_variable_type"
)
int
foo
=
0
;
throw
new
ClassNotFoundException
();
}
public
void
run
()
{}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录