Skip to content
Permalink
Browse files
7155: [JFR Writer] Complete the annotation handling code
Reviewed-by: hirt
  • Loading branch information
Jaroslav Bachorik authored and thegreystone committed Mar 16, 2021
1 parent e97d985 commit 20d87772049f3d97af5de3f673dabbe23d3d39f1
Showing with 559 additions and 109 deletions.
  1. +65 −0 ...rder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/AnnotationElementBuilderImpl.java
  2. +39 −6 ...k.jmc.flightrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/MetadataImpl.java
  3. +27 −1 ...recorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/TypeStructureBuilderImpl.java
  4. +20 −2 ...ghtrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/TypedFieldBuilderImpl.java
  5. +1 −1 ...jmc.flightrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/TypedFieldImpl.java
  6. +1 −1 ...jmc.flightrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/TypedValueImpl.java
  7. +7 −3 ...njdk.jmc.flightrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/TypesImpl.java
  8. +100 −0 ...order.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/api/AnnotatedElementBuilder.java
  9. +190 −13 ...jmc.flightrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/api/Annotation.java
  10. +70 −0 ...rder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/api/AnnotationElementBuilder.java
  11. +2 −2 ...enjdk.jmc.flightrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/api/Type.java
  12. +1 −21 ...recorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/api/TypeStructureBuilder.java
  13. +7 −44 ...ghtrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/api/TypedFieldBuilder.java
  14. +3 −5 ...lightrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/api/TypedFieldValue.java
  15. +3 −1 ...njdk.jmc.flightrecorder.writer/src/main/java/org/openjdk/jmc/flightrecorder/writer/api/Types.java
  16. +15 −5 ...jmc.flightrecorder.writer/src/test/java/org/openjdk/jmc/flightrecorder/writer/AnnotationTest.java
  17. +4 −1 ...c.flightrecorder.writer/src/test/java/org/openjdk/jmc/flightrecorder/writer/ChunkComplexTest.java
  18. +1 −1 ...rder.writer/src/test/java/org/openjdk/jmc/flightrecorder/writer/TypeStructureBuilderImplTest.java
  19. +3 −2 ...ecorder.writer/src/test/java/org/openjdk/jmc/flightrecorder/writer/TypedFieldBuilderImplTest.java
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Datadog, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The contents of this file are subject to the terms of either the Universal Permissive License
* v 1.0 as shown at http://oss.oracle.com/licenses/upl
*
* or the following license:
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.openjdk.jmc.flightrecorder.writer;

import org.openjdk.jmc.flightrecorder.writer.api.Annotation;
import org.openjdk.jmc.flightrecorder.writer.api.AnnotationElementBuilder;
import org.openjdk.jmc.flightrecorder.writer.api.Type;
import org.openjdk.jmc.flightrecorder.writer.api.TypedValue;
import org.openjdk.jmc.flightrecorder.writer.api.TypedValueBuilder;

import java.util.function.Consumer;

final class AnnotationElementBuilderImpl implements AnnotationElementBuilder {
private final Type type;

AnnotationElementBuilderImpl(Type type) {
this.type = type;
}

@Override
public AnnotationElementBuilder addArgument(String name, TypedValue value) {
return this;
}

@Override
public AnnotationElementBuilder addArgument(String name, Consumer<TypedValueBuilder> builderCallback) {
return this;
}

@Override
public Annotation build() {
return new Annotation(type, (String) null);
}
}
@@ -45,6 +45,8 @@

import org.openjdk.jmc.flightrecorder.writer.api.Annotation;
import org.openjdk.jmc.flightrecorder.writer.api.NamedType;
import org.openjdk.jmc.flightrecorder.writer.api.TypedFieldValue;
import org.openjdk.jmc.flightrecorder.writer.api.TypedValue;
import org.openjdk.jmc.flightrecorder.writer.api.Types;

