diff --git a/spring-auto-restdocs-json-doclet-jdk9/pom.xml b/spring-auto-restdocs-json-doclet-jdk9/pom.xml
index ec9ceaef..5d96a1a8 100644
--- a/spring-auto-restdocs-json-doclet-jdk9/pom.xml
+++ b/spring-auto-restdocs-json-doclet-jdk9/pom.xml
@@ -16,6 +16,7 @@
Doclet exporting JavaDoc to JSON for Spring Auto REST Docs
+ true
UTF-8
@@ -23,6 +24,16 @@
com.fasterxml.jackson.core
jackson-databind
+
+ [2.11.2,2.12.0),[2.12.1,2.99)
org.apache.commons
@@ -54,35 +65,70 @@
+ org.apache.maven.plugins
maven-compiler-plugin
9
-
- maven-javadoc-plugin
- true
-
-
- generate-javadoc-json
- compile
-
- test-javadoc-no-fork
-
-
- capital.scalable.restdocs.jsondoclet.ExtractDocumentationAsJsonDoclet
-
- capital.scalable
- spring-auto-restdocs-json-doclet-jdk9
- ${project.parent.version}
-
- ${project.build.directory}
- false
- package
-
-
-
-
+
+
+
+
+ java14
+
+ [14,17)
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ --enable-preview
+ --illegal-access=permit
+
+
+ alphabetical
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ test-compile-java-14
+ test-compile
+
+ testCompile
+
+
+ ${java.specification.version}
+ true
+
+
+ --enable-preview
+
+
+ ${project.basedir}/src/test/java14
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-auto-restdocs-json-doclet-jdk9/src/main/java/capital/scalable/restdocs/jsondoclet/ClassDocumentation.java b/spring-auto-restdocs-json-doclet-jdk9/src/main/java/capital/scalable/restdocs/jsondoclet/ClassDocumentation.java
index 0389fe59..54dbf20d 100644
--- a/spring-auto-restdocs-json-doclet-jdk9/src/main/java/capital/scalable/restdocs/jsondoclet/ClassDocumentation.java
+++ b/spring-auto-restdocs-json-doclet-jdk9/src/main/java/capital/scalable/restdocs/jsondoclet/ClassDocumentation.java
@@ -19,12 +19,17 @@
*/
package capital.scalable.restdocs.jsondoclet;
+import static java.util.Optional.ofNullable;
import static capital.scalable.restdocs.jsondoclet.DocletUtils.cleanupDocComment;
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.doctree.ParamTree;
+
import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import jdk.javadoc.doclet.DocletEnvironment;
@@ -42,14 +47,41 @@ public static ClassDocumentation fromClassDoc(DocletEnvironment docEnv,
ClassDocumentation cd = new ClassDocumentation();
cd.setComment(cleanupDocComment(docEnv.getElementUtils().getDocComment(element)));
- element.getEnclosedElements().forEach(fieldOrMethod -> {
- if (fieldOrMethod.getKind().equals(ElementKind.FIELD)) {
- cd.addField(docEnv, fieldOrMethod);
- } else if (fieldOrMethod.getKind().equals(ElementKind.METHOD)
- || fieldOrMethod.getKind().equals(ElementKind.CONSTRUCTOR)) {
- cd.addMethod(docEnv, fieldOrMethod);
- }
- });
+ if ("RECORD".equals(element.getKind().name())) {
+ ofNullable(docEnv.getDocTrees().getDocCommentTree(element))
+ .stream()
+ .map(DocCommentTree::getBlockTags)
+ .flatMap(List::stream)
+ .filter(ParamTree.class::isInstance)
+ .map(ParamTree.class::cast)
+ .filter(p -> !p.isTypeParameter())
+ .forEach(p -> {
+ String name = p.getName().getName().toString();
+ String desc = p.getDescription()
+ .stream()
+ .map(Object::toString)
+ .collect(Collectors.joining(" "))
+ ;
+
+ cd.fields.put(name, FieldDocumentation.fromString(desc));
+ })
+ ;
+ } else {
+ element.getEnclosedElements().forEach(fieldOrMethod -> {
+ switch (fieldOrMethod.getKind()) {
+ case FIELD:
+ cd.addField(docEnv, fieldOrMethod);
+ break;
+ case METHOD:
+ case CONSTRUCTOR:
+ cd.addMethod(docEnv, fieldOrMethod);
+ break;
+ default:
+ // Ignored
+ break;
+ }
+ });
+ }
return cd;
}
@@ -67,4 +99,5 @@ private void addMethod(DocletEnvironment docEnv, Element element) {
this.methods.put(element.getSimpleName().toString(),
MethodDocumentation.fromMethodDoc(docEnv, element));
}
+
}
diff --git a/spring-auto-restdocs-json-doclet-jdk9/src/main/java/capital/scalable/restdocs/jsondoclet/FieldDocumentation.java b/spring-auto-restdocs-json-doclet-jdk9/src/main/java/capital/scalable/restdocs/jsondoclet/FieldDocumentation.java
index 12a0298e..f3224d4c 100644
--- a/spring-auto-restdocs-json-doclet-jdk9/src/main/java/capital/scalable/restdocs/jsondoclet/FieldDocumentation.java
+++ b/spring-auto-restdocs-json-doclet-jdk9/src/main/java/capital/scalable/restdocs/jsondoclet/FieldDocumentation.java
@@ -37,6 +37,10 @@ public class FieldDocumentation {
private String comment;
private final Map tags = new HashMap<>();
+ private FieldDocumentation(String comment) {
+ this.comment = comment;
+ }
+
private void addTag(DocTree tag) {
if (tag instanceof BlockTagTree) {
tags.put(
@@ -47,8 +51,8 @@ private void addTag(DocTree tag) {
public static FieldDocumentation fromFieldDoc(DocletEnvironment docEnv,
Element fieldElement) {
- FieldDocumentation fd = new FieldDocumentation();
- fd.comment = cleanupDocComment(docEnv.getElementUtils().getDocComment(fieldElement));
+ FieldDocumentation fd = fromString(
+ cleanupDocComment(docEnv.getElementUtils().getDocComment(fieldElement)));
Optional.ofNullable(docEnv.getDocTrees().getDocCommentTree(fieldElement))
.ifPresent(docCommentTree -> docCommentTree.getBlockTags()
@@ -56,4 +60,8 @@ public static FieldDocumentation fromFieldDoc(DocletEnvironment docEnv,
return fd;
}
+
+ public static FieldDocumentation fromString(String comment) {
+ return new FieldDocumentation(comment);
+ }
}
diff --git a/spring-auto-restdocs-json-doclet-jdk9/src/test/java/capital/scalable/restdocs/jsondoclet/ExtractDocumentationAsJsonDocletTest.java b/spring-auto-restdocs-json-doclet-jdk9/src/test/java/capital/scalable/restdocs/jsondoclet/ExtractDocumentationAsJsonDocletTest.java
index 0915d8dc..873710a0 100644
--- a/spring-auto-restdocs-json-doclet-jdk9/src/test/java/capital/scalable/restdocs/jsondoclet/ExtractDocumentationAsJsonDocletTest.java
+++ b/spring-auto-restdocs-json-doclet-jdk9/src/test/java/capital/scalable/restdocs/jsondoclet/ExtractDocumentationAsJsonDocletTest.java
@@ -19,32 +19,89 @@
*/
package capital.scalable.restdocs.jsondoclet;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import java.io.File;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+
+import javax.tools.DocumentationTool.DocumentationTask;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+import static org.junit.Assert.assertTrue;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
import org.apache.commons.io.IOUtils;
import org.json.JSONException;
+import org.junit.Before;
import org.junit.Test;
import org.skyscreamer.jsonassert.JSONAssert;
public class ExtractDocumentationAsJsonDocletTest {
+ private static final Path SRC_PATH = FileSystems.getDefault().getPath("src/test/resources").toAbsolutePath();
+ private static final Path TGT_PATH = FileSystems.getDefault().getPath("target/test/generated-javadoc-json").toAbsolutePath();
+
private static final String JSON_PATH =
"capital/scalable/restdocs/jsondoclet/DocumentedClass.json";
- /**
- * The test requires that the Doclet is executed before. This is ensured by
- * the Maven configuration, but not when the test is executed on its own.
- */
+ private static final List args = List.of(
+ "--release", "9",
+ "-private",
+ "-d", TGT_PATH.toString()
+ );
+
+ @Before
+ public void setup() throws IOException {
+ Files.createDirectories(TGT_PATH);
+ }
+
@Test
public void testDocumentedClass() throws IOException, JSONException {
- String generated = IOUtils.toString(
- new FileInputStream(new File("target/generated-javadoc-json/" + JSON_PATH)), UTF_8);
- String expected = IOUtils.toString(
- this.getClass().getClassLoader().getResourceAsStream(JSON_PATH), UTF_8);
- JSONAssert.assertEquals(expected, generated, false);
+ Path source = SRC_PATH.resolve("capital/scalable/restdocs/jsondoclet/DocumentedClass.java");
+ Iterable compilationUnits = compilationUnits(source);
+
+ DocumentationTask task = ToolProvider.getSystemDocumentationTool().getTask(null, null, null, ExtractDocumentationAsJsonDoclet.class, args, compilationUnits);
+
+ boolean result = task.call();
+ assertTrue(result);
+
+ try (
+ InputStream expectedStream = new FileInputStream(SRC_PATH.resolve(JSON_PATH).toFile());
+ InputStream generatedStream = new FileInputStream(TGT_PATH.resolve(JSON_PATH).toFile());
+ ) {
+ String expected = IOUtils.toString(expectedStream, UTF_8);
+ String generated = IOUtils.toString(generatedStream, UTF_8);
+ JSONAssert.assertEquals(expected, generated, false);
+ }
+ }
+
+ Iterable compilationUnits(Path path) throws IOException {
+ try (InputStream in = new FileInputStream(path.toFile())) {
+ String content = IOUtils.toString(in, UTF_8);
+ return List.of(new InMemoryJavaFileObject(path.toUri(), content));
+ }
+ }
+
+ static class InMemoryJavaFileObject extends SimpleJavaFileObject {
+
+ private final String source;
+
+ public InMemoryJavaFileObject(URI uri, String sourceCode) {
+ super(uri, Kind.SOURCE);
+ this.source = sourceCode;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+
}
+
}
diff --git a/spring-auto-restdocs-json-doclet-jdk9/src/test/java14/capital/scalable/restdocs/jsondoclet/RecordTest.java b/spring-auto-restdocs-json-doclet-jdk9/src/test/java14/capital/scalable/restdocs/jsondoclet/RecordTest.java
new file mode 100644
index 00000000..2f5cfcb1
--- /dev/null
+++ b/spring-auto-restdocs-json-doclet-jdk9/src/test/java14/capital/scalable/restdocs/jsondoclet/RecordTest.java
@@ -0,0 +1,96 @@
+/*-
+ * #%L
+ * Spring Auto REST Docs Json Doclet for JDK9+
+ * %%
+ * Copyright (C) 2015 - 2021 Scalable Capital GmbH
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+package capital.scalable.restdocs.jsondoclet;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RecordTest {
+
+ private static final Path TGT_PATH = Path.of("target/test/generated-javadoc-json").toAbsolutePath();
+
+ private static final List args = List.of(
+ "--enable-preview",
+ "--release", Integer.toString(Runtime.version().feature()),
+ "-private",
+ "-d", TGT_PATH.toString()
+ );
+
+ @Before
+ public void setup() throws IOException {
+ Files.createDirectories(TGT_PATH);
+ }
+
+ @Test
+ public void testDocumentedRecord() throws IOException {
+ var src = new InMemoryJavaFileObject(URI.create("string:///DocumentedRecord.java"),
+ """
+ /**
+ * This is a test record. UTF 8 test: 我能吞下玻璃而不伤身体。Árvíztűrő tükörfúrógép
+ *
+ * @ Don't fail on invalid tags
+ * @param foo this is a record component
+ */
+ record DocumentedRecord(int foo) {}
+ """
+ );
+
+ var task = ToolProvider.getSystemDocumentationTool().getTask(null, null, null, ExtractDocumentationAsJsonDoclet.class, args, List.of(src));
+
+ boolean result = task.call();
+ assertTrue(result);
+
+ var mapper = new ObjectMapper();
+ var tree = mapper.readTree(TGT_PATH.resolve("DocumentedRecord.json").toFile());
+ assertEquals("This is a test record. UTF 8 test: 我能吞下玻璃而不伤身体。Árvíztűrő tükörfúrógép", tree.at("/comment").asText());
+ assertEquals("this is a record component", tree.at("/fields/foo/comment").asText());
+
+ }
+
+ static class InMemoryJavaFileObject extends SimpleJavaFileObject {
+
+ private final String source;
+
+ public InMemoryJavaFileObject(URI uri, String sourceCode) {
+ super(uri, Kind.SOURCE);
+ this.source = sourceCode;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return source;
+ }
+
+ }
+
+}
diff --git a/spring-auto-restdocs-json-doclet-jdk9/src/test/java/capital/scalable/restdocs/jsondoclet/DocumentedClass.java b/spring-auto-restdocs-json-doclet-jdk9/src/test/resources/capital/scalable/restdocs/jsondoclet/DocumentedClass.java
similarity index 100%
rename from spring-auto-restdocs-json-doclet-jdk9/src/test/java/capital/scalable/restdocs/jsondoclet/DocumentedClass.java
rename to spring-auto-restdocs-json-doclet-jdk9/src/test/resources/capital/scalable/restdocs/jsondoclet/DocumentedClass.java