Skip to content

Commit

Permalink
module impl (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
h908714124 authored Dec 25, 2023
1 parent e597d2a commit 52dfef8
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 181 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@

import io.jbock.simple.Component;
import io.jbock.simple.Inject;
import io.jbock.simple.Provides;
import io.jbock.simple.processor.binding.Binding;
import io.jbock.simple.processor.binding.ComponentElement;
import io.jbock.simple.processor.binding.Key;
import io.jbock.simple.processor.binding.KeyFactory;
import io.jbock.simple.processor.graph.TopologicalSorter;
import io.jbock.simple.processor.util.TypeTool;
import io.jbock.simple.processor.writing.Generator;
import io.jbock.simple.processor.writing.ComponentImpl;
import io.jbock.simple.processor.writing.Context;
import io.jbock.simple.processor.writing.ContextModule;
import io.jbock.simple.processor.writing.NamedBinding;

import javax.lang.model.element.TypeElement;
import java.util.List;
import java.util.Map;

@Component
@Component(modules = ContextModule.class)
public interface ContextComponent {

@Component.Builder
Expand All @@ -25,10 +33,17 @@ interface Builder {
KeyFactory keyFactory();

ComponentElement componentElement();

Generator generator();

TopologicalSorter topologicalSorter();
ComponentImpl componentImpl();

@Provides
static Context createContext(
TopologicalSorter topologicalSorter,
KeyFactory keyFactory) {
List<Binding> bindings = topologicalSorter.sortedBindings();
Map<Key, NamedBinding> sorted = ContextModule.addNames(keyFactory, bindings);
return new Context(sorted, ContextModule.createNames(sorted));
}

final class Factory {
private final TypeTool tool;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import io.jbock.javapoet.ParameterSpec;
import io.jbock.javapoet.ParameterizedTypeName;
import io.jbock.javapoet.TypeName;
import io.jbock.simple.Provides;
import io.jbock.simple.processor.util.Visitors;
import io.jbock.simple.processor.writing.NamedBinding;

Expand All @@ -30,26 +29,17 @@ public final class InjectBinding extends Binding {

private final KeyFactory keyFactory;

private static final List<String> PROVIDES_METHOD_COMMON_PREFIXES = List.of(
"get",
"provides",
"provide",
"create");

private final Supplier<String> suggestedVariableName = memoize(() -> {
if (element().getAnnotation(Provides.class) != null) {
return lowerFirst(removeMethodNamePrefix(element().getSimpleName().toString()));
}
Element enclosing = element().getEnclosingElement();
if (enclosing != null) {
if (keyFactory().tool().isSameType(key().type(), enclosing.asType())) {
TypeElement enclosingOuter = Visitors.TYPE_ELEMENT_VISITOR.visit(enclosing.getEnclosingElement());
if (enclosingOuter != null && keyFactory().tool().isSameType(key().type(), enclosing.asType())) {
return lowerFirst(enclosingOuter.getSimpleName().toString() + simpleName(key().typeName()));
}
} else {
return lowerFirst(enclosing.getSimpleName().toString() + simpleName(key().typeName()));
}
if (enclosing == null) {
return lowerFirst(simpleName(key().typeName()));
}
if (!keyFactory().tool().isSameType(key().type(), enclosing.asType())) {
return lowerFirst(enclosing.getSimpleName().toString() + simpleName(key().typeName()));
}
TypeElement enclosingOuter = Visitors.TYPE_ELEMENT_VISITOR.visit(enclosing.getEnclosingElement());
if (enclosingOuter != null && keyFactory().tool().isSameType(key().type(), enclosing.asType())) {
return lowerFirst(enclosingOuter.getSimpleName().toString() + simpleName(key().typeName()));
}
return lowerFirst(simpleName(key().typeName()));
});
Expand All @@ -61,15 +51,6 @@ private String simpleName(TypeName typeName) {
return verySimpleTypeName(typeName.toString());
}

private static String removeMethodNamePrefix(String s) {
for (String p : PROVIDES_METHOD_COMMON_PREFIXES) {
if (s.startsWith(p) && s.length() > p.length()) {
return s.substring(p.length());
}
}
return s;
}

static String simpleTypeName(ParameterizedTypeName type) {
StringBuilder sb = new StringBuilder();
sb.append(type.rawType.simpleName());
Expand All @@ -92,6 +73,9 @@ static String verySimpleTypeName(String typeName) {
if (i >= 0) {
typeName = typeName.substring(i + 1);
}
if (Character.isLowerCase(typeName.charAt(0))) {
typeName = Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1);
}
return typeName;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
import io.jbock.javapoet.TypeSpec;
import io.jbock.simple.Component;
import io.jbock.simple.Inject;
import io.jbock.simple.Modulus;
import io.jbock.simple.processor.ContextComponent;
import io.jbock.simple.processor.binding.Binding;
import io.jbock.simple.processor.binding.KeyFactory;
import io.jbock.simple.processor.util.SpecWriter;
import io.jbock.simple.processor.util.TypeTool;
import io.jbock.simple.processor.util.ValidationFailure;
import io.jbock.simple.processor.validation.ExecutableElementValidator;
import io.jbock.simple.processor.validation.TypeElementValidator;
import io.jbock.simple.processor.writing.Generator;

import javax.annotation.processing.Messager;
import javax.lang.model.element.Element;
Expand Down Expand Up @@ -73,6 +72,11 @@ private void process(TypeElement typeElement) {
typeElementValidator.validate(typeElement);
ContextComponent context = contextComponentFactory.create(typeElement);
KeyFactory keyFactory = context.keyFactory();
for (TypeElement module : context.componentElement().modules()) {
if (module.getAnnotation(Modulus.class) == null) {
throw new ValidationFailure("The module must be annotated with @Modulus", typeElement);
}
}
keyFactory.factoryElement().ifPresent(factory -> {
ExecutableElement method = factory.singleAbstractMethod();
if (!tool.types().isSameType(method.getReturnType(), typeElement.asType())) {
Expand All @@ -84,9 +88,7 @@ private void process(TypeElement typeElement) {
executableElementValidator.validate(m);
}
}
Generator generator = context.generator();
List<Binding> bindings = context.topologicalSorter().sortedBindings();
TypeSpec typeSpec = generator.generate(bindings);
TypeSpec typeSpec = context.componentImpl().generate();
specWriter.write(context.componentElement().generatedClass(), typeSpec);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.jbock.auto.common.BasicAnnotationProcessor.Step;
import io.jbock.simple.Component;
import io.jbock.simple.Inject;
import io.jbock.simple.Modulus;
import io.jbock.simple.Provides;
import io.jbock.simple.processor.util.ValidationFailure;

Expand Down Expand Up @@ -50,8 +51,8 @@ public Set<? extends Element> process(Map<String, Set<Element>> elementsByAnnota
throw new ValidationFailure("The @Provides method may not return void", m);
}
Element enclosing = m.getEnclosingElement();
if (enclosing.getAnnotation(Component.class) == null) {
throw new ValidationFailure("The @Provides method must be nested inside a @Component", m);
if (enclosing.getAnnotation(Component.class) == null && enclosing.getAnnotation(Modulus.class) == null) {
throw new ValidationFailure("The @Provides method must be nested inside a @Component or @Modulus", m);
}
bindingRegistry.register(m);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;

public class BuilderImpl {
public final class BuilderImpl {

private final ComponentElement component;
private final Map<Key, NamedBinding> sorted;
private final Function<Key, ParameterSpec> names;

private BuilderImpl(
@Inject
public BuilderImpl(
ComponentElement component,
Map<Key, NamedBinding> sorted,
Function<Key, ParameterSpec> names) {
Context context) {
this.component = component;
this.sorted = sorted;
this.names = names;
this.sorted = context.sorted();
this.names = context.names();
}

TypeSpec generate(BuilderElement builder, MockBuilder mockBuilder) {
Expand Down Expand Up @@ -136,22 +136,4 @@ private List<CodeBlock> constructorParameters() {
}
return result;
}

public static final class Factory {
private final ComponentElement component;

@Inject
public Factory(ComponentElement component) {
this.component = component;
}

BuilderImpl create(
Map<Key, NamedBinding> sorted,
Function<Key, ParameterSpec> names) {
return new BuilderImpl(
component,
sorted,
names);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,26 @@ public class ComponentImpl {
private final FactoryImpl factoryImpl;
private final Modifier[] modifiers;

private ComponentImpl(
@Inject
public ComponentImpl(
KeyFactory keyFactory,
ComponentElement component,
Map<Key, NamedBinding> sorted,
Function<Key, ParameterSpec> names,
Context context,
MockBuilder mockBuilder,
BuilderImpl builderImpl,
FactoryImpl factoryImpl) {
this.keyFactory = keyFactory;
this.component = component;
this.sorted = sorted;
this.names = names;
this.sorted = context.sorted();
this.names = context.names();
this.modifiers = component.element().getModifiers().stream()
.filter(m -> m == PUBLIC).toArray(Modifier[]::new);
this.mockBuilder = mockBuilder;
this.builderImpl = builderImpl;
this.factoryImpl = factoryImpl;
}

TypeSpec generate() {
public TypeSpec generate() {
TypeSpec.Builder spec = TypeSpec.classBuilder(component.generatedClass())
.addModifiers(modifiers)
.addModifiers(FINAL)
Expand Down Expand Up @@ -219,38 +219,4 @@ private MethodSpec generateAllParametersConstructor() {
}
return constructor.build();
}

public static final class Factory {
private final KeyFactory keyFactory;
private final ComponentElement component;
private final MockBuilder.Factory mockBuilderFactory;
private final BuilderImpl.Factory builderImplFactory;
private final FactoryImpl.Factory factoryImplFactory;

@Inject
public Factory(
KeyFactory keyFactory,
ComponentElement component,
MockBuilder.Factory mockBuilderFactory,
BuilderImpl.Factory builderImplFactory,
FactoryImpl.Factory factoryImplFactory) {
this.keyFactory = keyFactory;
this.component = component;
this.mockBuilderFactory = mockBuilderFactory;
this.builderImplFactory = builderImplFactory;
this.factoryImplFactory = factoryImplFactory;
}

ComponentImpl create(
Map<Key, NamedBinding> sorted,
Function<Key, ParameterSpec> names) {
return new ComponentImpl(
keyFactory, component,
sorted,
names,
mockBuilderFactory.create(sorted, names),
builderImplFactory.create(sorted, names),
factoryImplFactory.create(sorted, names));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.jbock.simple.processor.writing;

import io.jbock.javapoet.ParameterSpec;
import io.jbock.simple.processor.binding.Key;

import java.util.Map;
import java.util.function.Function;

public final class Context {

private final Map<Key, NamedBinding> sorted;
private final Function<Key, ParameterSpec> names;

public Context(Map<Key, NamedBinding> sorted, Function<Key, ParameterSpec> names) {
this.sorted = sorted;
this.names = names;
}

Map<Key, NamedBinding> sorted() {
return sorted;
}

Function<Key, ParameterSpec> names() {
return names;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package io.jbock.simple.processor.writing;

import io.jbock.javapoet.ParameterSpec;
import io.jbock.javapoet.TypeSpec;
import io.jbock.simple.Inject;
import io.jbock.simple.Modulus;
import io.jbock.simple.processor.binding.Binding;
import io.jbock.simple.processor.binding.Key;
import io.jbock.simple.processor.binding.KeyFactory;
Expand All @@ -15,25 +14,12 @@
import java.util.Map;
import java.util.function.Function;

public class Generator {
@Modulus
public interface ContextModule {

private final ComponentImpl.Factory componentImpl;
private final KeyFactory keyFactory;

@Inject
public Generator(
ComponentImpl.Factory componentImpl,
KeyFactory keyFactory) {
this.componentImpl = componentImpl;
this.keyFactory = keyFactory;
}

public TypeSpec generate(List<Binding> bindings) {
Map<Key, NamedBinding> sorted = addNames(bindings);
return componentImpl.create(sorted, createNames(sorted)).generate();
}

private Map<Key, NamedBinding> addNames(List<Binding> bindings) {
static Map<Key, NamedBinding> addNames(
KeyFactory keyFactory,
List<Binding> bindings) {
UniqueNameSet uniqueNameSet = new UniqueNameSet();
uniqueNameSet.claim("mockBuilder");
uniqueNameSet.claim("withMocks");
Expand All @@ -47,7 +33,7 @@ private Map<Key, NamedBinding> addNames(List<Binding> bindings) {
return result;
}

private static Function<Key, ParameterSpec> createNames(
static Function<Key, ParameterSpec> createNames(
Map<Key, NamedBinding> sorted) {
Map<Key, ParameterSpec> cache = new HashMap<>();
return key -> {
Expand Down Expand Up @@ -98,4 +84,5 @@ private static String protectAgainstKeywords(String candidateName) {
return SourceVersion.isKeyword(candidateName) ? candidateName + '_' : candidateName;
}
}

}
Loading

0 comments on commit 52dfef8

Please sign in to comment.