/** JFR type repository class. */
@@ -328,8 +330,21 @@ private void storeTypeStrings(TypeImpl type) {

private void storeAnnotationStrings(List<Annotation> annotations) {
for (Annotation annotation : annotations) {
if (annotation.getValue() != null) {
storeString(annotation.getValue());
for (Map.Entry<String, ? extends TypedFieldValue> entry : annotation.getAttributes().entrySet()) {
TypedFieldValue typedValue = entry.getValue();
// value arrays are encoded as 'attributeName-N' where N starts at 0
if (typedValue.getField().isArray()) {
TypedValue[] vals = typedValue.getValues();
for (int i = 0; i < vals.length; i++) {
TypedValue val = vals[i];
storeString(entry.getKey() + "-" + i);
storeString(Objects.toString(val.getValue()));
}
} else {
Object val = typedValue.getValue() != null ? typedValue.getValue().getValue() : null;
storeString(entry.getKey());
storeString(Objects.toString(val));
}
}
}
}
@@ -457,10 +472,28 @@ private void writeFieldAnnotations(LEB128Writer writer, TypedFieldImpl field) {
private void writeAnnotation(LEB128Writer writer, Annotation annotation) {
writer.writeInt(stringIndex(ANNOTATION_KEY));

writer.writeInt(annotation.getValue() != null ? 2 : 1) // number of attributes
.writeInt(stringIndex(CLASS_KEY)).writeInt(stringIndex(String.valueOf(annotation.getType().getId())));
if (annotation.getValue() != null) {
writer.writeInt(stringIndex(VALUE_KEY)).writeInt(stringIndex(annotation.getValue()));
int len = 1 + annotation.getAttributes().size();
for (TypedFieldValue value : annotation.getAttributes().values()) {
if (value.getField().isArray()) {
len += (value.getValues().length - 1); // add the number of synthetic attributes and remove the base one
}
}
writer.writeInt(len).writeInt(stringIndex(CLASS_KEY))
.writeInt(stringIndex(String.valueOf(annotation.getType().getId())));
for (Map.Entry<String, ? extends TypedFieldValue> entry : annotation.getAttributes().entrySet()) {
TypedFieldValue typedValue = entry.getValue();
if (typedValue.getField().isArray()) {
// value arrays are encoded as 'attributeName-N' where N starts at 0
TypedValue[] vals = typedValue.getValues();
for (int i = 0; i < vals.length; i++) {
TypedValue val = vals[i];
writer.writeInt(stringIndex(entry.getKey() + "-" + i))
.writeInt(stringIndex(Objects.toString(val.getValue())));
}
} else {
Object val = typedValue.getValue() != null ? typedValue.getValue().getValue() : null;
writer.writeInt(stringIndex(entry.getKey())).writeInt(stringIndex(Objects.toString(val)));
}
}
writer.writeInt(0); // no sub-elements
}
@@ -39,6 +39,7 @@
import org.openjdk.jmc.flightrecorder.writer.api.Type;
import org.openjdk.jmc.flightrecorder.writer.api.TypedField;
import org.openjdk.jmc.flightrecorder.writer.api.TypedFieldBuilder;
import org.openjdk.jmc.flightrecorder.writer.api.TypedValueBuilder;
import org.openjdk.jmc.flightrecorder.writer.api.Types;

import java.util.ArrayList;
@@ -98,7 +99,7 @@ public TypeStructureBuilder addFields(TypedField field1, TypedField field2, Type

@Override
public TypeStructureBuilderImpl addAnnotation(Type type) {
return addAnnotation(type, null);
return addAnnotation(type, (String) null);
}

@Override
@@ -107,6 +108,31 @@ public TypeStructureBuilderImpl addAnnotation(Type type, String value) {
return this;
}

@Override
public TypeStructureBuilderImpl addAnnotation(Types.Predefined type) {
return addAnnotation(types.getType(type));
}

@Override
public TypeStructureBuilderImpl addAnnotation(Types.Predefined type, String value) {
return addAnnotation(types.getType(type), value);
}

@Override
public TypeStructureBuilderImpl addAnnotation(Type type, Consumer<TypedValueBuilder> builderCallback) {
TypedValueBuilderImpl impl = new TypedValueBuilderImpl((TypeImpl) type);
if (builderCallback != null) {
builderCallback.accept(impl);
}
annotations.add(new Annotation(type, impl.build()));
return this;
}

@Override
public TypeStructureBuilderImpl addAnnotation(Types.Predefined type, Consumer<TypedValueBuilder> builderCallback) {
return addAnnotation(types.getType(type), builderCallback);
}

@Override
public Type selfType() {
return SelfType.INSTANCE;
@@ -36,9 +36,12 @@
import org.openjdk.jmc.flightrecorder.writer.api.Annotation;
import org.openjdk.jmc.flightrecorder.writer.api.Type;
import org.openjdk.jmc.flightrecorder.writer.api.TypedFieldBuilder;
import org.openjdk.jmc.flightrecorder.writer.api.TypedValueBuilder;
import org.openjdk.jmc.flightrecorder.writer.api.Types;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

final class TypedFieldBuilderImpl implements TypedFieldBuilder {
private final TypesImpl types;
@@ -55,7 +58,7 @@

@Override
public TypedFieldBuilderImpl addAnnotation(Type type) {
return addAnnotation(type, null);
return addAnnotation(type, (String) null);
}

@Override
@@ -70,10 +73,25 @@ public TypedFieldBuilderImpl addAnnotation(TypesImpl.Predefined type) {
}

@Override
public TypedFieldBuilderImpl addAnnotation(TypesImpl.Predefined type, String value) {
public TypedFieldBuilderImpl addAnnotation(Types.Predefined type, String value) {
return addAnnotation(types.getType(type), value);
}

@Override
public TypedFieldBuilder addAnnotation(Type type, Consumer<TypedValueBuilder> builderCallback) {
TypedValueBuilderImpl impl = new TypedValueBuilderImpl((TypeImpl) type);
if (builderCallback != null) {
builderCallback.accept(impl);
}
annotations.add(new Annotation(type, impl.build()));
return this;
}

@Override
public TypedFieldBuilder addAnnotation(Types.Predefined type, Consumer<TypedValueBuilder> builderCallback) {
return addAnnotation(types.getType(type), builderCallback);
}

@Override
public TypedFieldBuilderImpl asArray() {
asArray = true;
@@ -49,7 +49,7 @@
private final boolean isArray;
private final List<Annotation> annotations;

TypedFieldImpl(TypeImpl type, String name) {
public TypedFieldImpl(TypeImpl type, String name) {
this(type, name, false, Collections.emptyList());
}

@@ -44,7 +44,7 @@
import java.util.Objects;
import java.util.function.Consumer;

final class TypedValueImpl implements TypedValue {
public final class TypedValueImpl implements TypedValue {
private int hashcode = 0;

private final TypeImpl type;
@@ -85,19 +85,23 @@ private void registerJdkTypes() {
});
getOrAdd(JDK.ANNOTATION_TIMESTAMP, ANNOTATION_SUPER_TYPE_NAME, builder -> {
builder.addField("value", Builtin.STRING).addAnnotation(annotationNameType, "jdk.jfr.Timestamp")
.addAnnotation(annotationContentTypeType, null).addAnnotation(annotationLabelType, "Timestamp")
.addAnnotation(annotationContentTypeType).addAnnotation(annotationLabelType, "Timestamp")
.addAnnotation(annotationDescriptionType, "A point in time");
});
getOrAdd(JDK.ANNOTATION_TIMESPAN, ANNOTATION_SUPER_TYPE_NAME, builder -> {
builder.addField("value", Builtin.STRING).addAnnotation(annotationNameType, "jdk.jfr.Timespan")
.addAnnotation(annotationContentTypeType, null).addAnnotation(annotationLabelType, "Timespan")
.addAnnotation(annotationContentTypeType).addAnnotation(annotationLabelType, "Timespan")
.addAnnotation(annotationDescriptionType, "A duration, measured in nanoseconds by default");
});
getOrAdd(JDK.ANNOTATION_UNSIGNED, ANNOTATION_SUPER_TYPE_NAME, builder -> {
builder.addField("value", Builtin.STRING).addAnnotation(annotationNameType, "jdk.jfr.Unsigned")
.addAnnotation(annotationContentTypeType, null).addAnnotation(annotationLabelType, "Unsigned value")
.addAnnotation(annotationContentTypeType).addAnnotation(annotationLabelType, "Unsigned value")
.addAnnotation(annotationDescriptionType, "Value should be interpreted as unsigned data type");
});
getOrAdd(JDK.ANNOTATION_CATEGORY, ANNOTATION_SUPER_TYPE_NAME, builder -> {
builder.addField("value", STRING, TypedFieldBuilder::asArray).addAnnotation(annotationNameType,
"jdk.jfr.Category");
});

getOrAdd(JDK.TICKSPAN, builder -> {
builder.addField("tickSpan", Builtin.LONG);
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Datadog, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The contents of this file are subject to the terms of either the Universal Permissive License
* v 1.0 as shown at http://oss.oracle.com/licenses/upl
*
* or the following license:
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.openjdk.jmc.flightrecorder.writer.api;

import java.util.function.Consumer;

public interface AnnotatedElementBuilder<T extends AnnotatedElementBuilder<?>> {
/**
* Add an annotation of the given type
*
* @param type
* the annotation type
* @return a {@linkplain AnnotatedElementBuilder} instance for invocation chaining
*/
T addAnnotation(Type type);

/**
* Add an annotation of the given type and with the given value
*
* @param type
* the annotation type
* @param value
* the annotation value
* @return a {@linkplain AnnotatedElementBuilder} instance for invocation chaining
*/
T addAnnotation(Type type, String value);

/**
* Add a predefined annotation
*
* @param type
* predefined annotation type
* @return a {@linkplain AnnotatedElementBuilder} instance for invocation chaining
*/
T addAnnotation(Types.Predefined type);

/**
* Add a predefined annotation with a value
*
* @param type
* predefined annotation type
* @param value
* annotation value
* @return a {@linkplain AnnotatedElementBuilder} instance for invocation chaining
*/
T addAnnotation(Types.Predefined type, String value);

/**
* Add an annotation of the given type and with the given values array
*
* @param type
* the annotation type
* @param builderCallback
* the annotation attributes builder callback
* @return a {@linkplain AnnotatedElementBuilder} instance for invocation chaining
*/
T addAnnotation(Type type, Consumer<TypedValueBuilder> builderCallback);

/**
* Add an annotation of the given type and with the given values array
*
* @param type
* the annotation type
* @param builderCallback
* the annotation attributes builder callback
* @return a {@linkplain AnnotatedElementBuilder} instance for invocation chaining
*/
T addAnnotation(Types.Predefined type, Consumer<TypedValueBuilder> builderCallback);
}

0 comments on commit 20d8777

Please sign in to comment.