Skip to content

Commit 66c7594

Browse files
committed
- integrate ascii doc into openapi generator: maven/gradle plugin
- fix schema data iteration to support schema $ref - make schema filter pretty print output
1 parent 806f9b3 commit 66c7594

File tree

30 files changed

+1168
-540
lines changed

30 files changed

+1168
-540
lines changed

docs/src/main/java/io/jooby/adoc/DocGenerator.java

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -87,29 +87,29 @@ public static void generate(Path basedir, boolean publish, boolean v1, boolean d
8787
pb.step();
8888

8989
if (doAscii) {
90-
Asciidoctor asciidoctor = Asciidoctor.Factory.create();
91-
92-
asciidoctor.convertFile(
93-
asciidoc.resolve("index.adoc").toFile(),
94-
createOptions(asciidoc, outdir, version, null, asciidoc.resolve("index.adoc")));
95-
var index = outdir.resolve("index.html");
96-
Files.writeString(index, hljs(Files.readString(index)));
97-
pb.step();
98-
99-
Stream.of(treeDirs)
100-
.forEach(
101-
throwingConsumer(
102-
name -> {
103-
Path modules = outdir.resolve(name);
104-
Files.createDirectories(modules);
105-
Files.walk(asciidoc.resolve(name))
106-
.filter(Files::isRegularFile)
107-
.forEach(
108-
module -> {
109-
processModule(asciidoctor, asciidoc, module, outdir, name, version);
110-
pb.step();
111-
});
112-
}));
90+
try (var asciidoctor = Asciidoctor.Factory.create()) {
91+
asciidoctor.convertFile(
92+
asciidoc.resolve("index.adoc").toFile(),
93+
createOptions(asciidoc, outdir, version, null, asciidoc.resolve("index.adoc")));
94+
var index = outdir.resolve("index.html");
95+
Files.writeString(index, hljs(Files.readString(index)));
96+
pb.step();
97+
98+
Stream.of(treeDirs)
99+
.forEach(
100+
throwingConsumer(
101+
name -> {
102+
Path modules = outdir.resolve(name);
103+
Files.createDirectories(modules);
104+
Files.walk(asciidoc.resolve(name))
105+
.filter(Files::isRegularFile)
106+
.forEach(
107+
module -> {
108+
processModule(asciidoctor, asciidoc, module, outdir, name, version);
109+
pb.step();
110+
});
111+
}));
112+
}
113113
}
114114

115115
// LICENSE
@@ -242,6 +242,7 @@ private static Options createOptions(Path basedir, Path outdir, String version,
242242
var attributes = Attributes.builder();
243243

244244
attributes.attribute("docfile", docfile.toString());
245+
attributes.attribute("stylesheet", "js/styles/site.css");
245246
attributes.attribute("love", "♡");
246247
attributes.attribute("docinfo", "shared");
247248
attributes.title(title == null ? "jooby: do more! more easily!!" : "jooby: " + title);
@@ -280,7 +281,7 @@ private static Options createOptions(Path basedir, Path outdir, String version,
280281
attributes.attribute("date", DateTimeFormatter.ISO_INSTANT.format(Instant.now()));
281282

282283
OptionsBuilder options = Options.builder();
283-
options.backend("html");
284+
options.backend("html5");
284285

285286
options.attributes(attributes.build());
286287
options.baseDir(basedir.toAbsolutePath().toFile());

modules/jooby-gradle-plugin/src/main/java/io/jooby/gradle/OpenAPITask.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@
1717
import java.io.File;
1818
import java.nio.file.Path;
1919
import java.util.List;
20+
import java.util.Map;
2021
import java.util.Optional;
2122

23+
import static java.util.Optional.ofNullable;
24+
2225
/**
2326
* Generate an OpenAPI file from a jooby application.
2427
*
@@ -37,6 +40,8 @@ public class OpenAPITask extends BaseTask {
3740

3841
private String specVersion;
3942

43+
private List<File> adoc;
44+
4045
/**
4146
* Creates an OpenAPI task.
4247
*/
@@ -61,7 +66,8 @@ public void generate() throws Throwable {
6166
.map(File::toPath);
6267
})
6368
.distinct()
64-
.toList(); Path outputDir = classes(getProject(), false);
69+
.toList();
70+
Path outputDir = classes(getProject(), false);
6571

6672
ClassLoader classLoader = createClassLoader(projects);
6773

@@ -82,9 +88,10 @@ public void generate() throws Throwable {
8288

8389
OpenAPI result = tool.generate(mainClass);
8490

85-
for (OpenAPIGenerator.Format format : OpenAPIGenerator.Format.values()) {
86-
Path output = tool.export(result, format);
87-
getLogger().info(" writing: " + output);
91+
var adocPath = ofNullable(adoc).orElse(List.of()).stream().map(File::toPath).toList();
92+
for (var format : OpenAPIGenerator.Format.values()) {
93+
tool.export(result, format, Map.of("adoc", adocPath))
94+
.forEach(output -> getLogger().info(" writing: " + output));
8895
}
8996
}
9097

@@ -188,6 +195,26 @@ public void setSpecVersion(String specVersion) {
188195
this.specVersion = specVersion;
189196
}
190197

198+
/**
199+
* Optionally generates adoc output.
200+
*
201+
* @return List of adoc templates.
202+
*/
203+
@Input
204+
@org.gradle.api.tasks.Optional
205+
public List<File> getAdoc() {
206+
return adoc;
207+
}
208+
209+
/**
210+
* Set adoc templates to build.
211+
*
212+
* @param adoc Adoc templates to build.
213+
*/
214+
public void setAdoc(List<File> adoc) {
215+
this.adoc = adoc;
216+
}
217+
191218
private Optional<String> trim(String value) {
192219
if (value == null || value.trim().isEmpty()) {
193220
return Optional.empty();

modules/jooby-maven-plugin/src/main/java/io/jooby/maven/OpenAPIMojo.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
*/
66
package io.jooby.maven;
77

8+
import static java.util.Optional.ofNullable;
89
import static org.apache.maven.plugins.annotations.LifecyclePhase.PROCESS_CLASSES;
910
import static org.apache.maven.plugins.annotations.ResolutionScope.COMPILE_PLUS_RUNTIME;
1011

12+
import java.io.File;
1113
import java.nio.file.Path;
1214
import java.nio.file.Paths;
1315
import java.util.List;
16+
import java.util.Map;
1417
import java.util.Optional;
1518

1619
import org.apache.maven.plugins.annotations.Mojo;
@@ -20,7 +23,6 @@
2023
import edu.umd.cs.findbugs.annotations.NonNull;
2124
import edu.umd.cs.findbugs.annotations.Nullable;
2225
import io.jooby.openapi.OpenAPIGenerator;
23-
import io.swagger.v3.oas.models.OpenAPI;
2426

2527
/**
2628
* Generate an OpenAPI file from a jooby application.
@@ -47,6 +49,8 @@ public class OpenAPIMojo extends BaseMojo {
4749
@Parameter(property = "openAPI.specVersion")
4850
private String specVersion;
4951

52+
@Parameter private List<File> adoc;
53+
5054
@Override
5155
protected void doExecute(@NonNull List<MavenProject> projects, @NonNull String mainClass)
5256
throws Exception {
@@ -73,16 +77,17 @@ protected void doExecute(@NonNull List<MavenProject> projects, @NonNull String m
7377
trim(includes).ifPresent(tool::setIncludes);
7478
trim(excludes).ifPresent(tool::setExcludes);
7579

76-
OpenAPI result = tool.generate(mainClass);
80+
var result = tool.generate(mainClass);
7781

78-
for (OpenAPIGenerator.Format format : OpenAPIGenerator.Format.values()) {
79-
Path output = tool.export(result, format);
80-
getLog().info(" writing: " + output);
82+
var adocPath = ofNullable(adoc).orElse(List.of()).stream().map(File::toPath).toList();
83+
for (var format : OpenAPIGenerator.Format.values()) {
84+
tool.export(result, format, Map.of("adoc", adocPath))
85+
.forEach(output -> getLog().info(" writing: " + output));
8186
}
8287
}
8388

8489
private Optional<String> trim(String value) {
85-
if (value == null || value.trim().length() == 0) {
90+
if (value == null || value.trim().isEmpty()) {
8691
return Optional.empty();
8792
}
8893
return Optional.of(value.trim());
@@ -131,4 +136,12 @@ public String getSpecVersion() {
131136
public void setSpecVersion(String specVersion) {
132137
this.specVersion = specVersion;
133138
}
139+
140+
public List<File> getAdoc() {
141+
return adoc;
142+
}
143+
144+
public void setAdoc(List<File> adoc) {
145+
this.adoc = adoc;
146+
}
134147
}

modules/jooby-maven-plugin/src/main/java/io/jooby/maven/RunMojo.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.apache.maven.plugins.annotations.Mojo;
2525
import org.apache.maven.plugins.annotations.Parameter;
2626
import org.apache.maven.project.MavenProject;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
2729

2830
import io.jooby.run.JoobyRun;
2931
import io.jooby.run.JoobyRunOptions;
@@ -42,8 +44,10 @@
4244
@Execute(phase = PROCESS_CLASSES)
4345
public class RunMojo extends BaseMojo {
4446

47+
private static final Logger log = LoggerFactory.getLogger(RunMojo.class);
48+
4549
static {
46-
/** Turn off shutdown hook on Server. */
50+
/* Turn off shutdown hook on Server. */
4751
System.setProperty("jooby.useShutdownHook", "false");
4852
}
4953

@@ -97,7 +101,13 @@ protected void doExecute(List<MavenProject> projects, String mainClass) throws T
97101
var error = result.hasExceptions();
98102
// Success?
99103
if (error) {
100-
getLog().debug("Compilation error found: " + path);
104+
var filename = path.getFileName().toFile().toString();
105+
var isSource = filename.endsWith(".java") || filename.endsWith(".kt");
106+
for (Throwable exception : result.getExceptions()) {
107+
if (!isSource) {
108+
getLog().error(exception);
109+
}
110+
}
101111
}
102112
return !error;
103113
});
@@ -213,8 +223,7 @@ protected void setUseTestScope(boolean useTestScope) {
213223
* @return Request.
214224
*/
215225
private MavenExecutionRequest mavenRequest(String goal) {
216-
return DefaultMavenExecutionRequest.copy(session.getRequest())
217-
.setGoals(Collections.singletonList(goal));
226+
return DefaultMavenExecutionRequest.copy(session.getRequest()).setGoals(List.of(goal));
218227
}
219228

220229
private Set<Path> sourceDirectories(MavenProject project, boolean useTestScope) {

modules/jooby-openapi/pom.xml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@
5656
<artifactId>asciidoctorj</artifactId>
5757
<version>3.0.1</version>
5858
</dependency>
59-
59+
<dependency>
60+
<groupId>org.asciidoctor</groupId>
61+
<artifactId>asciidoctorj-pdf</artifactId>
62+
<version>2.3.23</version>
63+
</dependency>
6064
<dependency>
6165
<groupId>io.pebbletemplates</groupId>
6266
<artifactId>pebble</artifactId>
@@ -78,6 +82,12 @@
7882
<artifactId>guava</artifactId>
7983
</dependency>
8084

85+
<dependency>
86+
<groupId>jakarta.data</groupId>
87+
<artifactId>jakarta.data-api</artifactId>
88+
<version>1.0.1</version>
89+
</dependency>
90+
8191
<!-- Test dependencies -->
8292
<dependency>
8393
<groupId>org.junit.jupiter</groupId>

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/AsciiDocGenerator.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
import java.util.Map;
1414
import java.util.Optional;
1515

16+
import org.asciidoctor.Asciidoctor;
17+
import org.asciidoctor.Options;
18+
import org.asciidoctor.SafeMode;
19+
1620
import io.jooby.internal.openapi.asciidoc.Filters;
1721
import io.jooby.internal.openapi.asciidoc.Functions;
1822
import io.jooby.internal.openapi.asciidoc.SnippetResolver;
@@ -41,6 +45,23 @@ public static String generate(OpenAPIExt openAPI, Path index) throws IOException
4145
return writer.toString().trim();
4246
}
4347

48+
public static void export(Path baseDir, Path input, Path outputDir) {
49+
try (var asciidoctor = Asciidoctor.Factory.create()) {
50+
51+
var options =
52+
Options.builder()
53+
.backend("html5")
54+
.baseDir(baseDir.toFile())
55+
.toDir(outputDir.toFile())
56+
.mkDirs(true)
57+
.safe(SafeMode.UNSAFE)
58+
.build();
59+
60+
// Perform the conversion
61+
asciidoctor.convertFile(input.toFile(), options);
62+
}
63+
}
64+
4465
@SuppressWarnings("unchecked")
4566
private static PebbleEngine newEngine(OpenAPIExt openapi, Path baseDir) {
4667
var json = (openapi.getSpecVersion() == SpecVersion.V30 ? Json.mapper() : Json31.mapper());
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.internal.openapi;
7+
8+
import java.util.List;
9+
10+
import com.fasterxml.jackson.annotation.JsonProperty;
11+
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
12+
import com.fasterxml.jackson.databind.ObjectMapper;
13+
import io.swagger.annotations.ApiModelProperty;
14+
import jakarta.data.page.Page;
15+
import jakarta.data.page.PageRequest;
16+
17+
public class MixinHook {
18+
19+
@JsonPropertyOrder({
20+
"content",
21+
"numberOfElements",
22+
"totalElements",
23+
"totalPages",
24+
"pageRequest",
25+
"nextPageRequest",
26+
"previousPageRequest"
27+
})
28+
public abstract static class PageMixin<T> implements Page<T> {
29+
@JsonProperty("content")
30+
@Override
31+
public abstract List<T> content();
32+
33+
@JsonProperty("numberOfElements")
34+
@Override
35+
public abstract int numberOfElements();
36+
37+
@Override
38+
@JsonProperty("pageRequest")
39+
public abstract PageRequest pageRequest();
40+
41+
@Override
42+
@JsonProperty("nextPageRequest")
43+
public abstract PageRequest nextPageRequest();
44+
45+
@Override
46+
@JsonProperty("previousPageRequest")
47+
public abstract PageRequest previousPageRequest();
48+
49+
@Override
50+
@JsonProperty("totalElements")
51+
public abstract long totalElements();
52+
53+
@Override
54+
@JsonProperty("totalPages")
55+
public abstract long totalPages();
56+
}
57+
58+
@JsonPropertyOrder({"page", "size"})
59+
public abstract static class PageRequestMixin implements PageRequest {
60+
@JsonProperty("page")
61+
@Override
62+
@ApiModelProperty("The page to be returned")
63+
public abstract long page();
64+
65+
@JsonProperty("size")
66+
@Override
67+
@ApiModelProperty("The requested size of each page")
68+
public abstract int size();
69+
}
70+
71+
public static void mixin(ObjectMapper mapper) {
72+
mapper.addMixIn(jakarta.data.page.Page.class, PageMixin.class);
73+
mapper.addMixIn(jakarta.data.page.PageRequest.class, PageRequestMixin.class);
74+
}
75+
}

0 commit comments

Comments
 (0)