Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 51 additions & 30 deletions sdk-extensions/declarative-config/build.gradle.kts
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the changes you really want to review. The shape of the pojos themselves are the result of the jsonschema2pojo config defined in this file.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ plugins {
}

description = "OpenTelemetry SDK Declarative Config"
otelJava.moduleName.set("io.opentelemetry.sdk.declarativeconfig")
otelJava.moduleName.set("io.opentelemetry.sdk.autoconfigure.declarativeconfig")

dependencies {
api(project(":sdk:all"))
Expand Down Expand Up @@ -39,15 +39,15 @@ dependencies {
testImplementation("com.google.guava:guava-testlib")
}

// The following tasks download the JSON Schema files from open-telemetry/opentelemetry-configuration and generate classes from the type definitions which are used with jackson-databind to parse JSON / YAML to the configuration schema.
// The following tasks download the JSON Schema files from open-telemetry/opentelemetry-configuration,
// generate POJOs, and write the post-processed result into src/main/java for version control.
// The sequence of tasks is:
// 1. downloadConfigurationSchema - download configuration schema from open-telemetry/opentelemetry-configuration
// 2. unzipConfigurationSchema - unzip the configuration schema archive contents to $buildDir/configuration/
// 3. generateJsonSchema2Pojo - generate java POJOs from the configuration schema
// 4. jsonSchema2PojoPostProcessing - perform various post processing on the generated POJOs, e.g. replace javax.annotation.processing.Generated with javax.annotation.Generated, add @SuppressWarning("rawtypes") annotation
// 5. overwriteJs2p - overwrite original generated classes with versions containing updated @Generated annotation
// 6. deleteJs2pTmp - delete tmp directory
// ... proceed with normal sourcesJar, compileJava, etc
// 4. syncPojoModelsToSrc - post-process the generated POJOs and write them to src/main/java
// The generated POJOs are committed to src/main/java and are NOT regenerated as part of the normal build.
// To regenerate (e.g. after a schema update), run: ./gradlew :sdk-extensions:declarative-config:syncPojoModelsToSrc

val configurationTag = "1.0.0"
val configurationRef = "refs/tags/v$configurationTag" // Replace with commit SHA to point to experiment with a specific commit
Expand Down Expand Up @@ -90,8 +90,8 @@ jsonSchema2Pojo {
// Clear old source files to avoid contaminated source dir when updating
removeOldOutput = true

// Include @Nullable annotation. Note: jsonSchmea2Pojo will not add @Nullable annotations on getters
// so we perform some steps in jsonSchema2PojoPostProcessing to add these.
// Include @Nullable annotation. Note: jsonSchema2Pojo will not add @Nullable annotations on getters
// so we add these in syncPojoModelsToSrc.
includeJsr305Annotations = true

// Prefer builders to setters
Expand All @@ -118,34 +118,34 @@ jsonSchema2Pojo {
val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo")
generateJsonSchema2Pojo.dependsOn(unzipConfigurationSchema)

val jsonSchema2PojoPostProcessing by tasks.registering(Copy::class) {
val syncPojoModelsToSrc by tasks.registering(Copy::class) {
dependsOn(generateJsonSchema2Pojo)
finalizedBy("spotlessApply")

from("$buildDirectory/generated/sources/js2p")
into("$buildDirectory/generated/sources/js2p-tmp")
from("$buildDirectory/generated/sources/js2p/java/main")
into("$projectDir/src/main/java")
filter {
it
// Shorten FQCNs for same-package references generated by jsonschema2pojo
.replace("io.opentelemetry.sdk.autoconfigure.declarativeconfig.model.", "")
// Remove @Nullable annotation so it can be deterministically added later
.replace("import javax.annotation.Nullable;\n", "")
// Replace java 9+ @Generated annotation with java 8 version, add @Nullable annotation
.replace("import javax.annotation.processing.Generated;", "import javax.annotation.Nullable;\nimport javax.annotation.Generated;")
// Add @SuppressWarnings("rawtypes") annotation to address raw types used in jsonschema2pojo builders
.replace("@Generated(\"jsonschema2pojo\")", "@Generated(\"jsonschema2pojo\")\n@SuppressWarnings(\"rawtypes\")")
// Add @Nullable annotations to all getters
.replace("( *)public ([a-zA-Z]*) get([a-zA-Z]*)".toRegex(), "$1@Nullable\n$1public $2 get$3")
// Add @SuppressWarnings annotations for issues inherent in jsonschema2pojo-generated code:
// "rawtypes" - raw types used in builders
// "NullAway" - uninitialized @NonNull fields on Jackson-deserialized POJOs
// TODO(jack-berg): investigate jsonschema2pojo config to avoid @Nonnull on fields / generate initializing constructors
// "BoxedPrimitiveEquality" - == comparison of boxed primitives in generated equals()
// TODO(jack-berg): investigate jsonschema2pojo config for alternative equals implementation that avoids boxed primitives comparison
.replace(
"@Generated(\"jsonschema2pojo\")",
"@Generated(\"jsonschema2pojo\")\n@SuppressWarnings({\"NullAway\", \"rawtypes\", \"BoxedPrimitiveEquality\"})"
)
// Add @Nullable annotations to all getters (except getAdditionalProperties which is non-null)
.replace("( *)public (.+) get(?!AdditionalProperties)([a-zA-Z]*)".toRegex(), "$1@Nullable\n$1public $2 get$3")
}
}
val overwriteJs2p by tasks.registering(Copy::class) {
dependsOn(jsonSchema2PojoPostProcessing)

from("$buildDirectory/generated/sources/js2p-tmp")
into("$buildDirectory/generated/sources/js2p")
}
val deleteJs2pTmp by tasks.registering(Delete::class) {
dependsOn(overwriteJs2p)

delete("$buildDirectory/generated/sources/js2p-tmp/")
}

// Copies EnvironmentResource.java from the autoconfigure module into a generated source set so
// that declarative config can use the exact same source without taking a runtime dependency on
Expand Down Expand Up @@ -176,6 +176,19 @@ sourceSets {
}
}

afterEvaluate {
// The jsonschema2pojo plugin auto-adds its targetDirectory to the main source set. Remove it so
// that only the committed model POJOs in src/main/java are compiled, avoiding duplicate classes.
val js2pDir = File(buildDirectory, "generated/sources/js2p/java/main")
sourceSets {
main {
java {
setSrcDirs(srcDirs.filter { it != js2pDir })
}
}
}
}

val buildGraalVmReflectionJson = tasks.register("buildGraalVmReflectionJson") {
val buildDir = buildDirectory
val targetFile = File(
Expand Down Expand Up @@ -232,20 +245,28 @@ val buildGraalVmReflectionJson = tasks.register("buildGraalVmReflectionJson") {
}
}

tasks.getByName("compileJava").dependsOn(deleteJs2pTmp, copyResourceConfiguration)
tasks.getByName("sourcesJar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson, copyResourceConfiguration)
tasks.getByName("jar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson)
tasks.getByName("compileJava").dependsOn(copyResourceConfiguration)
tasks.getByName("sourcesJar").dependsOn(buildGraalVmReflectionJson, copyResourceConfiguration)
tasks.getByName("jar").dependsOn(buildGraalVmReflectionJson)
tasks.getByName("javadoc").dependsOn(buildGraalVmReflectionJson)
tasks.getByName("compileTestJava").dependsOn(buildGraalVmReflectionJson)

// Exclude jsonschema2pojo generated sources from checkstyle
// When syncPojoModelsToSrc runs it writes to src/main/java. Both spotlessJava and spotlessMisc
// declare the module directory as an input region, so Gradle requires ordering to be explicit.
// mustRunAfter satisfies the implicit-dependency validator without making spotless depend on
// generation during normal builds.
tasks.named("spotlessJava") { mustRunAfter(syncPojoModelsToSrc) }
tasks.named("spotlessMisc") { mustRunAfter(syncPojoModelsToSrc) }

// Exclude committed generated POJO sources from checkstyle
tasks.named<Checkstyle>("checkstyleMain") {
dependsOn(buildGraalVmReflectionJson)
exclude("**/declarativeconfig/model/**")
}

tasks {
withType<Test>().configureEach {
dependsOn(unzipConfigurationSchema)
environment(
mapOf(
// Expose the kitchen sink example file to tests
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.autoconfigure.declarativeconfig.model;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import javax.annotation.Generated;
import javax.annotation.Nullable;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"default",
"drop",
"explicit_bucket_histogram",
"base2_exponential_bucket_histogram",
"last_value",
"sum"
})
@Generated("jsonschema2pojo")
@SuppressWarnings({"NullAway", "rawtypes", "BoxedPrimitiveEquality"})
public class AggregationModel {

/** (Can be null) */
@Nullable
@JsonProperty("default")
private DefaultAggregationModel _default;

/** (Can be null) */
@Nullable
@JsonProperty("drop")
private DropAggregationModel drop;

/** (Can be null) */
@Nullable
@JsonProperty("explicit_bucket_histogram")
private ExplicitBucketHistogramAggregationModel explicitBucketHistogram;

/** (Can be null) */
@Nullable
@JsonProperty("base2_exponential_bucket_histogram")
private Base2ExponentialBucketHistogramAggregationModel base2ExponentialBucketHistogram;

/** (Can be null) */
@Nullable
@JsonProperty("last_value")
private LastValueAggregationModel lastValue;

/** (Can be null) */
@Nullable
@JsonProperty("sum")
private SumAggregationModel sum;

@JsonProperty("default")
@Nullable
public DefaultAggregationModel getDefault() {
return _default;
}

public AggregationModel withDefault(DefaultAggregationModel _default) {
this._default = _default;
return this;
}

@JsonProperty("drop")
@Nullable
public DropAggregationModel getDrop() {
return drop;
}

public AggregationModel withDrop(DropAggregationModel drop) {
this.drop = drop;
return this;
}

@JsonProperty("explicit_bucket_histogram")
@Nullable
public ExplicitBucketHistogramAggregationModel getExplicitBucketHistogram() {
return explicitBucketHistogram;
}

public AggregationModel withExplicitBucketHistogram(
ExplicitBucketHistogramAggregationModel explicitBucketHistogram) {
this.explicitBucketHistogram = explicitBucketHistogram;
return this;
}

@JsonProperty("base2_exponential_bucket_histogram")
@Nullable
public Base2ExponentialBucketHistogramAggregationModel getBase2ExponentialBucketHistogram() {
return base2ExponentialBucketHistogram;
}

public AggregationModel withBase2ExponentialBucketHistogram(
Base2ExponentialBucketHistogramAggregationModel base2ExponentialBucketHistogram) {
this.base2ExponentialBucketHistogram = base2ExponentialBucketHistogram;
return this;
}

@JsonProperty("last_value")
@Nullable
public LastValueAggregationModel getLastValue() {
return lastValue;
}

public AggregationModel withLastValue(LastValueAggregationModel lastValue) {
this.lastValue = lastValue;
return this;
}

@JsonProperty("sum")
@Nullable
public SumAggregationModel getSum() {
return sum;
}

public AggregationModel withSum(SumAggregationModel sum) {
this.sum = sum;
return this;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(AggregationModel.class.getName())
.append('@')
.append(Integer.toHexString(System.identityHashCode(this)))
.append('[');
sb.append("_default");
sb.append('=');
sb.append(((this._default == null) ? "<null>" : this._default));
sb.append(',');
sb.append("drop");
sb.append('=');
sb.append(((this.drop == null) ? "<null>" : this.drop));
sb.append(',');
sb.append("explicitBucketHistogram");
sb.append('=');
sb.append(((this.explicitBucketHistogram == null) ? "<null>" : this.explicitBucketHistogram));
sb.append(',');
sb.append("base2ExponentialBucketHistogram");
sb.append('=');
sb.append(
((this.base2ExponentialBucketHistogram == null)
? "<null>"
: this.base2ExponentialBucketHistogram));
sb.append(',');
sb.append("lastValue");
sb.append('=');
sb.append(((this.lastValue == null) ? "<null>" : this.lastValue));
sb.append(',');
sb.append("sum");
sb.append('=');
sb.append(((this.sum == null) ? "<null>" : this.sum));
sb.append(',');
if (sb.charAt((sb.length() - 1)) == ',') {
sb.setCharAt((sb.length() - 1), ']');
} else {
sb.append(']');
}
return sb.toString();
}

@Override
public int hashCode() {
int result = 1;
result = ((result * 31) + ((this.drop == null) ? 0 : this.drop.hashCode()));
result =
((result * 31)
+ ((this.explicitBucketHistogram == null)
? 0
: this.explicitBucketHistogram.hashCode()));
result = ((result * 31) + ((this._default == null) ? 0 : this._default.hashCode()));
result = ((result * 31) + ((this.lastValue == null) ? 0 : this.lastValue.hashCode()));
result = ((result * 31) + ((this.sum == null) ? 0 : this.sum.hashCode()));
result =
((result * 31)
+ ((this.base2ExponentialBucketHistogram == null)
? 0
: this.base2ExponentialBucketHistogram.hashCode()));
return result;
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if ((other instanceof AggregationModel) == false) {
return false;
}
AggregationModel rhs = ((AggregationModel) other);
return (((((((this.drop == rhs.drop) || ((this.drop != null) && this.drop.equals(rhs.drop)))
&& ((this.explicitBucketHistogram == rhs.explicitBucketHistogram)
|| ((this.explicitBucketHistogram != null)
&& this.explicitBucketHistogram.equals(
rhs.explicitBucketHistogram))))
&& ((this._default == rhs._default)
|| ((this._default != null) && this._default.equals(rhs._default))))
&& ((this.lastValue == rhs.lastValue)
|| ((this.lastValue != null) && this.lastValue.equals(rhs.lastValue))))
&& ((this.sum == rhs.sum) || ((this.sum != null) && this.sum.equals(rhs.sum))))
&& ((this.base2ExponentialBucketHistogram == rhs.base2ExponentialBucketHistogram)
|| ((this.base2ExponentialBucketHistogram != null)
&& this.base2ExponentialBucketHistogram.equals(
rhs.base2ExponentialBucketHistogram))));
}
}
Loading
Loading