Skip to content

Commit b2493d1

Browse files
committed
[docs] gradle Java doc @value replacement task
1 parent a00b20f commit b2493d1

File tree

8 files changed

+283
-34
lines changed

8 files changed

+283
-34
lines changed

.gitignore

-2
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,3 @@ bin/
1616
.project
1717
*/test/
1818
*/META-INF/
19-
src/main/docs/generated/*.adoc
20-
src/main/docs/generated/configurationProperties/*.adoc

build.gradle

+19-4
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,11 @@ subprojects { Project subproject ->
410410
}
411411
}
412412

413+
task javaDocAtReplacement(type: io.micronaut.docs.JavaDocAtValueReplacementTask, dependsOn: moveConfigProps) {
414+
adocFile = new File("${rootProject.buildDir}/config-props/${subproject.name}-config-properties.adoc")
415+
rootProjectDir = rootProject.projectDir
416+
}
417+
413418
task replaceAtLink(dependsOn: moveConfigProps) {
414419
doLast {
415420
File file = new File("${rootProject.buildDir}/config-props/${subproject.name}-config-properties.adoc")
@@ -435,13 +440,23 @@ subprojects { Project subproject ->
435440
}
436441
}
437442
}
438-
439-
task processConfigProps(dependsOn: replaceAtLink) {
443+
task createDocsGeneratedFolders {
444+
doLast {
445+
if(!new File("${rootProject.buildDir}/generated").exists()) {
446+
new File("${rootProject.buildDir}/generated").mkdir()
447+
}
448+
if(!new File("${rootProject.buildDir}/generated/configurationProperties").exists()) {
449+
new File("${rootProject.buildDir}/generated/configurationProperties").mkdir()
450+
}
451+
}
452+
}
453+
task processConfigProps(dependsOn: [replaceAtLink, javaDocAtReplacement, createDocsGeneratedFolders]) {
440454
group 'documentation'
441455
ext {
442-
individualConfigPropsFolder = 'src/main/docs/generated/configurationProperties'
456+
individualConfigPropsFolder = "${rootProject.buildDir}/generated/configurationProperties"
443457
}
444458
doLast {
459+
445460
def f = new File("${rootProject.buildDir}/config-props/${subproject.name}-config-properties.adoc")
446461
if (f.exists()) {
447462
def lines = f.readLines()
@@ -456,7 +471,7 @@ subprojects { Project subproject ->
456471
configurationPropertyName = sub
457472
}
458473
if (line == separator) {
459-
File outputfile = new File("${rootProject.projectDir}/${individualConfigPropsFolder}/${configurationPropertyName}.adoc")
474+
File outputfile = new File("${individualConfigPropsFolder}/${configurationPropertyName}.adoc")
460475
outputfile.createNewFile()
461476
outputfile.text = accumulator.join('\n')
462477
accumulator = []
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package io.micronaut.docs;
2+
3+
public class AtValue {
4+
5+
private String type;
6+
private String fieldName;
7+
8+
public AtValue() {}
9+
10+
11+
public AtValue(String type, String fieldName) {
12+
this.type = type;
13+
this.fieldName = fieldName;
14+
}
15+
16+
public String getType() {
17+
return type;
18+
}
19+
20+
public void setType(String type) {
21+
this.type = type != null ? type.replaceAll(" " , "") : type;
22+
}
23+
24+
public String getFieldName() {
25+
return fieldName;
26+
}
27+
28+
public void setFieldName(String fieldName) {
29+
this.fieldName = fieldName != null ? fieldName.replaceAll(" " , "") : fieldName;
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package io.micronaut.docs;
2+
3+
import java.lang.reflect.Field;
4+
5+
public class JavaDocAtValueReplacement {
6+
private static final String OPEN_ATVALUE = "{@value ";
7+
private static final String CLOSE_ATVALUE = "}";
8+
9+
static String replaceAtValue(String type, String description) {
10+
if(description == null || description.isEmpty()) {
11+
return description;
12+
}
13+
String atValue = atValue(type, description);
14+
if (atValue == null) {
15+
return description;
16+
}
17+
String result = description.substring(0, description.indexOf(OPEN_ATVALUE));
18+
result += atValue;
19+
String sub = description.substring(description.indexOf(atValue) + atValue.length());
20+
result += sub.substring(sub.indexOf(CLOSE_ATVALUE) + CLOSE_ATVALUE.length());
21+
return result;
22+
}
23+
24+
public static String atValue(String type, String description) {
25+
AtValue atValue = atValueField(type, description);
26+
27+
if (atValue != null && atValue.getType() != null && atValue.getFieldName() != null) {
28+
try {
29+
Class<?> clazz = Class.forName(atValue.getType());
30+
Field f = clazz.getField(atValue.getFieldName());
31+
Class<?> t = f.getType();
32+
if (t == int.class) {
33+
return String.valueOf(f.getInt(null));
34+
} else if (t == double.class) {
35+
return String.valueOf(f.getDouble(null));
36+
} else if (t == boolean.class) {
37+
return String.valueOf(f.getBoolean(null));
38+
}
39+
return f.get(null).toString();
40+
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
41+
42+
}
43+
}
44+
return null;
45+
}
46+
47+
public static AtValue atValueField(String type, String description) {
48+
AtValue result = new AtValue();
49+
50+
if(description.contains(OPEN_ATVALUE)) {
51+
String str = description.substring(description.indexOf(OPEN_ATVALUE) + OPEN_ATVALUE.length());
52+
if(str.contains(CLOSE_ATVALUE)) {
53+
str = str.substring(0, str.indexOf(CLOSE_ATVALUE));
54+
}
55+
if ( str.startsWith("#")) {
56+
str = str.substring(1);
57+
result.setType(type);
58+
result.setFieldName(str);
59+
} else if ( str.contains("#")) {
60+
result.setType(str.substring(0, str.indexOf('#')));
61+
result.setFieldName(str.substring(str.indexOf('#') + 1));
62+
}
63+
}
64+
return result;
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package io.micronaut.docs
2+
3+
import org.gradle.api.DefaultTask
4+
import org.gradle.api.tasks.InputFile
5+
import org.gradle.api.tasks.TaskAction
6+
7+
class JavaDocAtValueReplacementTask extends DefaultTask {
8+
9+
@InputFile
10+
private File adocFile
11+
12+
private String rootProjectDir
13+
14+
String getRootProjectDir() {
15+
return rootProjectDir
16+
}
17+
18+
void setAdocFile(File adocFile) {
19+
this.adocFile = adocFile
20+
}
21+
22+
void setRootProjectDir(String rootProjectDir) {
23+
this.rootProjectDir = rootProjectDir
24+
}
25+
26+
public String getConfigurationPropertiesFolder() { return configurationPropertiesFolder }
27+
public void setConfigurationPropertiesFolder(String configurationPropertiesFolder) { this.configurationPropertiesFolder = configurationPropertiesFolder }
28+
29+
@Override
30+
String getGroup() {
31+
'documentation'
32+
}
33+
34+
@TaskAction
35+
void replaceAtValue() {
36+
if (this.adocFile.exists()) {
37+
38+
String configurationPropertiesClassName
39+
List<String> accumulator = []
40+
List<String> allLines = adocFile.readLines()
41+
for ( int i = 0; i < allLines.size(); i++) {
42+
String line = allLines[i]
43+
if (line == '++++' && allLines[i+1].startsWith("<a id=\"")) {
44+
String subline = allLines[i+1].substring("<a id=\"".length())
45+
configurationPropertiesClassName = subline.substring(0, subline.indexOf("\""))
46+
}
47+
48+
String proccessedLine = line
49+
50+
int attempts = 5
51+
52+
while(proccessedLine.contains('{@value') && attempts > 0) {
53+
AtValue atValueReplacement = JavaDocAtValueReplacement.atValueField(configurationPropertiesClassName, proccessedLine)
54+
55+
if (atValueReplacement != null && atValueReplacement.type != null && atValueReplacement.fieldName != null) {
56+
String resolvedValue = calculateResolvedValue(atValueReplacement.type, atValueReplacement.fieldName)
57+
if (resolvedValue) {
58+
String result = proccessedLine.substring(0, proccessedLine.indexOf("{@value "))
59+
result += resolvedValue
60+
String sub = proccessedLine.substring(proccessedLine.indexOf("{@value ") + "{@value ".size())
61+
sub = sub.substring(sub.indexOf('}') + '}'.length())
62+
result += sub
63+
proccessedLine = result
64+
} else {
65+
println "no resolved value for type: ${atValueReplacement?.type} fieldname: ${atValueReplacement?.fieldName}"
66+
}
67+
}
68+
attempts--
69+
}
70+
71+
accumulator << proccessedLine
72+
73+
}
74+
adocFile.text = accumulator.join('\n')
75+
}
76+
}
77+
78+
String calculateResolvedValue(String className, String fieldName) {
79+
80+
List<String> targetClassNames = []
81+
targetClassNames.addAll((className.split('\\.') as List<String>).findAll { it -> Character.isUpperCase(it.charAt(0)) }.collect { it.split('\\$') }.flatten() )
82+
83+
def classFiles
84+
for ( String targetClassName : targetClassNames) {
85+
classFiles = project.fileTree(rootProjectDir).filter { it.isFile() && it.name == (targetClassName+".java") }.files
86+
if (classFiles) {
87+
break
88+
}
89+
}
90+
91+
if (classFiles) {
92+
File f = classFiles.first()
93+
List<String> lines = f.readLines()
94+
95+
for (String targetClassName : targetClassNames.reverse()) {
96+
String classEvaluated
97+
String interfaceEvaluated
98+
for (int i = 0; i < lines.size(); i++) {
99+
String line = lines[i]
100+
if (line.contains("class ")) {
101+
String subLine = line.substring(line.indexOf("class ") + "class ".length())
102+
classEvaluated = subLine.substring(0, subLine.indexOf(' '))
103+
}
104+
if (line.contains("interface ")) {
105+
String subLine = line.substring(line.indexOf("interface ") + "interface ".length())
106+
interfaceEvaluated = subLine.substring(0, subLine.indexOf(' '))
107+
}
108+
if (
109+
(classEvaluated && (classEvaluated == targetClassName)) ||
110+
(interfaceEvaluated && (interfaceEvaluated == targetClassName))
111+
) {
112+
if (line.contains(" ${fieldName} = ".toString()) && line.contains(';')) {
113+
return line.substring(line.indexOf("${fieldName} = ".toString()) + "${fieldName} = ".toString().length(), line.indexOf(';'))
114+
}
115+
}
116+
}
117+
}
118+
}
119+
null
120+
}
121+
}

gradle/docs.gradle

+43-26
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,55 @@ task javadoc(type: Javadoc, description: 'Generate javadocs from all child proje
8181
}
8282
}
8383

84+
task cleanupPropertyReference(type: Delete) {
85+
group = DOCUMENTATION_GROUP
86+
delete file( "${rootProject.buildDir}/docs/guide/configurationreference.html" )
87+
}
8488

85-
task copyConfigurationReference(type: Copy) {
89+
task createDocsGeneratedFolders {
90+
doLast {
91+
if(!new File("${rootProject.buildDir}/generated").exists()) {
92+
new File("${rootProject.buildDir}/generated").mkdir()
93+
}
94+
if(!new File("${rootProject.buildDir}/generated/configurationProperties").exists()) {
95+
new File("${rootProject.buildDir}/generated/configurationProperties").mkdir()
96+
}
97+
}
98+
}
99+
100+
task mergeConfigProps(dependsOn: createDocsGeneratedFolders) {
101+
inputs.files( fileTree( "$project.buildDir/config-props" ) ).skipWhenEmpty()
102+
outputs.file( "${project.buildDir}/generated/propertyReference.adoc" )
103+
doLast {
104+
outputs.files.singleFile.withOutputStream { out ->
105+
List<File> files = new ArrayList<>(inputs.files.files).sort { File f -> f.name }
106+
for ( file in files ) {
107+
String header = "=== " + file.name.replace('.adoc', '').split('-').collect { token ->
108+
"${token.charAt(0).toString().toUpperCase()}${token.substring(1)}"
109+
}.join(' ')
110+
file.withInputStream {
111+
out << header << '\n' << it << '\n'
112+
}
113+
}
114+
}
115+
}
116+
}
117+
118+
task publishConfigurationReference(type: Copy) {
119+
dependsOn cleanupPropertyReference, createDocsGeneratedFolders, mergeConfigProps
86120
ext {
87121
destinationFileName = "configurationreference.html"
88122
}
89123
group = DOCUMENTATION_GROUP
124+
125+
inputs.files file("${project.buildDir}/generated/propertyReference.adoc")
126+
90127
from "${rootProject.projectDir}/src/main/docs/resources/style/page.html"
91128
into "${rootProject.buildDir}/docs/guide/"
92129
filter(org.apache.tools.ant.filters.ReplaceTokens, tokens: [
93130
projectVersion: projectVersion,
94131
pagetitle: 'Configuration Reference | Micronaut',
95-
docscontent: org.asciidoctor.Asciidoctor.Factory.create().render(new File("${project.projectDir}/src/main/docs/generated/propertyReference.adoc").exists() ? new File("${project.projectDir}/src/main/docs/generated/propertyReference.adoc").text : '', [:] as Map<String, Object>)])
132+
docscontent: org.asciidoctor.Asciidoctor.Factory.create().render(new File("${project.buildDir}/generated/propertyReference.adoc").exists() ? new File("${project.buildDir}/generated/propertyReference.adoc").text : '', [:] as Map<String, Object>)])
96133
rename { String fileName ->
97134
fileName.replace("page.html", destinationFileName)
98135
}
@@ -103,33 +140,13 @@ task cleanupGuideFiles(type: Delete) {
103140
delete fileTree("${rootProject.buildDir}/docs/guide") {
104141
include '*.html'
105142
exclude 'index.html'
106-
exclude copyConfigurationReference.destinationFileName
143+
exclude publishConfigurationReference.destinationFileName
107144
}
108145
delete fileTree("${rootProject.buildDir}/docs/guide/pages") {
109146
include '*.html'
110147
}
111148
}
112149

113-
task mergeConfigProps() {
114-
inputs.files( fileTree( "$project.buildDir/config-props" ) ).skipWhenEmpty()
115-
outputs.file( "${project.projectDir}/src/main/docs/generated/propertyReference.adoc" )
116-
doLast {
117-
outputs.files.singleFile.withOutputStream { out ->
118-
List<File> files = new ArrayList<>(inputs.files.files).sort { File f -> f.name }
119-
for ( file in files ) {
120-
String header = "=== " + file.name.replace('.adoc', '').split('-').collect { token ->
121-
"${token.charAt(0).toString().toUpperCase()}${token.substring(1)}"
122-
}.join(' ')
123-
file.withInputStream {
124-
out << header << '\n' << it << '\n'
125-
}
126-
}
127-
}
128-
}
129-
}
130-
copyConfigurationReference.mustRunAfter mergeConfigProps
131-
copyConfigurationReference.finalizedBy cleanupGuideFiles
132-
133150
task publishGuide(type: grails.doc.gradle.PublishGuide) {
134151
group = DOCUMENTATION_GROUP
135152
description = 'Generate Guide'
@@ -149,7 +166,7 @@ task publishGuide(type: grails.doc.gradle.PublishGuide) {
149166
'api': '../api',
150167
'sourceDir':rootProject.projectDir.absolutePath,
151168
'sourcedir':rootProject.projectDir.absolutePath,
152-
'includedir': "${rootProject.projectDir.absolutePath}/src/main/docs/generated/",
169+
'includedir': "${rootProject.buildDir.absolutePath}/generated/",
153170
'javaee': 'https://docs.oracle.com/javaee/8/api/',
154171
'javase': 'https://docs.oracle.com/javase/8/docs/api/',
155172
'groovyapi': 'http://docs.groovy-lang.org/latest/html/gapi/',
@@ -173,13 +190,13 @@ task publishGuide(type: grails.doc.gradle.PublishGuide) {
173190
'''
174191
}
175192
}
176-
publishGuide.dependsOn mergeConfigProps
177-
publishGuide.dependsOn copyConfigurationReference
178193

179194
publishGuide.mustRunAfter javadoc
195+
180196
task docs(dependsOn:[javadoc, publishGuide]) {
181197
group = DOCUMENTATION_GROUP
182198
}
199+
docs.finalizedBy cleanupGuideFiles
183200

184201
def assembleTask = project.tasks.findByName("assemble")
185202
if(assembleTask == null) {

src/main/docs/generated/configurationProperties/README.md

-1
This file was deleted.

0 commit comments

Comments
 (0)