Skip to content

Commit c7a3791

Browse files
authored
TEZ-4387: use new doclet API in Java 9+ (#296) (Laszlo Bodor Co-authored-by Laszlo Attila Toth, reviewed by Ayush Saxena)
1 parent c77d37e commit c7a3791

21 files changed

+1150
-115
lines changed

pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,7 @@
13851385
</profile>
13861386
</profiles>
13871387

1388+
<!-- TODO: TEZ-4597: IncludePublicAnnotationsStandardDoclet is not JDK9+ compatible -->
13881389
<reporting>
13891390
<plugins>
13901391
<plugin>

tez-tools/tez-javadoc-tools/findbugs-exclude.xml

+12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@
1313
-->
1414
<FindBugsFilter>
1515

16+
<Match>
17+
<Class name="org.apache.tez.tools.javadoc.model.ConfigProperty"/>
18+
<Field name="description"/>
19+
<Bug pattern="UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD"/>
20+
</Match>
21+
22+
<Match>
23+
<Class name="org.apache.tez.tools.javadoc.model.ConfigProperty"/>
24+
<Field name="validValues"/>
25+
<Bug pattern="UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD"/>
26+
</Match>
27+
1628
<Match>
1729
<Class name="org.apache.tez.tools.javadoc.model.ConfigProperty"/>
1830
<Field name="validValues"/>

tez-tools/tez-javadoc-tools/pom.xml

+56
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,62 @@
7878
</dependency>
7979
</dependencies>
8080
</profile>
81+
82+
<profile>
83+
<id>java8-16</id>
84+
<activation>
85+
<jdk>[1.8,16]</jdk>
86+
</activation>
87+
<build>
88+
<plugins>
89+
<plugin>
90+
<groupId>org.codehaus.mojo</groupId>
91+
<artifactId>build-helper-maven-plugin</artifactId>
92+
<executions>
93+
<execution>
94+
<phase>generate-sources</phase>
95+
<goals>
96+
<goal>add-source</goal>
97+
</goals>
98+
<configuration>
99+
<sources>
100+
<source>src/main/java-8-16</source>
101+
</sources>
102+
</configuration>
103+
</execution>
104+
</executions>
105+
</plugin>
106+
</plugins>
107+
</build>
108+
</profile>
109+
110+
<profile>
111+
<id>java17</id>
112+
<activation>
113+
<jdk>[17,)</jdk>
114+
</activation>
115+
<build>
116+
<plugins>
117+
<plugin>
118+
<groupId>org.codehaus.mojo</groupId>
119+
<artifactId>build-helper-maven-plugin</artifactId>
120+
<executions>
121+
<execution>
122+
<phase>generate-sources</phase>
123+
<goals>
124+
<goal>add-source</goal>
125+
</goals>
126+
<configuration>
127+
<sources>
128+
<source>src/main/java-17</source>
129+
</sources>
130+
</configuration>
131+
</execution>
132+
</executions>
133+
</plugin>
134+
</plugins>
135+
</build>
136+
</profile>
81137
</profiles>
82138

83139

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.tez.tools.javadoc.doclet;
20+
21+
import com.sun.source.util.DocTrees;
22+
import jdk.javadoc.doclet.Doclet;
23+
import jdk.javadoc.doclet.DocletEnvironment;
24+
import jdk.javadoc.doclet.Reporter;
25+
import org.apache.hadoop.classification.InterfaceAudience.Private;
26+
import org.apache.hadoop.classification.InterfaceStability.Evolving;
27+
import org.apache.hadoop.classification.InterfaceStability.Unstable;
28+
import org.apache.tez.common.annotation.ConfigurationClass;
29+
import org.apache.tez.common.annotation.ConfigurationProperty;
30+
import org.apache.tez.tools.javadoc.model.Config;
31+
import org.apache.tez.tools.javadoc.model.ConfigProperty;
32+
import org.apache.tez.tools.javadoc.util.HtmlWriter;
33+
import org.apache.tez.tools.javadoc.util.XmlWriter;
34+
35+
import javax.lang.model.SourceVersion;
36+
import javax.lang.model.element.AnnotationMirror;
37+
import javax.lang.model.element.AnnotationValue;
38+
import javax.lang.model.element.Element;
39+
import javax.lang.model.element.ElementKind;
40+
import javax.lang.model.element.ExecutableElement;
41+
import javax.lang.model.element.Modifier;
42+
import javax.lang.model.element.TypeElement;
43+
import javax.lang.model.element.VariableElement;
44+
import javax.tools.Diagnostic;
45+
import java.io.IOException;
46+
import java.util.Arrays;
47+
import java.util.HashSet;
48+
import java.util.List;
49+
import java.util.Locale;
50+
import java.util.Map;
51+
import java.util.Set;
52+
53+
public class ConfigStandardDoclet implements Doclet {
54+
55+
private static boolean debugMode = false;
56+
57+
private Reporter reporter;
58+
59+
private static String stripQuotes(String s) {
60+
if (s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"') {
61+
return s.substring(1, s.length() - 1);
62+
}
63+
return s;
64+
}
65+
66+
@Override
67+
public void init(Locale locale, Reporter reporter) {
68+
this.reporter = reporter;
69+
}
70+
71+
@Override
72+
public String getName() {
73+
return "Tez";
74+
}
75+
76+
@Override
77+
public SourceVersion getSupportedSourceVersion() {
78+
return SourceVersion.RELEASE_9;
79+
}
80+
81+
private void logMessage(String message) {
82+
if (!debugMode) {
83+
return;
84+
}
85+
reporter.print(Diagnostic.Kind.NOTE, message);
86+
}
87+
88+
@Override
89+
public boolean run(DocletEnvironment docEnv) {
90+
logMessage("Running doclet " + ConfigStandardDoclet.class.getSimpleName());
91+
DocTrees docTrees = docEnv.getDocTrees();
92+
for (Element element : docEnv.getIncludedElements()) {
93+
if (element.getKind().equals(ElementKind.CLASS) && element instanceof TypeElement) {
94+
processDoc(docTrees, (TypeElement) element);
95+
}
96+
}
97+
98+
return true;
99+
}
100+
101+
private void processDoc(DocTrees docTrees, TypeElement doc) {
102+
logMessage("Parsing : " + doc);
103+
if (!doc.getKind().equals(ElementKind.CLASS)) {
104+
logMessage("Ignoring non-class: " + doc);
105+
return;
106+
}
107+
108+
List<? extends AnnotationMirror> annotations = doc.getAnnotationMirrors();
109+
boolean isConfigClass = false;
110+
String templateName = null;
111+
for (AnnotationMirror annotation : annotations) {
112+
logMessage("Checking annotation: " + annotation.getAnnotationType());
113+
if (annotation.getAnnotationType().asElement().toString().equals(
114+
ConfigurationClass.class.getName())) {
115+
isConfigClass = true;
116+
Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = annotation.getElementValues();
117+
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> element : elementValues.entrySet()) {
118+
if (element.getKey().getSimpleName().toString().equals("templateFileName")) {
119+
templateName = stripQuotes(element.getValue().getValue().toString());
120+
}
121+
}
122+
break;
123+
}
124+
}
125+
126+
if (!isConfigClass) {
127+
logMessage("Ignoring non-config class: " + doc);
128+
return;
129+
}
130+
131+
logMessage("Processing config class: " + doc);
132+
Config config = new Config(doc.getSimpleName().toString(), templateName);
133+
Map<String, ConfigProperty> configProperties = config.getConfigProperties();
134+
135+
processElements(docTrees, doc, configProperties);
136+
137+
HtmlWriter writer = new HtmlWriter();
138+
try {
139+
writer.write(config);
140+
} catch (IOException e) {
141+
throw new RuntimeException(e);
142+
}
143+
144+
XmlWriter xmlWriter = new XmlWriter();
145+
try {
146+
xmlWriter.write(config);
147+
} catch (IOException e) {
148+
throw new RuntimeException(e);
149+
}
150+
}
151+
152+
private void processElements(DocTrees docTrees, TypeElement doc, Map<String, ConfigProperty> configProperties) {
153+
List<? extends Element> elements = doc.getEnclosedElements();
154+
for (Element f : elements) {
155+
if (!(f instanceof VariableElement)) {
156+
continue;
157+
}
158+
159+
if (!f.getKind().equals(ElementKind.FIELD)) {
160+
continue;
161+
}
162+
163+
VariableElement field = (VariableElement) f;
164+
165+
if (field.getModifiers().contains(Modifier.PRIVATE)) {
166+
logMessage("Skipping private field: " + field);
167+
continue;
168+
}
169+
if (field.getModifiers().contains(Modifier.STATIC)) {
170+
logMessage("Skipping non-static field: " + field);
171+
continue;
172+
}
173+
174+
String fieldName = field.getSimpleName().toString();
175+
if (fieldName.endsWith("_PREFIX")) {
176+
logMessage("Skipping non-config prefix constant field: " + field);
177+
continue;
178+
}
179+
if (fieldName.equals("TEZ_SITE_XML")) {
180+
logMessage("Skipping constant field: " + field);
181+
continue;
182+
}
183+
184+
if (fieldName.endsWith("_DEFAULT")) {
185+
186+
String name = fieldName.substring(0, fieldName.lastIndexOf("_DEFAULT"));
187+
if (!configProperties.containsKey(name)) {
188+
configProperties.put(name, new ConfigProperty());
189+
}
190+
ConfigProperty configProperty = configProperties.get(name);
191+
if (field.getConstantValue() == null) {
192+
String val = field.getConstantValue().toString();
193+
logMessage("Got null constant value"
194+
+ ", name=" + name
195+
+ ", field=" + fieldName
196+
+ ", val=" + val);
197+
configProperty.setDefaultValue(val);
198+
} else {
199+
configProperty.setDefaultValue(field.getConstantValue().toString());
200+
}
201+
configProperty.setInferredType(field.getSimpleName().toString());
202+
203+
if (name.equals("TEZ_AM_STAGING_DIR") && configProperty.getDefaultValue() != null) {
204+
String defaultValue = configProperty.getDefaultValue();
205+
defaultValue = defaultValue.replace(System.getProperty("user.name"), "${user.name}");
206+
configProperty.setDefaultValue(defaultValue);
207+
}
208+
209+
continue;
210+
}
211+
212+
if (!configProperties.containsKey(fieldName)) {
213+
configProperties.put(fieldName, new ConfigProperty());
214+
}
215+
ConfigProperty configProperty = configProperties.get(fieldName);
216+
configProperty.setPropertyName(field.getConstantValue().toString());
217+
218+
List<? extends AnnotationMirror> annotationDescs = field.getAnnotationMirrors();
219+
220+
for (AnnotationMirror annotationDesc : annotationDescs) {
221+
String elementFqName = annotationDesc.getAnnotationType().asElement().toString();
222+
if (elementFqName.equals(Private.class.getCanonicalName())) {
223+
configProperty.setPrivate(true);
224+
}
225+
if (elementFqName.equals(Unstable.class.getCanonicalName())) {
226+
configProperty.setUnstable(true);
227+
}
228+
if (elementFqName.equals(Evolving.class.getCanonicalName())) {
229+
configProperty.setEvolving(true);
230+
}
231+
if (elementFqName.equals(ConfigurationProperty.class.getCanonicalName())) {
232+
configProperty.setValidConfigProp(true);
233+
234+
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> element
235+
: annotationDesc.getElementValues().entrySet()) {
236+
if (element.getKey().getSimpleName().toString().equals("type")) {
237+
configProperty.setType(stripQuotes(element.getValue().getValue().toString()));
238+
} else {
239+
logMessage("Unhandled annotation property: " + element.getKey().getSimpleName());
240+
}
241+
}
242+
}
243+
}
244+
configProperty.setDescription(docTrees.getDocCommentTree(field).getFullBody().toString());
245+
}
246+
}
247+
248+
@Override
249+
public Set<? extends Option> getSupportedOptions() {
250+
Option[] options = {
251+
new Option() {
252+
private final List<String> someOption = Arrays.asList(
253+
"-debug",
254+
"--debug"
255+
);
256+
257+
@Override
258+
public int getArgumentCount() {
259+
return 0;
260+
}
261+
262+
@Override
263+
public String getDescription() {
264+
return "Debug mode";
265+
}
266+
267+
@Override
268+
public Option.Kind getKind() {
269+
return Kind.STANDARD;
270+
}
271+
272+
@Override
273+
public List<String> getNames() {
274+
return someOption;
275+
}
276+
277+
@Override
278+
public String getParameters() {
279+
return "";
280+
}
281+
282+
@Override
283+
public boolean process(String opt, List<String> arguments) {
284+
debugMode = true;
285+
return true;
286+
}
287+
}
288+
};
289+
return new HashSet<>(Arrays.asList(options));
290+
}
291+
}

0 commit comments

Comments
 (0)