Skip to content

Commit 3c9e08b

Browse files
Enhance OpenSearch APIs annotation processor with OpenSearch version validation (#15502) (#15510)
(cherry picked from commit 0a10aca) Signed-off-by: Andriy Redko <[email protected]> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent f700f50 commit 3c9e08b

File tree

4 files changed

+128
-0
lines changed

4 files changed

+128
-0
lines changed

libs/common/src/main/java/org/opensearch/common/annotation/processor/ApiAnnotationProcessor.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public class ApiAnnotationProcessor extends AbstractProcessor {
5959
private static final String OPENSEARCH_PACKAGE = "org.opensearch";
6060

6161
private final Set<Element> reported = new HashSet<>();
62+
private final Set<Element> validated = new HashSet<>();
6263
private final Set<AnnotatedConstruct> processed = new HashSet<>();
6364
private Kind reportFailureAs = Kind.ERROR;
6465

@@ -85,6 +86,8 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
8586
);
8687

8788
for (var element : elements) {
89+
validate(element);
90+
8891
if (!checkPackage(element)) {
8992
continue;
9093
}
@@ -100,6 +103,64 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
100103
return false;
101104
}
102105

106+
private void validate(Element element) {
107+
// The element was validated already
108+
if (validated.contains(element)) {
109+
return;
110+
}
111+
112+
validated.add(element);
113+
114+
final PublicApi publicApi = element.getAnnotation(PublicApi.class);
115+
if (publicApi != null) {
116+
if (!validateVersion(publicApi.since())) {
117+
processingEnv.getMessager()
118+
.printMessage(
119+
reportFailureAs,
120+
"The type " + element + " has @PublicApi annotation with unparseable OpenSearch version: " + publicApi.since()
121+
);
122+
}
123+
}
124+
125+
final DeprecatedApi deprecatedApi = element.getAnnotation(DeprecatedApi.class);
126+
if (deprecatedApi != null) {
127+
if (!validateVersion(deprecatedApi.since())) {
128+
processingEnv.getMessager()
129+
.printMessage(
130+
reportFailureAs,
131+
"The type "
132+
+ element
133+
+ " has @DeprecatedApi annotation with unparseable OpenSearch version: "
134+
+ deprecatedApi.since()
135+
);
136+
}
137+
}
138+
}
139+
140+
private boolean validateVersion(String version) {
141+
String[] parts = version.split("[.-]");
142+
if (parts.length < 3 || parts.length > 4) {
143+
return false;
144+
}
145+
146+
int major = Integer.parseInt(parts[0]);
147+
if (major > 3 || major < 0) {
148+
return false;
149+
}
150+
151+
int minor = Integer.parseInt(parts[1]);
152+
if (minor < 0) {
153+
return false;
154+
}
155+
156+
int patch = Integer.parseInt(parts[2]);
157+
if (patch < 0) {
158+
return false;
159+
}
160+
161+
return true;
162+
}
163+
103164
/**
104165
* Check top level executable element
105166
* @param executable top level executable element

libs/common/src/test/java/org/opensearch/common/annotation/processor/ApiAnnotationProcessorTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,4 +486,35 @@ public void testPublicApiConstructorAnnotatedInternalApi() {
486486

487487
assertThat(failure.diagnotics(), not(hasItem(matching(Diagnostic.Kind.ERROR))));
488488
}
489+
490+
public void testPublicApiUnparseableVersion() {
491+
final CompilerResult result = compile("PublicApiAnnotatedUnparseable.java");
492+
assertThat(result, instanceOf(Failure.class));
493+
494+
final Failure failure = (Failure) result;
495+
assertThat(failure.diagnotics(), hasSize(3));
496+
497+
assertThat(
498+
failure.diagnotics(),
499+
hasItem(
500+
matching(
501+
Diagnostic.Kind.ERROR,
502+
containsString(
503+
"The type org.opensearch.common.annotation.processor.PublicApiAnnotatedUnparseable has @PublicApi annotation with unparseable OpenSearch version: 2.x"
504+
)
505+
)
506+
)
507+
);
508+
}
509+
510+
public void testPublicApiWithDeprecatedApiMethod() {
511+
final CompilerResult result = compile("PublicApiWithDeprecatedApiMethod.java");
512+
assertThat(result, instanceOf(Failure.class));
513+
514+
final Failure failure = (Failure) result;
515+
assertThat(failure.diagnotics(), hasSize(2));
516+
517+
assertThat(failure.diagnotics(), not(hasItem(matching(Diagnostic.Kind.ERROR))));
518+
}
519+
489520
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.common.annotation.processor;
10+
11+
import org.opensearch.common.annotation.PublicApi;
12+
13+
@PublicApi(since = "2.x")
14+
public class PublicApiAnnotatedUnparseable {
15+
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.common.annotation.processor;
10+
11+
import org.opensearch.common.annotation.DeprecatedApi;
12+
import org.opensearch.common.annotation.PublicApi;
13+
14+
@PublicApi(since = "1.0.0")
15+
public class PublicApiWithDeprecatedApiMethod {
16+
@DeprecatedApi(since = "0.1.0")
17+
public void method() {
18+
19+
}
20+
}

0 commit comments

Comments
 (0)