Skip to content

Commit 74f047b

Browse files
committed
8356224: JFR: Default value of @registered is ignored
Reviewed-by: mgronlun
1 parent 97d2a37 commit 74f047b

File tree

3 files changed

+141
-40
lines changed

3 files changed

+141
-40
lines changed

src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ class AnnotationIterator : public StackObj {
369369
};
370370

371371
static const char value_name[] = "value";
372-
static bool has_annotation(const InstanceKlass* ik, const Symbol* annotation_type, bool& value) {
372+
static bool has_annotation(const InstanceKlass* ik, const Symbol* annotation_type, bool default_value, bool& value) {
373373
assert(annotation_type != nullptr, "invariant");
374374
AnnotationArray* class_annotations = ik->class_annotations();
375375
if (class_annotations == nullptr) {
@@ -385,6 +385,12 @@ static bool has_annotation(const InstanceKlass* ik, const Symbol* annotation_typ
385385
SymbolTable::probe(value_name, sizeof value_name - 1);
386386
assert(value_symbol != nullptr, "invariant");
387387
const AnnotationElementIterator element_iterator = annotation_iterator.elements();
388+
if (!element_iterator.has_next()) {
389+
// Default values are not stored in the annotation element, so if the
390+
// element-value pair is empty, return the default value.
391+
value = default_value;
392+
return true;
393+
}
388394
while (element_iterator.has_next()) {
389395
element_iterator.move_to_next();
390396
if (value_symbol == element_iterator.name()) {
@@ -402,15 +408,15 @@ static bool has_annotation(const InstanceKlass* ik, const Symbol* annotation_typ
402408
// Evaluate to the value of the first found Symbol* annotation type.
403409
// Searching moves upwards in the klass hierarchy in order to support
404410
// inherited annotations in addition to the ability to override.
405-
static bool annotation_value(const InstanceKlass* ik, const Symbol* annotation_type, bool& value) {
411+
static bool annotation_value(const InstanceKlass* ik, const Symbol* annotation_type, bool default_value, bool& value) {
406412
assert(ik != nullptr, "invariant");
407413
assert(annotation_type != nullptr, "invariant");
408414
assert(JdkJfrEvent::is_a(ik), "invariant");
409-
if (has_annotation(ik, annotation_type, value)) {
415+
if (has_annotation(ik, annotation_type, default_value, value)) {
410416
return true;
411417
}
412418
InstanceKlass* const super = InstanceKlass::cast(ik->super());
413-
return super != nullptr && JdkJfrEvent::is_a(super) ? annotation_value(super, annotation_type, value) : false;
419+
return super != nullptr && JdkJfrEvent::is_a(super) ? annotation_value(super, annotation_type, default_value, value) : false;
414420
}
415421

416422
static const char jdk_jfr_module_name[] = "jdk.jfr";
@@ -469,7 +475,7 @@ static bool should_register_klass(const InstanceKlass* ik, bool& untypedEventHan
469475
}
470476
assert(registered_symbol != nullptr, "invariant");
471477
bool value = false; // to be set by annotation_value
472-
untypedEventHandler = !(annotation_value(ik, registered_symbol, value) || java_base_can_read_jdk_jfr());
478+
untypedEventHandler = !(annotation_value(ik, registered_symbol, true, value) || java_base_can_read_jdk_jfr());
473479
return value;
474480
}
475481

src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.lang.classfile.AnnotationElement;
3131
import java.lang.classfile.AnnotationValue;
3232
import java.lang.classfile.Attribute;
33+
import java.lang.classfile.Attributes;
3334
import java.lang.classfile.ClassFile;
3435
import java.lang.classfile.ClassModel;
3536
import java.lang.classfile.FieldModel;
@@ -63,6 +64,7 @@ final class ClassInspector {
6364
private static final ClassDesc ANNOTATION_NAME = classDesc(Name.class);
6465
private static final ClassDesc ANNOTATION_ENABLED = classDesc(Enabled.class);
6566
private static final ClassDesc ANNOTATION_REMOVE_FIELDS = classDesc(RemoveFields.class);
67+
private static final String[] EMPTY_STRING_ARRAY = {};
6668

6769
private final ClassModel classModel;
6870
private final Class<?> superClass;
@@ -104,12 +106,12 @@ MethodDesc findStaticCommitMethod() {
104106
}
105107

106108
String getEventName() {
107-
String name = annotationValue(ANNOTATION_NAME, String.class);
109+
String name = annotationValue(ANNOTATION_NAME, String.class, null);
108110
return name == null ? getClassName() : name;
109111
}
110112

111113
boolean isRegistered() {
112-
Boolean result = annotationValue(ANNOTATION_REGISTERED, Boolean.class);
114+
Boolean result = annotationValue(ANNOTATION_REGISTERED, Boolean.class, true);
113115
if (result != null) {
114116
return result.booleanValue();
115117
}
@@ -123,7 +125,7 @@ boolean isRegistered() {
123125
}
124126

125127
boolean isEnabled() {
126-
Boolean result = annotationValue(ANNOTATION_ENABLED, Boolean.class);
128+
Boolean result = annotationValue(ANNOTATION_ENABLED, Boolean.class, true);
127129
if (result != null) {
128130
return result.booleanValue();
129131
}
@@ -201,52 +203,59 @@ private ImplicitFields determineImplicitFields() {
201203
}
202204
}
203205
ImplicitFields ifs = new ImplicitFields(superClass);
204-
String[] value = annotationValue(ANNOTATION_REMOVE_FIELDS, String[].class);
206+
String[] value = annotationValue(ANNOTATION_REMOVE_FIELDS, String[].class, EMPTY_STRING_ARRAY);
205207
if (value != null) {
206208
ifs.removeFields(value);
207209
}
208210
return ifs;
209211
}
210212

211-
private List<AnnotationValue> getAnnotationValues(ClassDesc classDesc) {
212-
List<AnnotationValue> list = new ArrayList<>();
213-
for (Attribute<?> attribute: classModel.attributes()) {
214-
if (attribute instanceof RuntimeVisibleAnnotationsAttribute rvaa) {
215-
for (Annotation a : rvaa.annotations()) {
216-
if (a.classSymbol().equals(classDesc) && a.elements().size() == 1) {
217-
AnnotationElement ae = a.elements().getFirst();
218-
if (ae.name().equalsString("value")) {
219-
list.add(ae.value());
220-
}
221-
}
213+
private Annotation getFirstAnnotation(ClassDesc classDesc) {
214+
for (RuntimeVisibleAnnotationsAttribute attribute : classModel.findAttributes(Attributes.runtimeVisibleAnnotations())) {
215+
for (Annotation a : attribute.annotations()) {
216+
if (a.classSymbol().equals(classDesc)) {
217+
return a;
222218
}
223219
}
224220
}
225-
return list;
221+
return null;
226222
}
227223

228224
@SuppressWarnings("unchecked")
229225
// Only supports String, String[] and Boolean values
230-
private <T> T annotationValue(ClassDesc classDesc, Class<T> type) {
231-
for (AnnotationValue a : getAnnotationValues(classDesc)) {
232-
if (a instanceof AnnotationValue.OfBoolean ofb && type.equals(Boolean.class)) {
233-
Boolean b = ofb.booleanValue();
234-
return (T) b;
235-
}
236-
if (a instanceof AnnotationValue.OfString ofs && type.equals(String.class)) {
237-
String s = ofs.stringValue();
238-
return (T) s;
239-
}
240-
if (a instanceof AnnotationValue.OfArray ofa && type.equals(String[].class)) {
241-
List<AnnotationValue> list = ofa.values();
242-
String[] array = new String[list.size()];
243-
int index = 0;
244-
for (AnnotationValue av : list) {
245-
var avs = (AnnotationValue.OfString) av;
246-
array[index++] = avs.stringValue();
247-
}
248-
return (T) array;
226+
private <T> T annotationValue(ClassDesc classDesc, Class<T> type, T defaultValue) {
227+
Annotation annotation = getFirstAnnotation(classDesc);
228+
if (annotation == null) {
229+
return null;
230+
}
231+
// Default values are not stored in the annotation element, so if the
232+
// element-value pair is empty, return the default value.
233+
if (annotation.elements().isEmpty()) {
234+
return defaultValue;
235+
}
236+
237+
AnnotationElement ae = annotation.elements().getFirst();
238+
if (!ae.name().equalsString("value")) {
239+
return null;
240+
}
241+
AnnotationValue a = ae.value();
242+
if (a instanceof AnnotationValue.OfBoolean ofb && type.equals(Boolean.class)) {
243+
Boolean b = ofb.booleanValue();
244+
return (T) b;
245+
}
246+
if (a instanceof AnnotationValue.OfString ofs && type.equals(String.class)) {
247+
String s = ofs.stringValue();
248+
return (T) s;
249+
}
250+
if (a instanceof AnnotationValue.OfArray ofa && type.equals(String[].class)) {
251+
List<AnnotationValue> list = ofa.values();
252+
String[] array = new String[list.size()];
253+
int index = 0;
254+
for (AnnotationValue av : list) {
255+
var avs = (AnnotationValue.OfString) av;
256+
array[index++] = avs.stringValue();
249257
}
258+
return (T) array;
250259
}
251260
return null;
252261
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package jdk.jfr.api.metadata.annotations;
25+
26+
import java.io.IOException;
27+
import java.util.List;
28+
29+
import jdk.jfr.Enabled;
30+
import jdk.jfr.Event;
31+
import jdk.jfr.Recording;
32+
import jdk.jfr.Registered;
33+
import jdk.jfr.consumer.RecordedEvent;
34+
import jdk.test.lib.jfr.Events;
35+
36+
/**
37+
* @test
38+
* @summary Tests that annotations can be overridden with the default value.
39+
* @requires vm.flagless
40+
* @requires vm.hasJFR
41+
* @library /test/lib
42+
* @run main/othervm jdk.jfr.api.metadata.annotations.TestOverrideWithDefaultValue
43+
*/
44+
public class TestOverrideWithDefaultValue {
45+
46+
@Enabled(false)
47+
static class Mammal extends Event {
48+
}
49+
50+
@Enabled
51+
static class Cat extends Mammal {
52+
}
53+
54+
@Registered(false)
55+
static class Animal extends Event {
56+
}
57+
58+
@Registered
59+
static class Dog extends Animal {
60+
}
61+
62+
public static void main(String[] args) throws IOException {
63+
testEnabled();
64+
testRegistered();
65+
}
66+
67+
private static void testEnabled() throws IOException {
68+
try (Recording r = new Recording()) {
69+
r.start();
70+
Cat cat = new Cat();
71+
cat.commit();
72+
List<RecordedEvent> events = Events.fromRecording(r);
73+
Events.hasEvents(events);
74+
}
75+
}
76+
77+
private static void testRegistered() throws IOException {
78+
try (Recording r = new Recording()) {
79+
r.start();
80+
Dog dog = new Dog();
81+
dog.commit();
82+
List<RecordedEvent> events = Events.fromRecording(r);
83+
Events.hasEvents(events);
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)