Skip to content

Add javadoc comments into generated code #76

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

Merged
merged 3 commits into from
Nov 3, 2020
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 @@ -4,8 +4,11 @@ class Constants {

static final String KOTLIN_METADATA = "kotlin.Metadata";
static final String GENERATED_9 = "javax.annotation.processing.Generated";
static final String GENERATED_LOCAL = "io.avaje.inject.spi.Generated";

static final String PROVIDER = "javax.inject.Provider";
static final String SINGLETON = "javax.inject.Singleton";
static final String INJECT = "javax.inject.Inject";

static final String PATH = "io.avaje.http.api.Path";
static final String CONTROLLER = "io.avaje.http.api.Controller";
Expand All @@ -14,19 +17,16 @@ class Constants {
static final String AT_GENERATED = "@Generated(\"io.avaje.inject.generator\")";
static final String META_INF_FACTORY = "META-INF/services/io.avaje.inject.spi.BeanContextFactory";

static final String BEANCONTEXT = "io.avaje.inject.BeanContext;";
static final String CONTEXTMODULE = "io.avaje.inject.ContextModule;";

static final String BEAN_FACTORY = "io.avaje.inject.spi.BeanFactory";
static final String BEAN_FACTORY2 = "io.avaje.inject.spi.BeanFactory2";
static final String BEAN_LIFECYCLE = "io.avaje.inject.spi.BeanLifecycle";
static final String BUILDER = "io.avaje.inject.spi.Builder";
static final String SINGLETON = "javax.inject.Singleton";
static final String INJECT = "javax.inject.Inject";

static final String IMPORT_CONTEXTMODULE = "import io.avaje.inject.ContextModule;";
static final String IMPORT_DEPENDENCYMETA = "import io.avaje.inject.spi.DependencyMeta;";
static final String IMPORT_BEANCONTEXT = "import io.avaje.inject.BeanContext;";
static final String IMPORT_BEANCONTEXTFACTORY = "import io.avaje.inject.spi.BeanContextFactory;";
static final String IMPORT_BUILDERFACTORY = "import io.avaje.inject.spi.BuilderFactory;";
static final String IMPORT_BUILDER = "import io.avaje.inject.spi.Builder;";
static final String DEPENDENCYMETA = "io.avaje.inject.spi.DependencyMeta;";
static final String BEANCONTEXTFACTORY = "io.avaje.inject.spi.BeanContextFactory;";
static final String BUILDERFACTORY = "io.avaje.inject.spi.BuilderFactory;";

static boolean isBeanLifecycle(String type) {
return BEAN_LIFECYCLE.equals(type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ private boolean hasMethod() {
}

private void appendProvides(StringBuilder sb, String attribute, List<String> types) {
sb.append(",").append(attribute).append("={");
sb.append(", ").append(attribute).append("={");
for (int i = 0; i < types.size(); i++) {
if (i > 0) {
sb.append(",");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@

class MethodReader {

private static final String CODE_COMMENT_LIFECYCLE =" /**\n * Lifecycle wrapper for %s.\n */";
private static final String CODE_COMMENT_BUILD_FACTORYBEAN = " /**\n * Create and register %s via factory bean method %s#%s().\n */";

private final ProcessingContext context;
private final ExecutableElement element;
private final String factoryType;
private final String methodName;
private final TypeMirror returnType;
private final String returnTypeRaw;
private final String shortName;
Expand All @@ -40,6 +44,7 @@ class MethodReader {
this.isFactory = bean != null;
this.context = context;
this.element = element;
this.methodName = element.getSimpleName().toString();
this.returnType = element.getReturnType();
this.returnTypeRaw = returnType.toString();
this.shortName = Util.shortName(returnTypeRaw);
Expand All @@ -52,6 +57,10 @@ class MethodReader {
initInterfaces();
}

String getName() {
return methodName;
}

private void initInterfaces() {
Element element = context.asElement(returnType);
if (element instanceof TypeElement) {
Expand Down Expand Up @@ -84,9 +93,6 @@ List<MethodParam> getParams() {
return params;
}

String getName() {
return element.getSimpleName().toString();
}

MetaData createMeta() {

Expand All @@ -112,15 +118,12 @@ String builderGetFactory() {
}

String builderBuildBean() {

String methodName = element.getSimpleName().toString();
StringBuilder sb = new StringBuilder();
if (isVoid) {
sb.append(String.format(" factory.%s(", methodName));
} else {
sb.append(String.format(" %s bean = factory.%s(", Util.shortName(returnTypeRaw), methodName));
}

for (int i = 0; i < params.size(); i++) {
if (i > 0) {
sb.append(",");
Expand All @@ -135,7 +138,7 @@ void builderBuildAddBean(Append writer) {
if (!isVoid) {
writer.append(" ");
if (beanLifeCycle || hasLifecycleMethods()) {
writer.append(" %s $bean = ", shortName);
writer.append("%s $bean = ", shortName);
}
writer.append("builder.register(bean, ");
if (name == null) {
Expand Down Expand Up @@ -197,7 +200,7 @@ void buildLifecycleClass(Append writer) {
if (!hasLifecycleMethods()) {
return;
}

writer.append(CODE_COMMENT_LIFECYCLE, shortName).eol();
writer.append(" static class %s$lifecycle implements BeanLifecycle {", shortName).eol().eol();
writer.append(" final %s bean;", shortName).eol().eol();
writer.append(" %s$lifecycle(%s bean) {", shortName, shortName).eol();
Expand Down Expand Up @@ -251,6 +254,10 @@ void writeRequestConstructor(Append writer) {
}
}

public void commentBuildMethod(Append writer) {
writer.append(CODE_COMMENT_BUILD_FACTORYBEAN, shortName, factoryShortName, methodName).eol();
}

static class MethodParam {

private final String named;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class ProcessingContext {
}

private String generatedAnnotation(boolean jdk8) {
return jdk8 ? null : isTypeAvailable(Constants.GENERATED_9) ? Constants.GENERATED_9 : null;
return jdk8 ? Constants.GENERATED_LOCAL : isTypeAvailable(Constants.GENERATED_9) ? Constants.GENERATED_9 : Constants.GENERATED_LOCAL;
Copy link
Contributor

Choose a reason for hiding this comment

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

What about just switching to always using a local @Generated annotation regardless of the JDK version or if JPMS is in use?
I think that's what Lombok finally decided to do.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that is pretty tempting. I've had a little discussion on the jigsaw mailing list about this and at this stage I'm pretty confident that we ultimately can't use javax.annotation.processing.Generated with JPMS so just using the local one makes more and more sense to me now.

}

private boolean isTypeAvailable(String canonicalName) {
Expand Down Expand Up @@ -151,6 +151,10 @@ void deriveContextName(String factoryPackage) {
}
}

String contextName() {
return contextName;
}

String getContextPackage() {
return contextPackage;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
*/
class SimpleBeanWriter {

private static final String CODE_COMMENT = "/**\n * Generated source - dependency injection builder for %s.\n */";
private static final String CODE_COMMENT_FACTORY = "/**\n * Generated source - dependency injection factory for request scoped %s.\n */";
private static final String CODE_COMMENT_LIFECYCLE =" /**\n * Lifecycle wrapper for %s.\n */";
private static final String CODE_COMMENT_BUILD = " /**\n * Create and register %s.\n */";

private final BeanReader beanReader;
private final ProcessingContext context;
private final String originName;
Expand Down Expand Up @@ -73,6 +78,7 @@ private void writeStaticFactoryBeanLifecycle() {
}

private void writeFactoryBeanMethod(MethodReader method) {
method.commentBuildMethod(writer);
writer.append(" public static void build_%s(Builder builder) {", method.getName()).eol();
method.buildAddFor(writer);
writer.append(method.builderGetFactory()).eol();
Expand All @@ -91,6 +97,7 @@ private void writeStaticFactoryMethod() {
}

int providerIndex = 0;
writer.append(CODE_COMMENT_BUILD, shortName).eol();
writer.append(" public static void build(Builder builder");
for (MethodReader.MethodParam param : constructor.getParams()) {
if (param.isGenericType()) {
Expand Down Expand Up @@ -125,6 +132,7 @@ private void writeStaticFactoryMethod() {
}
if (beanReader.isFieldInjectionRequired() || beanReader.isMethodInjectionRequired()) {
writer.append(" builder.addInjector(b -> {").eol();
writer.append(" // field and method injection").eol();
for (FieldReader fieldReader : beanReader.getInjectFields()) {
String fieldName = fieldReader.getFieldName();
String getDependency = fieldReader.builderGetDependency();
Expand Down Expand Up @@ -166,6 +174,7 @@ private void lifecycleMethod(String method, Element methodElement) {
private void writeLifecycleWrapper() {
if (beanReader.isLifecycleWrapperRequired()) {
writer.append(" private final %s bean;", shortName).eol().eol();
writer.append(CODE_COMMENT_LIFECYCLE, shortName).eol();
writer.append(" public %s%s(%s bean) {", shortName, suffix, shortName).eol();
writer.append(" this.bean = bean;").eol();
writer.append(" }").eol().eol();
Expand All @@ -180,6 +189,11 @@ private void writeClassEnd() {
}

private void writeClassStart() {
if (beanReader.isRequestScoped()) {
writer.append(CODE_COMMENT_FACTORY, shortName).eol();
} else {
writer.append(CODE_COMMENT, shortName).eol();
}
if (context.isGeneratedAvailable()) {
writer.append(Constants.AT_GENERATED).eol();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,47 @@
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;
import java.util.TreeSet;

/**
* Write the source code for the factory.
*/
class SimpleFactoryWriter {

private static final String CODE_COMMENT_FACTORY =
"/**\n" +
" * Generated source - Creates the BeanContext for the %s module.\n" +
" * \n" +
" * With JPMS Java module system this generated class should be explicitly\n" +
" * registered in module-info via a <code>provides</code> clause like:\n" +
" * \n" +
" * <pre>{@code\n" +
" * \n" +
" * module example {\n" +
" * requires io.avaje.inject;\n" +
" * \n" +
" * provides io.avaje.inject.spi.BeanContextFactory with %s._di$BeanContextFactory;\n" +
" * \n" +
" * }\n" +
" * \n" +
" * }</pre>\n" +
" */";

private static final String CODE_COMMENT_CREATE_CONTEXT =
" /**\n" +
" * Create and return the BeanContext.\n" +
" * <p>\n" +
" * Creates all the beans in order based on constuctor dependencies.\n" +
" * The beans are registered into the builder along with callbacks for\n" +
" * field injection, method injection and lifecycle support.\n" +
" * <p>\n" +
" * Ultimately the builder returns the BeanContext containing the beans.\n" +
" *\n" +
" * @param parent The parent context for multi-module wiring\n" +
" * @return The BeanContext containing the beans\n" +
" */";

private final MetaDataOrdering ordering;
private final ProcessingContext context;

Expand Down Expand Up @@ -69,9 +104,12 @@ private void writeBuildMethods() {

private void writeCreateMethod() {

writer.append(CODE_COMMENT_CREATE_CONTEXT).eol();
writer.append(" @Override").eol();
writer.append(" public BeanContext createContext(Builder parent) {").eol();
writer.append(" builder.setParent(parent);").eol();
writer.append(" // create beans in order based on constructor dependencies").eol();
writer.append(" // i.e. \"provides\" followed by \"dependsOn\"").eol();
for (MetaData metaData : ordering.getOrdered()) {
writer.append(" build_%s();", metaData.getBuildName()).eol();
}
Expand All @@ -81,20 +119,10 @@ private void writeCreateMethod() {
}

private void writePackage() {

writer.append("package %s;", factoryPackage).eol().eol();

final String generated = context.getGeneratedAnnotation();
if (generated != null) {
writer.append("import %s;", generated).eol();
for (String type : factoryImportTypes()) {
writer.append("import %s;", type).eol();
}
writer.append(Constants.IMPORT_BEANCONTEXT).eol();
writer.append(Constants.IMPORT_CONTEXTMODULE).eol();
writer.append(Constants.IMPORT_DEPENDENCYMETA).eol().eol();
writer.append(Constants.IMPORT_BEANCONTEXTFACTORY).eol();
writer.append(Constants.IMPORT_BUILDER).eol();
writer.append(Constants.IMPORT_BUILDERFACTORY).eol();

for (String type : ordering.getImportTypes()) {
if (Util.validImportType(type)) {
writer.append("import %s;", type).eol();
Expand All @@ -103,8 +131,24 @@ private void writePackage() {
writer.eol();
}

private Set<String> factoryImportTypes() {
Set<String> importTypes = new TreeSet<>();
final String generated = context.getGeneratedAnnotation();
if (generated != null) {
importTypes.add(generated);
}
importTypes.add(Constants.BEANCONTEXT);
importTypes.add(Constants.CONTEXTMODULE);
importTypes.add(Constants.DEPENDENCYMETA);
importTypes.add(Constants.BEANCONTEXTFACTORY);
importTypes.add(Constants.BUILDER);
importTypes.add(Constants.BUILDERFACTORY);
return importTypes;
}

private void writeStartClass() {

writer.append(CODE_COMMENT_FACTORY, context.contextName(), factoryPackage).eol();
context.buildAtContextModule(writer);

writer.append("public class %s implements BeanContextFactory {", factoryShortName).eol().eol();
Expand Down Expand Up @@ -138,4 +182,5 @@ private Writer createFileWriter() throws IOException {
JavaFileObject jfo = context.createWriter(factoryFullName);
return jfo.openWriter();
}

}
2 changes: 1 addition & 1 deletion inject/src/main/java/io/avaje/inject/spi/Builder.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public interface Builder {
void addLifecycle(BeanLifecycle bean);

/**
* Add a field injector.
* Add field and method injection.
*/
void addInjector(Consumer<Builder> injector);

Expand Down
19 changes: 19 additions & 0 deletions inject/src/main/java/io/avaje/inject/spi/Generated.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.avaje.inject.spi;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Marks source code that has been generated.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Generated {

/**
* The name of the generator used to generate this source.
*/
String value();
}