Skip to content

Commit a5cd87f

Browse files
authored
Commit declarative config schema pojos to git (#8408)
1 parent 327f564 commit a5cd87f

117 files changed

Lines changed: 15402 additions & 29 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.codecov.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ coverage:
1515
paths:
1616
- "!opencensus-shim/"
1717
- "!opentracing-shim/"
18+
# exclude declarative config generated POJOs
19+
- "!sdk-extensions/declarative-config/src/main/java/io/opentelemetry/sdk/autoconfigure/declarativeconfig/model/"
1820
unmaintained:
1921
target: 80%
2022
paths:

sdk-extensions/declarative-config/build.gradle.kts

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ dependencies {
4949
testImplementation("com.google.guava:guava-testlib")
5050
}
5151

52-
// 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.
52+
// The following tasks download the JSON Schema files from open-telemetry/opentelemetry-configuration,
53+
// generate POJOs, and write the post-processed result into src/main/java for version control.
5354
// The sequence of tasks is:
5455
// 1. downloadConfigurationSchema - download configuration schema from open-telemetry/opentelemetry-configuration
5556
// 2. unzipConfigurationSchema - unzip the configuration schema archive contents to $buildDir/configuration/
5657
// 3. generateJsonSchema2Pojo - generate java POJOs from the configuration schema
57-
// 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
58-
// 5. overwriteJs2p - overwrite original generated classes with versions containing updated @Generated annotation
59-
// 6. deleteJs2pTmp - delete tmp directory
60-
// ... proceed with normal sourcesJar, compileJava, etc
58+
// 4. syncPojoModelsToSrc - post-process the generated POJOs and write them to src/main/java
59+
// The generated POJOs are committed to src/main/java and are NOT regenerated as part of the normal build.
60+
// To regenerate (e.g. after a schema update), run: ./gradlew :sdk-extensions:declarative-config:syncPojoModelsToSrc
6161

6262
val configurationTag = "1.0.0"
6363
val configurationRef = "refs/tags/v$configurationTag" // Replace with commit SHA to point to experiment with a specific commit
@@ -100,8 +100,8 @@ jsonSchema2Pojo {
100100
// Clear old source files to avoid contaminated source dir when updating
101101
removeOldOutput = true
102102

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

107107
// Prefer builders to setters
@@ -128,34 +128,42 @@ jsonSchema2Pojo {
128128
val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo")
129129
generateJsonSchema2Pojo.dependsOn(unzipConfigurationSchema)
130130

131-
val jsonSchema2PojoPostProcessing by tasks.registering(Copy::class) {
131+
val syncPojoModelsToSrc by tasks.registering(Copy::class) {
132132
dependsOn(generateJsonSchema2Pojo)
133+
finalizedBy("spotlessApply")
134+
val modelDir = File(projectDir, "src/main/java/io/opentelemetry/sdk/autoconfigure/declarativeconfig/model")
135+
doFirst {
136+
require(JavaVersion.current() == JavaVersion.VERSION_21) {
137+
"syncPojoModelsToSrc requires Java 21 (current: ${JavaVersion.current()}). jsonschema2pojo output is JVM-version-sensitive; using the wrong version produces spurious diffs."
138+
}
139+
// Copy won't remove files that no longer exist in the source. Delete first so schema type removals don't leave stale classes.
140+
modelDir.deleteRecursively()
141+
}
133142

134-
from("$buildDirectory/generated/sources/js2p")
135-
into("$buildDirectory/generated/sources/js2p-tmp")
143+
from("$buildDirectory/generated/sources/js2p/java/main")
144+
into("$projectDir/src/main/java")
136145
filter {
137146
it
147+
// Shorten FQCNs for same-package references generated by jsonschema2pojo
148+
.replace("io.opentelemetry.sdk.autoconfigure.declarativeconfig.model.", "")
138149
// Remove @Nullable annotation so it can be deterministically added later
139150
.replace("import javax.annotation.Nullable;\n", "")
140151
// Replace java 9+ @Generated annotation with java 8 version, add @Nullable annotation
141152
.replace("import javax.annotation.processing.Generated;", "import javax.annotation.Nullable;\nimport javax.annotation.Generated;")
142-
// Add @SuppressWarnings("rawtypes") annotation to address raw types used in jsonschema2pojo builders
143-
.replace("@Generated(\"jsonschema2pojo\")", "@Generated(\"jsonschema2pojo\")\n@SuppressWarnings(\"rawtypes\")")
144-
// Add @Nullable annotations to all getters
145-
.replace("( *)public ([a-zA-Z]*) get([a-zA-Z]*)".toRegex(), "$1@Nullable\n$1public $2 get$3")
153+
// Add @SuppressWarnings annotations for issues inherent in jsonschema2pojo-generated code:
154+
// "rawtypes" - raw types used in builders
155+
// "NullAway" - uninitialized @NonNull fields on Jackson-deserialized POJOs
156+
// TODO(jack-berg): investigate jsonschema2pojo config to avoid @Nonnull on fields / generate initializing constructors
157+
// "BoxedPrimitiveEquality" - == comparison of boxed primitives in generated equals()
158+
// TODO(jack-berg): investigate jsonschema2pojo config for alternative equals implementation that avoids boxed primitives comparison
159+
.replace(
160+
"@Generated(\"jsonschema2pojo\")",
161+
"@Generated(\"jsonschema2pojo\")\n@SuppressWarnings({\"NullAway\", \"rawtypes\", \"BoxedPrimitiveEquality\"})"
162+
)
163+
// Add @Nullable annotations to all getters (except getAdditionalProperties which is non-null)
164+
.replace("( *)public (.+) get(?!AdditionalProperties)([a-zA-Z]*)".toRegex(), "$1@Nullable\n$1public $2 get$3")
146165
}
147166
}
148-
val overwriteJs2p by tasks.registering(Copy::class) {
149-
dependsOn(jsonSchema2PojoPostProcessing)
150-
151-
from("$buildDirectory/generated/sources/js2p-tmp")
152-
into("$buildDirectory/generated/sources/js2p")
153-
}
154-
val deleteJs2pTmp by tasks.registering(Delete::class) {
155-
dependsOn(overwriteJs2p)
156-
157-
delete("$buildDirectory/generated/sources/js2p-tmp/")
158-
}
159167

160168
// Copies EnvironmentResource.java from the autoconfigure module into a generated source set so
161169
// that declarative config can use the exact same source without taking a runtime dependency on
@@ -186,6 +194,19 @@ sourceSets {
186194
}
187195
}
188196

197+
afterEvaluate {
198+
// The jsonschema2pojo plugin auto-adds its targetDirectory to the main source set. Remove it so
199+
// that only the committed model POJOs in src/main/java are compiled, avoiding duplicate classes.
200+
val js2pDir = File(buildDirectory, "generated/sources/js2p/java/main")
201+
sourceSets {
202+
main {
203+
java {
204+
setSrcDirs(srcDirs.filter { it != js2pDir })
205+
}
206+
}
207+
}
208+
}
209+
189210
val buildGraalVmReflectionJson = tasks.register("buildGraalVmReflectionJson") {
190211
val buildDir = buildDirectory
191212
val targetFile = File(
@@ -242,20 +263,28 @@ val buildGraalVmReflectionJson = tasks.register("buildGraalVmReflectionJson") {
242263
}
243264
}
244265

245-
tasks.getByName("compileJava").dependsOn(deleteJs2pTmp, copyResourceConfiguration)
246-
tasks.getByName("sourcesJar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson, copyResourceConfiguration)
247-
tasks.getByName("jar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson)
266+
tasks.getByName("compileJava").dependsOn(copyResourceConfiguration)
267+
tasks.getByName("sourcesJar").dependsOn(buildGraalVmReflectionJson, copyResourceConfiguration)
268+
tasks.getByName("jar").dependsOn(buildGraalVmReflectionJson)
248269
tasks.getByName("javadoc").dependsOn(buildGraalVmReflectionJson)
249270
tasks.getByName("compileTestJava").dependsOn(buildGraalVmReflectionJson)
250271

251-
// Exclude jsonschema2pojo generated sources from checkstyle
272+
// When syncPojoModelsToSrc runs it writes to src/main/java. Both spotlessJava and spotlessMisc
273+
// declare the module directory as an input region, so Gradle requires ordering to be explicit.
274+
// mustRunAfter satisfies the implicit-dependency validator without making spotless depend on
275+
// generation during normal builds.
276+
tasks.named("spotlessJava") { mustRunAfter(syncPojoModelsToSrc) }
277+
tasks.named("spotlessMisc") { mustRunAfter(syncPojoModelsToSrc) }
278+
279+
// Exclude committed generated POJO sources from checkstyle
252280
tasks.named<Checkstyle>("checkstyleMain") {
253281
dependsOn(buildGraalVmReflectionJson)
254282
exclude("**/declarativeconfig/model/**")
255283
}
256284

257285
tasks {
258286
withType<Test>().configureEach {
287+
dependsOn(unzipConfigurationSchema)
259288
environment(
260289
mapOf(
261290
// Expose the kitchen sink example file to tests
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.autoconfigure.declarativeconfig.model;
7+
8+
import com.fasterxml.jackson.annotation.JsonInclude;
9+
import com.fasterxml.jackson.annotation.JsonProperty;
10+
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
11+
import javax.annotation.Generated;
12+
import javax.annotation.Nullable;
13+
14+
@JsonInclude(JsonInclude.Include.NON_NULL)
15+
@JsonPropertyOrder({
16+
"default",
17+
"drop",
18+
"explicit_bucket_histogram",
19+
"base2_exponential_bucket_histogram",
20+
"last_value",
21+
"sum"
22+
})
23+
@Generated("jsonschema2pojo")
24+
@SuppressWarnings({"NullAway", "rawtypes", "BoxedPrimitiveEquality"})
25+
public class AggregationModel {
26+
27+
/** (Can be null) */
28+
@Nullable
29+
@JsonProperty("default")
30+
private DefaultAggregationModel _default;
31+
32+
/** (Can be null) */
33+
@Nullable
34+
@JsonProperty("drop")
35+
private DropAggregationModel drop;
36+
37+
/** (Can be null) */
38+
@Nullable
39+
@JsonProperty("explicit_bucket_histogram")
40+
private ExplicitBucketHistogramAggregationModel explicitBucketHistogram;
41+
42+
/** (Can be null) */
43+
@Nullable
44+
@JsonProperty("base2_exponential_bucket_histogram")
45+
private Base2ExponentialBucketHistogramAggregationModel base2ExponentialBucketHistogram;
46+
47+
/** (Can be null) */
48+
@Nullable
49+
@JsonProperty("last_value")
50+
private LastValueAggregationModel lastValue;
51+
52+
/** (Can be null) */
53+
@Nullable
54+
@JsonProperty("sum")
55+
private SumAggregationModel sum;
56+
57+
@JsonProperty("default")
58+
@Nullable
59+
public DefaultAggregationModel getDefault() {
60+
return _default;
61+
}
62+
63+
public AggregationModel withDefault(DefaultAggregationModel _default) {
64+
this._default = _default;
65+
return this;
66+
}
67+
68+
@JsonProperty("drop")
69+
@Nullable
70+
public DropAggregationModel getDrop() {
71+
return drop;
72+
}
73+
74+
public AggregationModel withDrop(DropAggregationModel drop) {
75+
this.drop = drop;
76+
return this;
77+
}
78+
79+
@JsonProperty("explicit_bucket_histogram")
80+
@Nullable
81+
public ExplicitBucketHistogramAggregationModel getExplicitBucketHistogram() {
82+
return explicitBucketHistogram;
83+
}
84+
85+
public AggregationModel withExplicitBucketHistogram(
86+
ExplicitBucketHistogramAggregationModel explicitBucketHistogram) {
87+
this.explicitBucketHistogram = explicitBucketHistogram;
88+
return this;
89+
}
90+
91+
@JsonProperty("base2_exponential_bucket_histogram")
92+
@Nullable
93+
public Base2ExponentialBucketHistogramAggregationModel getBase2ExponentialBucketHistogram() {
94+
return base2ExponentialBucketHistogram;
95+
}
96+
97+
public AggregationModel withBase2ExponentialBucketHistogram(
98+
Base2ExponentialBucketHistogramAggregationModel base2ExponentialBucketHistogram) {
99+
this.base2ExponentialBucketHistogram = base2ExponentialBucketHistogram;
100+
return this;
101+
}
102+
103+
@JsonProperty("last_value")
104+
@Nullable
105+
public LastValueAggregationModel getLastValue() {
106+
return lastValue;
107+
}
108+
109+
public AggregationModel withLastValue(LastValueAggregationModel lastValue) {
110+
this.lastValue = lastValue;
111+
return this;
112+
}
113+
114+
@JsonProperty("sum")
115+
@Nullable
116+
public SumAggregationModel getSum() {
117+
return sum;
118+
}
119+
120+
public AggregationModel withSum(SumAggregationModel sum) {
121+
this.sum = sum;
122+
return this;
123+
}
124+
125+
@Override
126+
public String toString() {
127+
StringBuilder sb = new StringBuilder();
128+
sb.append(AggregationModel.class.getName())
129+
.append('@')
130+
.append(Integer.toHexString(System.identityHashCode(this)))
131+
.append('[');
132+
sb.append("_default");
133+
sb.append('=');
134+
sb.append(((this._default == null) ? "<null>" : this._default));
135+
sb.append(',');
136+
sb.append("drop");
137+
sb.append('=');
138+
sb.append(((this.drop == null) ? "<null>" : this.drop));
139+
sb.append(',');
140+
sb.append("explicitBucketHistogram");
141+
sb.append('=');
142+
sb.append(((this.explicitBucketHistogram == null) ? "<null>" : this.explicitBucketHistogram));
143+
sb.append(',');
144+
sb.append("base2ExponentialBucketHistogram");
145+
sb.append('=');
146+
sb.append(
147+
((this.base2ExponentialBucketHistogram == null)
148+
? "<null>"
149+
: this.base2ExponentialBucketHistogram));
150+
sb.append(',');
151+
sb.append("lastValue");
152+
sb.append('=');
153+
sb.append(((this.lastValue == null) ? "<null>" : this.lastValue));
154+
sb.append(',');
155+
sb.append("sum");
156+
sb.append('=');
157+
sb.append(((this.sum == null) ? "<null>" : this.sum));
158+
sb.append(',');
159+
if (sb.charAt((sb.length() - 1)) == ',') {
160+
sb.setCharAt((sb.length() - 1), ']');
161+
} else {
162+
sb.append(']');
163+
}
164+
return sb.toString();
165+
}
166+
167+
@Override
168+
public int hashCode() {
169+
int result = 1;
170+
result = ((result * 31) + ((this.drop == null) ? 0 : this.drop.hashCode()));
171+
result =
172+
((result * 31)
173+
+ ((this.explicitBucketHistogram == null)
174+
? 0
175+
: this.explicitBucketHistogram.hashCode()));
176+
result = ((result * 31) + ((this._default == null) ? 0 : this._default.hashCode()));
177+
result = ((result * 31) + ((this.lastValue == null) ? 0 : this.lastValue.hashCode()));
178+
result = ((result * 31) + ((this.sum == null) ? 0 : this.sum.hashCode()));
179+
result =
180+
((result * 31)
181+
+ ((this.base2ExponentialBucketHistogram == null)
182+
? 0
183+
: this.base2ExponentialBucketHistogram.hashCode()));
184+
return result;
185+
}
186+
187+
@Override
188+
public boolean equals(Object other) {
189+
if (other == this) {
190+
return true;
191+
}
192+
if ((other instanceof AggregationModel) == false) {
193+
return false;
194+
}
195+
AggregationModel rhs = ((AggregationModel) other);
196+
return (((((((this.drop == rhs.drop) || ((this.drop != null) && this.drop.equals(rhs.drop)))
197+
&& ((this.explicitBucketHistogram == rhs.explicitBucketHistogram)
198+
|| ((this.explicitBucketHistogram != null)
199+
&& this.explicitBucketHistogram.equals(
200+
rhs.explicitBucketHistogram))))
201+
&& ((this._default == rhs._default)
202+
|| ((this._default != null) && this._default.equals(rhs._default))))
203+
&& ((this.lastValue == rhs.lastValue)
204+
|| ((this.lastValue != null) && this.lastValue.equals(rhs.lastValue))))
205+
&& ((this.sum == rhs.sum) || ((this.sum != null) && this.sum.equals(rhs.sum))))
206+
&& ((this.base2ExponentialBucketHistogram == rhs.base2ExponentialBucketHistogram)
207+
|| ((this.base2ExponentialBucketHistogram != null)
208+
&& this.base2ExponentialBucketHistogram.equals(
209+
rhs.base2ExponentialBucketHistogram))));
210+
}
211+
}

0 commit comments

Comments
 (0)