1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.generic;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertTrue;
21 import static org.junit.jupiter.api.Assertions.fail;
22
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.apache.bcel.AbstractTestCase;
28 import org.apache.bcel.Const;
29 import org.apache.bcel.classfile.AnnotationEntry;
30 import org.apache.bcel.classfile.ArrayElementValue;
31 import org.apache.bcel.classfile.ElementValue;
32 import org.apache.bcel.classfile.ElementValuePair;
33 import org.apache.bcel.classfile.JavaClass;
34 import org.apache.bcel.classfile.Method;
35 import org.apache.bcel.classfile.ParameterAnnotationEntry;
36 import org.apache.bcel.classfile.SimpleElementValue;
37 import org.apache.bcel.util.SyntheticRepository;
38 import org.junit.jupiter.api.Test;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class GeneratingAnnotatedClassesTestCase extends AbstractTestCase {
60 private void assertArrayElementValue(final int nExpectedArrayValues, final AnnotationEntry anno) {
61 final ElementValuePair elementValuePair = anno.getElementValuePairs()[0];
62 assertEquals("value", elementValuePair.getNameString());
63 final ArrayElementValue ev = (ArrayElementValue) elementValuePair.getValue();
64 final ElementValue[] eva = ev.getElementValuesArray();
65 assertEquals(nExpectedArrayValues, eva.length);
66 }
67
68 private void assertMethodAnnotations(final Method method, final int expectedNumberAnnotations, final int nExpectedArrayValues) {
69 final String methodName = method.getName();
70 final AnnotationEntry[] annos = method.getAnnotationEntries();
71 assertEquals(expectedNumberAnnotations, annos.length, () -> "For " + methodName);
72 if (expectedNumberAnnotations != 0) {
73 assertArrayElementValue(nExpectedArrayValues, annos[0]);
74 }
75 }
76
77 private void assertParameterAnnotations(final Method method, final int... expectedNumberOfParmeterAnnotations) {
78 final String methodName = "For " + method.getName();
79 final ParameterAnnotationEntry[] parameterAnnotations = method.getParameterAnnotationEntries();
80 assertEquals(expectedNumberOfParmeterAnnotations.length, parameterAnnotations.length, methodName);
81
82 int i = 0;
83 for (final ParameterAnnotationEntry parameterAnnotation : parameterAnnotations) {
84 final AnnotationEntry[] annos = parameterAnnotation.getAnnotationEntries();
85 final int expectedLength = expectedNumberOfParmeterAnnotations[i++];
86 final int j = i;
87 assertEquals(expectedLength, annos.length, () -> methodName + " parameter " + j);
88 if (expectedLength != 0) {
89 assertSimpleElementValue(annos[0]);
90 }
91 }
92 }
93
94 private void assertSimpleElementValue(final AnnotationEntry anno) {
95 final ElementValuePair elementValuePair = anno.getElementValuePairs()[0];
96 assertEquals("id", elementValuePair.getNameString());
97 final SimpleElementValue ev = (SimpleElementValue) elementValuePair.getValue();
98 assertEquals(42, ev.getValueInt());
99 }
100
101 private void buildClassContents(final ClassGen cg, final ConstantPoolGen cp, final InstructionList il) {
102
103 final MethodGen mg = createMethodGen("main", il, cp);
104 final InstructionFactory factory = new InstructionFactory(cg);
105
106 final ObjectType iStream = new ObjectType("java.io.InputStream");
107 final ObjectType pStream = new ObjectType("java.io.PrintStream");
108
109
110
111
112 il.append(factory.createNew("java.io.BufferedReader"));
113 il.append(InstructionConst.DUP);
114 il.append(factory.createNew("java.io.InputStreamReader"));
115 il.append(InstructionConst.DUP);
116 il.append(factory.createFieldAccess("java.lang.System", "in", iStream, Const.GETSTATIC));
117 il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", Type.VOID, new Type[] {iStream}, Const.INVOKESPECIAL));
118 il.append(factory.createInvoke("java.io.BufferedReader", "<init>", Type.VOID, new Type[] {new ObjectType("java.io.Reader")}, Const.INVOKESPECIAL));
119 LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType("java.io.BufferedReader"), null, null);
120 final int in = lg.getIndex();
121 lg.setStart(il.append(new ASTORE(in)));
122
123 lg = mg.addLocalVariable("name", Type.STRING, null, null);
124 final int name = lg.getIndex();
125 il.append(InstructionConst.ACONST_NULL);
126 lg.setStart(il.append(new ASTORE(name)));
127
128
129
130
131
132
133
134
135
136
137
138 final InstructionHandle tryStart = il.append(new PUSH(cp, "Andy"));
139 il.append(new ASTORE(name));
140
141
142 final GOTO g = new GOTO(null);
143 final InstructionHandle tryEnd = il.append(g);
144
145 final LocalVariableGen varEx = mg.addLocalVariable("ex", Type.getType("Ljava.io.IOException;"), null, null);
146 final int varExSlot = varEx.getIndex();
147 final InstructionHandle handler = il.append(new ASTORE(varExSlot));
148 varEx.setStart(handler);
149 varEx.setEnd(il.append(InstructionConst.RETURN));
150 mg.addExceptionHandler(tryStart, tryEnd, handler, new ObjectType("java.io.IOException"));
151
152
153 final InstructionHandle ih = il.append(factory.createFieldAccess("java.lang.System", "out", pStream, Const.GETSTATIC));
154 g.setTarget(ih);
155
156
157 il.append(factory.createNew(Type.STRINGBUFFER));
158 il.append(InstructionConst.DUP);
159 il.append(new PUSH(cp, "Hello, "));
160 il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID, new Type[] {Type.STRING}, Const.INVOKESPECIAL));
161 il.append(new ALOAD(name));
162 il.append(factory.createInvoke("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {Type.STRING}, Const.INVOKEVIRTUAL));
163 il.append(factory.createInvoke("java.lang.StringBuffer", "toString", Type.STRING, Type.NO_ARGS, Const.INVOKEVIRTUAL));
164 il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] {Type.STRING}, Const.INVOKEVIRTUAL));
165 il.append(InstructionConst.RETURN);
166
167
168
169 mg.setMaxStack();
170 mg.setMaxLocals();
171 cg.addMethod(mg.getMethod());
172 il.dispose();
173 cg.addEmptyConstructor(Const.ACC_PUBLIC);
174 }
175
176 private void buildClassContentsWithAnnotatedMethods(final ClassGen cg, final ConstantPoolGen cp, final InstructionList il) {
177
178 final MethodGen mg = createMethodGen("main", il, cp);
179 final InstructionFactory factory = new InstructionFactory(cg);
180 mg.addAnnotationEntry(createSimpleVisibleAnnotation(mg.getConstantPool()));
181
182 final ObjectType iStream = new ObjectType("java.io.InputStream");
183 final ObjectType pStream = new ObjectType("java.io.PrintStream");
184
185
186
187
188 il.append(factory.createNew("java.io.BufferedReader"));
189 il.append(InstructionConst.DUP);
190 il.append(factory.createNew("java.io.InputStreamReader"));
191 il.append(InstructionConst.DUP);
192 il.append(factory.createFieldAccess("java.lang.System", "in", iStream, Const.GETSTATIC));
193 il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", Type.VOID, new Type[] {iStream}, Const.INVOKESPECIAL));
194 il.append(factory.createInvoke("java.io.BufferedReader", "<init>", Type.VOID, new Type[] {new ObjectType("java.io.Reader")}, Const.INVOKESPECIAL));
195 LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType("java.io.BufferedReader"), null, null);
196 final int in = lg.getIndex();
197 lg.setStart(il.append(new ASTORE(in)));
198
199 lg = mg.addLocalVariable("name", Type.STRING, null, null);
200 final int name = lg.getIndex();
201 il.append(InstructionConst.ACONST_NULL);
202 lg.setStart(il.append(new ASTORE(name)));
203
204
205
206
207
208
209
210
211
212
213
214 final InstructionHandle tryStart = il.append(new PUSH(cp, "Andy"));
215 il.append(new ASTORE(name));
216
217
218 final GOTO g = new GOTO(null);
219 final InstructionHandle tryEnd = il.append(g);
220
221 final LocalVariableGen varEx = mg.addLocalVariable("ex", Type.getType("Ljava.io.IOException;"), null, null);
222 final int varExSlot = varEx.getIndex();
223 final InstructionHandle handler = il.append(new ASTORE(varExSlot));
224 varEx.setStart(handler);
225 varEx.setEnd(il.append(InstructionConst.RETURN));
226 mg.addExceptionHandler(tryStart, tryEnd, handler, new ObjectType("java.io.IOException"));
227
228
229 final InstructionHandle ih = il.append(factory.createFieldAccess("java.lang.System", "out", pStream, Const.GETSTATIC));
230 g.setTarget(ih);
231
232
233 il.append(factory.createNew(Type.STRINGBUFFER));
234 il.append(InstructionConst.DUP);
235 il.append(new PUSH(cp, "Hello, "));
236 il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID, new Type[] {Type.STRING}, Const.INVOKESPECIAL));
237 il.append(new ALOAD(name));
238 il.append(factory.createInvoke("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {Type.STRING}, Const.INVOKEVIRTUAL));
239 il.append(factory.createInvoke("java.lang.StringBuffer", "toString", Type.STRING, Type.NO_ARGS, Const.INVOKEVIRTUAL));
240 il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] {Type.STRING}, Const.INVOKEVIRTUAL));
241 il.append(InstructionConst.RETURN);
242
243
244
245 mg.setMaxStack();
246 mg.setMaxLocals();
247 cg.addMethod(mg.getMethod());
248 il.dispose();
249 cg.addEmptyConstructor(Const.ACC_PUBLIC);
250 }
251
252
253 private ClassGen createClassGen(final String className) {
254 return new ClassGen(className, "java.lang.Object", "<generated>", Const.ACC_PUBLIC | Const.ACC_SUPER, null);
255 }
256
257 public AnnotationEntryGen createCombinedAnnotation(final ConstantPoolGen cp) {
258
259 final AnnotationEntryGen a = createSimpleVisibleAnnotation(cp);
260 final ArrayElementValueGen array = new ArrayElementValueGen(cp);
261 array.addElement(new AnnotationElementValueGen(a, cp));
262 final ElementValuePairGen nvp = new ElementValuePairGen("value", array, cp);
263 final List<ElementValuePairGen> elements = new ArrayList<>();
264 elements.add(nvp);
265 return new AnnotationEntryGen(new ObjectType("CombinedAnnotation"), elements, true, cp);
266 }
267
268 public AnnotationEntryGen createFruitAnnotation(final ConstantPoolGen cp, final String aFruit) {
269 final SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.STRING, cp, aFruit);
270 final ElementValuePairGen nvGen = new ElementValuePairGen("fruit", evg, cp);
271 final ObjectType t = new ObjectType("SimpleStringAnnotation");
272 final List<ElementValuePairGen> elements = new ArrayList<>();
273 elements.add(nvGen);
274 return new AnnotationEntryGen(t, elements, true, cp);
275 }
276
277 private MethodGen createMethodGen(final String methodname, final InstructionList il, final ConstantPoolGen cp) {
278 return new MethodGen(Const.ACC_STATIC | Const.ACC_PUBLIC,
279
280 Type.VOID,
281 new Type[] {new ArrayType(Type.STRING, 1)},
282
283 new String[] {"argv"},
284 methodname, "HelloWorld",
285 il, cp);
286 }
287
288 public AnnotationEntryGen createSimpleInvisibleAnnotation(final ConstantPoolGen cp) {
289 final SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_INT, cp, 4);
290 final ElementValuePairGen nvGen = new ElementValuePairGen("id", evg, cp);
291 final ObjectType t = new ObjectType("SimpleAnnotation");
292 final List<ElementValuePairGen> elements = new ArrayList<>();
293 elements.add(nvGen);
294 return new AnnotationEntryGen(t, elements, false, cp);
295 }
296
297 public AnnotationEntryGen createSimpleVisibleAnnotation(final ConstantPoolGen cp) {
298 final SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.PRIMITIVE_INT, cp, 4);
299 final ElementValuePairGen nvGen = new ElementValuePairGen("id", evg, cp);
300 final ObjectType t = new ObjectType("SimpleAnnotation");
301 final List<ElementValuePairGen> elements = new ArrayList<>();
302 elements.add(nvGen);
303 return new AnnotationEntryGen(t, elements, true, cp);
304 }
305
306 private void dumpClass(final ClassGen cg, final String fname) {
307 try {
308 final File f = createTestdataFile(fname);
309 cg.getJavaClass().dump(f);
310 } catch (final java.io.IOException e) {
311 System.err.println(e);
312 }
313 }
314
315 private void dumpClass(final ClassGen cg, final String dir, final String fname) {
316 dumpClass(cg, dir + File.separator + fname);
317 }
318
319 private JavaClass getClassFrom(final String where, final String clazzname) throws ClassNotFoundException {
320
321 final SyntheticRepository repos = createRepos(where);
322 return repos.loadClass(clazzname);
323 }
324
325
326
327
328
329
330
331
332
333
334
335 @Test
336 public void testGenerateClassLevelAnnotations() throws ClassNotFoundException {
337
338 final ClassGen cg = createClassGen("HelloWorld");
339 cg.setMajor(49);
340 cg.setMinor(0);
341 final ConstantPoolGen cp = cg.getConstantPool();
342 final InstructionList il = new InstructionList();
343 cg.addAnnotationEntry(createSimpleVisibleAnnotation(cp));
344 cg.addAnnotationEntry(createSimpleInvisibleAnnotation(cp));
345 buildClassContents(cg, cp, il);
346
347 dumpClass(cg, "HelloWorld.class");
348 final JavaClass jc = getClassFrom(".", "HelloWorld");
349 final AnnotationEntry[] as = jc.getAnnotationEntries();
350 assertEquals(2, as.length, "Wrong number of AnnotationEntries");
351
352 assertEquals("LSimpleAnnotation;", as[0].getAnnotationType(), "Wrong name of annotation 1");
353 assertEquals("LSimpleAnnotation;", as[1].getAnnotationType(), "Wrong name of annotation 2");
354 final ElementValuePair[] vals = as[0].getElementValuePairs();
355 final ElementValuePair nvp = vals[0];
356 assertEquals("id", nvp.getNameString(), "Wrong name of element in SimpleAnnotation");
357 final ElementValue ev = nvp.getValue();
358 assertEquals(ElementValue.PRIMITIVE_INT, ev.getElementValueType(), "Wrong type of element value");
359 assertEquals("4", ev.stringifyValue(), "Wrong value of element");
360 assertTrue(createTestdataFile("HelloWorld.class").delete());
361 }
362
363
364
365
366 @Test
367 public void testGenerateMethodLevelAnnotations1() throws ClassNotFoundException {
368
369 final ClassGen cg = createClassGen("HelloWorld");
370 final ConstantPoolGen cp = cg.getConstantPool();
371 final InstructionList il = new InstructionList();
372 buildClassContentsWithAnnotatedMethods(cg, cp, il);
373
374 int i = cg.getMethods()[0].getAnnotationEntries().length;
375 assertEquals(1, i, "Wrong number of annotations of main method prior to dumping");
376 dumpClass(cg, "temp1" + File.separator + "HelloWorld.class");
377 final JavaClass jc2 = getClassFrom("temp1", "HelloWorld");
378
379 i = jc2.getMethods()[0].getAnnotationEntries().length;
380 assertEquals(1, i, "Wrong number of annotation on JavaClass");
381 final ClassGen cg2 = new ClassGen(jc2);
382
383 final Method[] m = cg2.getMethods();
384 i = m[0].getAnnotationEntries().length;
385 assertEquals(1, i, "Wrong number of annotations on the main 'Method'");
386 final FieldGenOrMethodGen mg = new MethodGen(m[0], cg2.getClassName(), cg2.getConstantPool());
387
388 i = mg.getAnnotationEntries().length;
389 assertEquals(1, i, "Wrong number of annotations on the main 'MethodGen'");
390
391 assertTrue(delete("temp1", "HelloWorld.class"));
392 }
393
394
395
396
397
398
399 @Test
400 public void testGenerateMethodLevelAnnotations2() throws ClassNotFoundException {
401
402 final ClassGen cg = createClassGen("HelloWorld");
403 final ConstantPoolGen cp = cg.getConstantPool();
404 final InstructionList il = new InstructionList();
405 buildClassContentsWithAnnotatedMethods(cg, cp, il);
406 dumpClass(cg, "temp2", "HelloWorld.class");
407 final JavaClass jc2 = getClassFrom("temp2", "HelloWorld");
408 final ClassGen cg2 = new ClassGen(jc2);
409
410 final Method mainMethod1 = jc2.getMethods()[0];
411 assertEquals(1, mainMethod1.getAnnotationEntries().length, "Wrong number of annotations of the 'Method'");
412 final MethodGen mainMethod2 = new MethodGen(mainMethod1, cg2.getClassName(), cg2.getConstantPool());
413 assertEquals(1, mainMethod2.getAnnotationEntries().length, "Wrong number of annotations of the 'MethodGen'");
414 final AnnotationEntryGen fruit = createFruitAnnotation(cg2.getConstantPool(), "Pear");
415 mainMethod2.addAnnotationEntry(fruit);
416 cg2.removeMethod(mainMethod1);
417 cg2.addMethod(mainMethod2.getMethod());
418 dumpClass(cg2, "temp3", "HelloWorld.class");
419 final JavaClass jc3 = getClassFrom("temp3", "HelloWorld");
420 final ClassGen cg3 = new ClassGen(jc3);
421 final Method mainMethod3 = cg3.getMethods()[1];
422 final int i = mainMethod3.getAnnotationEntries().length;
423 assertEquals(2, i, "Wrong number of annotations on the 'Method'");
424 mainMethod2.removeAnnotationEntry(fruit);
425 assertEquals(1, mainMethod2.getAnnotationEntries().length, "Wrong number of annotations on the 'MethodGen'");
426 mainMethod2.removeAnnotationEntries();
427 assertEquals(0, mainMethod2.getAnnotationEntries().length, 0, "Wrong number of annotations on the 'MethodGen'");
428 assertTrue(delete("temp2", "HelloWorld.class"));
429 assertTrue(delete("temp3", "HelloWorld.class"));
430 }
431
432
433
434
435 @Test
436 public void testModifyingClasses1() throws ClassNotFoundException {
437 final JavaClass jc = getTestJavaClass(PACKAGE_BASE_NAME + ".data.SimpleAnnotatedClass");
438 final ClassGen cgen = new ClassGen(jc);
439 final ConstantPoolGen cp = cgen.getConstantPool();
440 cgen.addAnnotationEntry(createFruitAnnotation(cp, "Pineapple"));
441 assertEquals(2, cgen.getAnnotationEntries().length, "Wrong number of annotations");
442 dumpClass(cgen, "SimpleAnnotatedClass.class");
443 assertTrue(delete("SimpleAnnotatedClass.class"));
444 }
445
446
447
448
449 @Test
450 public void testModifyingClasses2() throws ClassNotFoundException {
451 final JavaClass jc = getTestJavaClass(PACKAGE_BASE_NAME + ".data.SimpleAnnotatedClass");
452 final ClassGen cgen = new ClassGen(jc);
453 final ConstantPoolGen cp = cgen.getConstantPool();
454 cgen.addAnnotationEntry(createCombinedAnnotation(cp));
455 assertEquals(2, cgen.getAnnotationEntries().length, "Wrong number of annotations");
456 dumpClass(cgen, "SimpleAnnotatedClass.class");
457 final JavaClass jc2 = getClassFrom(".", "SimpleAnnotatedClass");
458 jc2.getAnnotationEntries();
459 assertTrue(delete("SimpleAnnotatedClass.class"));
460
461 }
462
463
464
465
466
467 @Test
468 public void testTransformClassToClassGen_ArrayAndAnnotationTypes() throws ClassNotFoundException {
469 final JavaClass jc = getTestJavaClass(PACKAGE_BASE_NAME + ".data.AnnotatedWithCombinedAnnotation");
470 final ClassGen cgen = new ClassGen(jc);
471
472 final AnnotationEntryGen[] annotations = cgen.getAnnotationEntries();
473 assertEquals(1, annotations.length, "Wrong number of annotations");
474 final AnnotationEntryGen a = annotations[0];
475 assertEquals(1, a.getValues().size(), "Wrong number of values for the annotation");
476 final ElementValuePairGen nvp = a.getValues().get(0);
477 final ElementValueGen value = nvp.getValue();
478 assertTrue(value instanceof ArrayElementValueGen, "Value should be ArrayElementValueGen but is " + value);
479 final ArrayElementValueGen arrayValue = (ArrayElementValueGen) value;
480 assertEquals(1, arrayValue.getElementValuesSize(), "Wrong size of the array");
481 final ElementValueGen innerValue = arrayValue.getElementValues().get(0);
482 assertTrue(innerValue instanceof AnnotationElementValueGen, "Value in the array should be AnnotationElementValueGen but is " + innerValue);
483 final AnnotationElementValueGen innerAnnotationValue = (AnnotationElementValueGen) innerValue;
484 assertEquals("L" + PACKAGE_BASE_SIG + "/data/SimpleAnnotation;", innerAnnotationValue.getAnnotation().getTypeSignature(), "Wrong type signature");
485
486
487 final Method[] methods = cgen.getMethods();
488 assertEquals(3, methods.length);
489 for (final Method method : methods) {
490 final String methodName = method.getName();
491 if (methodName.equals("<init>")) {
492 assertMethodAnnotations(method, 0, 1);
493 assertParameterAnnotations(method, 0, 1);
494 } else if (methodName.equals("methodWithArrayOfZeroAnnotations")) {
495 assertMethodAnnotations(method, 1, 0);
496 } else if (methodName.equals("methodWithArrayOfTwoAnnotations")) {
497 assertMethodAnnotations(method, 1, 2);
498 } else {
499 fail(() -> "unexpected method " + method.getName());
500 }
501 }
502 }
503
504
505
506
507
508 @Test
509 public void testTransformClassToClassGen_EnumType() throws ClassNotFoundException {
510 final JavaClass jc = getTestJavaClass(PACKAGE_BASE_NAME + ".data.AnnotatedWithEnumClass");
511 final ClassGen cgen = new ClassGen(jc);
512
513 final AnnotationEntryGen[] annotations = cgen.getAnnotationEntries();
514 assertEquals(1, annotations.length, "Wrong number of annotations");
515 }
516
517
518
519
520
521 @Test
522 public void testTransformClassToClassGen_SimpleTypes() throws ClassNotFoundException {
523 final JavaClass jc = getTestJavaClass(PACKAGE_BASE_NAME + ".data.SimpleAnnotatedClass");
524 final ClassGen cgen = new ClassGen(jc);
525
526 final AnnotationEntryGen[] annotations = cgen.getAnnotationEntries();
527 assertEquals(1, annotations.length, "Wrong number of annotations");
528 }
529
530
531
532
533 @Test
534 public void testTransformComplexClassToClassGen() throws ClassNotFoundException {
535 final JavaClass jc = getTestJavaClass(PACKAGE_BASE_NAME + ".data.ComplexAnnotatedClass");
536 final ClassGen cgen = new ClassGen(jc);
537
538 final AnnotationEntryGen[] annotations = cgen.getAnnotationEntries();
539 assertEquals(1, annotations.length, "Wrong number of annotations");
540 final List<?> l = annotations[0].getValues();
541 boolean found = false;
542 for (final Object name : l) {
543 final ElementValuePairGen element = (ElementValuePairGen) name;
544 if (element.getNameString().equals("dval") && element.getValue().stringifyValue().equals("33.4")) {
545 found = true;
546 }
547 }
548 assertTrue(found, "Did not find double annotation value with value 33.4");
549 }
550 }