Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use JavaDoc as comments #2481

Merged
merged 1 commit into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,11 @@ public class ModuleBuilder {
private final Map<DotName, TopicsBuildItem.DiscoveredTopic> knownTopics;
private final Map<DotName, VerbClientBuildItem.DiscoveredClients> verbClients;
private final FTLRecorder recorder;
private final Map<String, String> verbDocs;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to make sure you know, most declarations in the FTL schema can include comments - data structures, enums, etc.


public ModuleBuilder(IndexView index, String moduleName, Map<DotName, TopicsBuildItem.DiscoveredTopic> knownTopics,
Map<DotName, VerbClientBuildItem.DiscoveredClients> verbClients, FTLRecorder recorder) {
Map<DotName, VerbClientBuildItem.DiscoveredClients> verbClients, FTLRecorder recorder,
Map<String, String> verbDocs) {
this.index = index;
this.moduleName = moduleName;
this.moduleBuilder = Module.newBuilder()
Expand All @@ -93,6 +95,7 @@ public ModuleBuilder(IndexView index, String moduleName, Map<DotName, TopicsBuil
this.knownTopics = knownTopics;
this.verbClients = verbClients;
this.recorder = recorder;
this.verbDocs = verbDocs;
}

public static @NotNull String methodToName(MethodInfo method) {
Expand Down Expand Up @@ -236,6 +239,9 @@ public void registerVerbMethod(MethodInfo method, String className,
.setExport(exported)
.setRequest(buildType(bodyParamType, exported))
.setResponse(buildType(method.returnType(), exported));
if (verbDocs.containsKey(verbName)) {
verbBuilder.addComments(verbDocs.get(verbName));
}

if (metadataCallback != null) {
metadataCallback.accept(verbBuilder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Base64;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -107,9 +110,24 @@ public void generateSchema(CombinedIndexBuildItem index,
VerbClientBuildItem verbClientBuildItem,
List<SchemaContributorBuildItem> schemaContributorBuildItems) throws Exception {
String moduleName = moduleNameBuildItem.getModuleName();
Map<String, String> verbDocs = new HashMap<>();
try (var input = Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/ftl-verbs.txt")) {
if (input != null) {
var contents = new String(input.readAllBytes(), StandardCharsets.UTF_8).split("\n");
for (var content : contents) {
var eq = content.indexOf('=');
if (eq == -1) {
continue;
}
String key = content.substring(0, eq);
String value = new String(Base64.getDecoder().decode(content.substring(eq + 1)), StandardCharsets.UTF_8);
verbDocs.put(key, value);
}
}
}

ModuleBuilder moduleBuilder = new ModuleBuilder(index.getComputingIndex(), moduleName, topicsBuildItem.getTopics(),
verbClientBuildItem.getVerbClients(), recorder);
verbClientBuildItem.getVerbClients(), recorder, verbDocs);

for (var i : schemaContributorBuildItems) {
i.getSchemaContributor().accept(moduleBuilder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ public String bytesHttp(byte[] data) {
return "Hello " + new String(data, StandardCharsets.UTF_8);
}

/**
* This is a verb FOOO
*
* @param name
* @param echoClient
* @return
*/
@Verb
public String hello(String name, EchoClient echoClient) {
return "Hello " + echoClient.call(new EchoRequest().setName(name)).getMessage();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package xyz.block.ftl.runtime.processor;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.annotation.processing.Completion;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;

import xyz.block.ftl.Verb;

/**
* POC annotation processor for capturing JavaDoc, this needs a lot more work.
*/
public class AnnotationProcessor implements Processor {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this run as part of the module JVM instance, or as part of the build?

private static final Pattern REMOVE_LEADING_SPACE = Pattern.compile("^ ", Pattern.MULTILINE);
private ProcessingEnvironment processingEnv;

final Map<String, String> saved = new HashMap<>();

@Override
public Set<String> getSupportedOptions() {
return Set.of();
}

@Override
public Set<String> getSupportedAnnotationTypes() {
return Set.of(Verb.class.getName());
}

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}

@Override
public void init(ProcessingEnvironment processingEnv) {
this.processingEnv = processingEnv;
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//TODO: @VerbName, HTTP, CRON etc
roundEnv.getElementsAnnotatedWith(Verb.class)
.forEach(element -> {
Optional<String> javadoc = getJavadoc(element);
javadoc.ifPresent(doc -> saved.put(element.getSimpleName().toString(), doc));
});

if (roundEnv.processingOver()) {
write("META-INF/ftl-verbs.txt", saved.entrySet().stream().map(
e -> e.getKey() + "=" + Base64.getEncoder().encodeToString(e.getValue().getBytes(StandardCharsets.UTF_8)))
.collect(Collectors.toSet()));
}
return false;
}

/**
* This method uses the annotation processor Filer API and we shouldn't use a Path as paths containing \ are not supported.
*/
public void write(String filePath, Set<String> set) {
if (set.isEmpty()) {
return;
}
try {
final FileObject listResource = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "",
filePath.toString());

try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(listResource.openOutputStream(), StandardCharsets.UTF_8))) {
for (String className : set) {
writer.write(className);
writer.newLine();
}
}
} catch (IOException e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Failed to write " + filePath + ": " + e);
return;
}
}

@Override
public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member,
String userText) {
return null;
}

public Optional<String> getJavadoc(Element e) {
String docComment = processingEnv.getElementUtils().getDocComment(e);

if (docComment == null || docComment.isBlank()) {
return Optional.empty();
}

// javax.lang.model keeps the leading space after the "*" so we need to remove it.

return Optional.of(REMOVE_LEADING_SPACE.matcher(docComment)
.replaceAll("")
.trim());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
xyz.block.ftl.runtime.processor.AnnotationProcessor
Loading