Skip to content

Commit

Permalink
#2 add factoryVisibility and factoryMethodName, use javax.inject.Prov…
Browse files Browse the repository at this point in the history
…ider in factory for for injected fields
  • Loading branch information
stCarolas committed Jul 13, 2020
1 parent b224513 commit 1303aa3
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .mvn/maven.config
Original file line number Diff line number Diff line change
@@ -1 +1 @@
-Drevision=0.2.3
-Drevision=0.3.0
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,34 @@ Its the same but with fewer code - annotations lies on fields so you can use gen
</plugin>
```

### Factory customization
Compiler args listed below can be passed
to define some aspects of generated factories

1. `factoryMethodName`. Default value: "from".
1. `factoryVisibility`. Available values: "public","package". Default value: "public".

Configuration example:
```xml
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<compilerArguments>
<AmethodName>to</AmethodName>
<Avisibility>package</Avisibility>
</compilerArguments>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>com.github.stcarolas.enriched-beans</groupId>
<artifactId>enriched-beans-processor</artifactId>
<version>${revision}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</plugin>
```

### How to view generated sources
All generated factories lies in `$buildDir/generated/sources/annotationProcessor/java/main` directory if using gradle and `target/generated-sources/annotations` if using maven

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package com.github.stcarolas.enrichedbeans.processor;
package com.github.stcarolas.enrichedbeans.processor;

import com.squareup.javapoet.TypeName;
import org.immutables.value.Value;

import io.vavr.collection.Seq;
import lombok.RequiredArgsConstructor;

@Value.Immutable
public interface AssistingFactoryConfig {
String factoryMethodName();
String factoryClassName();
String factoryMethodName();
TypeName targetType();
Seq<Field> injectingFields();
Seq<Field> instanceFields();
FactoryVisibility visibility();
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,56 @@
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import io.vavr.Function2;
import io.vavr.collection.Seq;
import lombok.RequiredArgsConstructor;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.ClassName;

public class CreateAssistingFactory {

public TypeSpec apply(
String factoryName,
TypeName targetType,
Seq<Field> injectingFields,
Seq<Field> instanceFields,
AssistingFactoryConfig config
) {
return classBuilder(factoryName)
public TypeSpec apply(AssistingFactoryConfig config) {
Builder factory = classBuilder(config.factoryClassName())
.addAnnotation(Singleton.class)
.addAnnotation(Named.class)
.addModifiers(Modifier.PUBLIC)
.addFields(injectingFields.map(privateFactoryField))
.addMethod(constructor(injectingFields))
.addMethod(factoryMethod(instanceFields, injectingFields, targetType))
.build();
.addFields(config.injectingFields().map(privateFactoryField))
.addMethod(constructor(config.injectingFields()))
.addMethod(
factoryMethod(
config.factoryMethodName(),
config.instanceFields(),
config.injectingFields(),
config.targetType()
)
);
if (config.visibility() == FactoryVisibility.PUBLIC) {
factory.addModifiers(Modifier.PUBLIC);
}
return factory.build();
}

private Function<Field, ParameterizedTypeName> provider = field -> ParameterizedTypeName.get(
ClassName.get("javax.inject", "Provider"),
field.typeName()
);

private Function<Field, FieldSpec> privateFactoryField = field -> FieldSpec.builder(
field.typeName(),
provider.apply(field),
field.name(),
Modifier.PRIVATE
)
.build();

private MethodSpec constructor(Seq<Field> fields) {
return fields.foldLeft(
MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Inject.class)
.build(),
addParameterWithAssignment
);
return fields.map(field -> field.withType(provider.apply(field)))
.foldLeft(
MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Inject.class)
.build(),
addParameterWithAssignment
);
}

private Function2<MethodSpec, Field, MethodSpec> addParameter = (method, field) -> method.toBuilder()
Expand All @@ -64,24 +76,33 @@ private MethodSpec constructor(Seq<Field> fields) {
.build();

private MethodSpec factoryMethod(
String name,
Seq<Field> signatureFields,
Seq<Field> objectFields,
TypeName returnType
) {
return signatureFields.foldLeft(
MethodSpec.methodBuilder("from")
MethodSpec.methodBuilder(name)
.returns(returnType)
.addModifiers(Modifier.PUBLIC)
.build(),
addParameter
)
.toBuilder()
.addCode(returnLine(signatureFields.appendAll(objectFields), returnType))
.addCode(
returnLine(
signatureFields.map(Field::name)
.appendAll(
objectFields.map(field -> field.name())
.map(fieldName -> fieldName + ".get()")
),
returnType
)
)
.build();
}

private String returnLine(Seq<Field> fields, TypeName returnType) {
return fields.map(Field::name)
.mkString("return new " + returnType.toString() + "(", ",", ");");
private String returnLine(Seq<String> fields, TypeName returnType) {
return fields.mkString("return new " + returnType.toString() + "(", ",", ");");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,48 +31,62 @@

@AutoService(Processor.class)
@SupportedAnnotationTypes("com.github.stcarolas.enrichedbeans.annotations.Enrich")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EnrichProcessor extends AbstractProcessor {

@Override
public boolean process(
java.util.Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv
) {
Seq<Try<Void>> created = collectBeans(
roundEnv.getElementsAnnotatedWith(Enrich.class)
)
.map(TargetBean::new)
.map(factorySource)
.map(source -> run(() -> source.writeTo(processingEnv.getFiler())));
Seq<Try<Void>> created = collectBeans(
roundEnv.getElementsAnnotatedWith(Enrich.class)
)
.map(TargetBean::new)
.map(factorySource)
.map(source -> run(() -> source.writeTo(processingEnv.getFiler())));

return !created.exists(Try::isFailure);
return !created.exists(Try::isFailure);
}

private Seq<TypeElement> collectBeans(
java.util.Set<? extends Element> annotatedElements
) {
return List.ofAll(annotatedElements)
.map(element -> (TypeElement) element.getEnclosingElement())
.distinct();
return List.ofAll(annotatedElements)
.map(element -> (TypeElement) element.getEnclosingElement())
.distinct();
}

private JavaFile sourceFile(String packageName, TypeSpec javaClass) {
return JavaFile.builder(packageName, javaClass).build();
return JavaFile.builder(packageName, javaClass).build();
}

private Function<TargetBean, JavaFile> factorySource = bean -> sourceFile(
bean.packageName(),
factory(bean)
bean.packageName(),
factory(bean)
);

private TypeSpec factory(TargetBean bean) {
return new CreateAssistingFactory().apply(
bean.name() + "Factory",
bean.type(),
bean.allFields().filter(Field::isEnriched),
bean.allFields().reject(Field::isEnriched),
ImmutableAssistingFactoryConfig.builder().build()
);
return new CreateAssistingFactory()
.apply(
ImmutableAssistingFactoryConfig.builder()
.factoryClassName(bean.name() + "Factory")
.factoryMethodName(detectFactoryMethodName())
.targetType(bean.type())
.visibility(detectVisibility())
.instanceFields(bean.allFields().reject(Field::isEnriched))
.injectingFields(bean.allFields().filter(Field::isEnriched))
.build()
);
}

private String detectFactoryMethodName() {
String methodName = processingEnv.getOptions().get("factoryMethodName");
return methodName == null ? "from" : methodName;
}

private FactoryVisibility detectVisibility() {
return "package".equals(processingEnv.getOptions().get("factoryVisibility"))
? FactoryVisibility.PACKAGE
: FactoryVisibility.PUBLIC;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.github.stcarolas.enrichedbeans.processor;

public enum FactoryVisibility {
PUBLIC, PACKAGE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,45 @@ public static Field from(
String name,
TypeName type,
List<AnnotationMirror> annotations
) {
return from(name, type, annotations, List());
}

public static Field from(
String name,
TypeName type,
List<AnnotationMirror> annotations,
List<Modifier> modifiers
) {
Field field = new Field();
field.name = name;
field.type = type;
field.modifiers = List();
field.modifiers = modifiers;
field.annotationMirrors = annotations;
return field;
}

public Field withName(
String name
) {
return from(name, this.type, this.annotationMirrors, this.modifiers);
}

public Field withType(
TypeName type
) {
return from(this.name, type, this.annotationMirrors, this.modifiers);
}

public Field withAnnotations(
List<AnnotationMirror> annotationMirrors
) {
return from(this.name, this.type, annotationMirrors, this.modifiers);
}

public Field withModifiers(
List<Modifier> modifiers
) {
return from(this.name, this.type, this.annotationMirrors, modifiers);
}
}

0 comments on commit 1303aa3

Please sign in to comment.