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

make componentElement available in keyFactory #56

Merged
merged 1 commit into from
Dec 24, 2023
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 @@ -3,7 +3,6 @@
import io.jbock.simple.Component;
import io.jbock.simple.Inject;
import io.jbock.simple.processor.binding.ComponentElement;
import io.jbock.simple.processor.binding.InjectBindingFactory;
import io.jbock.simple.processor.binding.KeyFactory;
import io.jbock.simple.processor.graph.TopologicalSorter;
import io.jbock.simple.processor.util.TypeTool;
Expand All @@ -20,40 +19,30 @@ interface Builder {

Builder tool(TypeTool tool);

Builder injectBindingFactory(InjectBindingFactory injectBindingFactory);

Builder keyFactory(KeyFactory keyFactory);

ContextComponent build();
}

ComponentElement componentElement();
KeyFactory keyFactory();

ComponentElement componentElement();

Generator generator();

TopologicalSorter topologicalSorter();

final class Factory {
private final TypeTool tool;
private final InjectBindingFactory injectBindingFactory;
private final KeyFactory keyFactory;

@Inject
public Factory(
TypeTool tool,
InjectBindingFactory injectBindingFactory,
KeyFactory keyFactory) {
TypeTool tool) {
this.tool = tool;
this.injectBindingFactory = injectBindingFactory;
this.keyFactory = keyFactory;
}

public ContextComponent create(TypeElement typeElement) {
return ContextComponent_Impl.builder()
.typeElement(typeElement)
.tool(tool)
.injectBindingFactory(injectBindingFactory)
.keyFactory(keyFactory)
.build();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import io.jbock.simple.Component;
import io.jbock.simple.Provides;
import io.jbock.simple.processor.binding.InjectBindingFactory;
import io.jbock.simple.processor.binding.KeyFactory;
import io.jbock.simple.processor.binding.InjectBindingCache;
import io.jbock.simple.processor.binding.KeyCache;
import io.jbock.simple.processor.step.ComponentFactoryStep;
import io.jbock.simple.processor.step.ComponentStep;
import io.jbock.simple.processor.step.InjectStep;
Expand Down Expand Up @@ -48,10 +48,10 @@ static Types provideTypes(ProcessingEnvironment processingEnvironment) {

@Provides
static List<ClearableCache> caches(
InjectBindingFactory injectBindingFactory,
KeyFactory keyFactory,
InjectBindingCache injectBindingCache,
KeyCache keyCache,
SafeElements safeElements) {
return List.of(injectBindingFactory, keyFactory, safeElements);
return List.of(injectBindingCache, keyCache, safeElements);
}

ComponentStep componentStep();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,15 @@
import io.jbock.javapoet.ClassName;
import io.jbock.simple.Component;
import io.jbock.simple.Inject;
import io.jbock.simple.Provides;
import io.jbock.simple.processor.util.ValidationFailure;
import io.jbock.simple.processor.util.Visitors;

import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;

import static io.jbock.simple.processor.util.Suppliers.memoize;
import static javax.lang.model.util.ElementFilter.methodsIn;

public final class ComponentElement {

private final TypeElement element;
private final KeyFactory keyFactory;

private final Supplier<ClassName> generatedClass = memoize(() -> {
ClassName className = ClassName.get(element());
Expand All @@ -34,141 +20,20 @@ public final class ComponentElement {
.peerClass(String.join("_", className.simpleNames()) + "_Impl");
});

private final Supplier<Optional<FactoryElement>> factoryElement = memoize(() -> {
for (Element el : element().getEnclosedElements()) {
boolean hasFactoryAnnotation = el.getAnnotation(Component.Factory.class) != null;
if (!hasFactoryAnnotation) {
continue;
}
TypeElement tel = Visitors.TYPE_ELEMENT_VISITOR.visit(el);
if (tel == null) {
continue;
}
return Optional.of(new FactoryElement(tel, generatedClass(), keyFactory()));
}
return Optional.empty();
});


private final Supplier<Optional<BuilderElement>> builderElement = memoize(() -> {
for (Element el : element().getEnclosedElements()) {
boolean hasBuilderAnnotation = el.getAnnotation(Component.Builder.class) != null;
if (!hasBuilderAnnotation) {
continue;
}
TypeElement tel = Visitors.TYPE_ELEMENT_VISITOR.visit(el);
if (tel == null) {
continue;
}
return Optional.of(new BuilderElement(tel, generatedClass(), keyFactory()));
}
return Optional.empty();
});

private final Supplier<Map<Key, InjectBinding>> providesBindings = memoize(() -> {
List<ExecutableElement> methods = methodsIn(element().getEnclosedElements());
Map<Key, InjectBinding> result = new LinkedHashMap<>();
for (ExecutableElement method : methods) {
if (method.getAnnotation(Provides.class) == null) {
continue; // ignore
}
Key key = keyFactory().getKey(method);
InjectBinding b = keyFactory().createBinding(method);
result.put(key, b);
}
return result;
});

private final Supplier<Map<Key, DependencyRequest>> requests = memoize(() -> {
List<ExecutableElement> methods = methodsIn(element().getEnclosedElements());
Map<Key, DependencyRequest> result = new LinkedHashMap<>();
for (ExecutableElement method : methods) {
if (method.getModifiers().contains(Modifier.STATIC)) {
continue; // ignore
}
if (method.getAnnotation(Provides.class) != null) {
continue; // ignore
}
if (!method.getParameters().isEmpty()) {
throw new ValidationFailure("Request method may not have any parameters", method);
}
if (method.getModifiers().contains(Modifier.DEFAULT)) {
throw new ValidationFailure("Default modifier is not allowed here", method);
}
if (method.getReturnType().getKind() == TypeKind.VOID) {
throw new ValidationFailure("Request method may not return void", method);
}
Key key = keyFactory().getKey(method);
result.put(key, new DependencyRequest(key, method, method));
}
return result;
});

private final Supplier<Map<Key, ParameterBinding>> parameterBindings = memoize(() -> {
List<ParameterBinding> pBindings = factoryElement()
.map(FactoryElement::parameterBindings)
.or(() -> builderElement().map(BuilderElement::parameterBindings))
.orElse(List.of());
Map<Key, ParameterBinding> result = new LinkedHashMap<>();
for (ParameterBinding b : pBindings) {
ParameterBinding previousBinding = result.put(b.key(), b);
if (previousBinding != null) {
Element p = previousBinding.element();
throw new ValidationFailure("The binding is in conflict with another parameter: " +
p.asType() + ' ' + p.getSimpleName(), b.element());
}
}
return result;
});

@Inject
public ComponentElement(
TypeElement element,
KeyFactory keyFactory) {
TypeElement element) {
this.element = element;
this.keyFactory = keyFactory;
}

public TypeElement element() {
return element;
}

public Optional<FactoryElement> factoryElement() {
return factoryElement.get();
}

public Optional<BuilderElement> builderElement() {
return builderElement.get();
}

public boolean isComponentRequest(Binding binding) {
return requests.get().containsKey(binding.key());
}

public Collection<DependencyRequest> requests() {
return requests.get().values();
}

public Map<Key, InjectBinding> providesBindings() {
return providesBindings.get();
}

public ClassName generatedClass() {
return generatedClass.get();
}

private KeyFactory keyFactory() {
return keyFactory;
}

public Optional<Binding> parameterBinding(Key key) {
return Optional.ofNullable(parameterBindings.get().get(key));
}

public Collection<ParameterBinding> parameterBindings() {
return parameterBindings.get().values();
}

public boolean publicMockBuilder() {
Component annotation = element.getAnnotation(Component.class);
if (annotation == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.jbock.simple.processor.binding;

import io.jbock.simple.Inject;
import io.jbock.simple.processor.util.ClearableCache;

import javax.lang.model.element.TypeElement;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class InjectBindingCache implements ClearableCache {

private final Map<TypeElement, Map<Key, InjectBinding>> injectBindingCache = new HashMap<>();

@Inject
public InjectBindingCache() {
}

Map<Key, InjectBinding> computeIfAbsent(
TypeElement typeElement,
Function<TypeElement, Map<Key, InjectBinding>> f) {
return injectBindingCache.computeIfAbsent(typeElement, f);
}


@Override
public void clearCache() {
injectBindingCache.clear();
}
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
package io.jbock.simple.processor.binding;

import io.jbock.simple.Inject;
import io.jbock.simple.processor.util.ClearableCache;
import io.jbock.simple.processor.util.TypeTool;

import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static io.jbock.simple.processor.util.Visitors.TYPE_ELEMENT_VISITOR;

public final class InjectBindingFactory implements ClearableCache {

private final Map<TypeElement, Map<Key, InjectBinding>> injectBindingCache = new HashMap<>();
public final class InjectBindingFactory {

private final InjectBindingCache injectBindingCache;
private final TypeTool tool;
private final KeyFactory keyFactory;
private final InjectBindingScanner injectBindingScanner;

@Inject
public InjectBindingFactory(
TypeTool tool,
InjectBindingCache injectBindingCache,
KeyFactory keyFactory,
InjectBindingScanner injectBindingScanner) {
this.tool = tool;
this.injectBindingCache = injectBindingCache;
this.keyFactory = keyFactory;
this.injectBindingScanner = injectBindingScanner;
}
Expand All @@ -54,9 +53,4 @@ public Optional<Binding> binding(Key key) {
return Optional.ofNullable(m.get(key));
});
}

@Override
public void clearCache() {
injectBindingCache.clear();
}
}
Loading
Loading