Skip to content
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 @@ -41,7 +41,7 @@ public String message() {
if (tags.isEmpty()) {
return """
Missing component: %s
Component can be provided by standard Kora module you may forgot to plug it:
Component is provided by standard Kora module you may forgot to plug it:
Gradle dependency: implementation("%s")
Module interface: %s
""".formatted(type, artifact, module);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import ru.tinkoff.kora.kora.app.annotation.processor.component.ResolvedComponent;
import ru.tinkoff.kora.kora.app.annotation.processor.declaration.ComponentDeclaration;
import ru.tinkoff.kora.kora.app.annotation.processor.exception.CircularDependencyException;
import ru.tinkoff.kora.kora.app.annotation.processor.exception.DuplicateDependencyException;
import ru.tinkoff.kora.kora.app.annotation.processor.exception.NewRoundException;
import ru.tinkoff.kora.kora.app.annotation.processor.exception.UnresolvedDependencyException;
import ru.tinkoff.kora.kora.app.annotation.processor.extension.ExtensionResult;
Expand Down Expand Up @@ -145,13 +146,7 @@ public static ProcessingState processProcessing(ProcessingContext ctx, RoundEnvi
}
}
if (results.size() > 1) {
var deps = templates.stream().map(Objects::toString).collect(Collectors.joining("\n")).indent(2);
if (dependencyClaim.tags().isEmpty()) {
throw new ProcessingErrorException("More than one component matches dependency claim " + dependencyClaim.type() + ":\n" + deps, declaration.source());
} else {
var tagMsg = dependencyClaim.tags().stream().collect(Collectors.joining(", ", "@Tag(", ")"));
throw new ProcessingErrorException("More than one component matches dependency claim " + dependencyClaim.type() + " with tag " + tagMsg + " :\n" + deps, declaration.source());
}
throw new DuplicateDependencyException(dependencyClaim, declaration, templates);
}
throw exception;
}
Expand Down Expand Up @@ -477,17 +472,17 @@ private static boolean checkCycle(ProcessingContext ctx, ProcessingState.Process
var dependencyClaimType = dependencyClaim.type();
var dependencyClaimTypeElement = ctx.types.asElement(dependencyClaimType);
if (!(ctx.types.isAssignable(declaration.type(), dependencyClaimType) || ctx.serviceTypeHelper.isAssignableToUnwrapped(declaration.type(), dependencyClaimType) || ctx.serviceTypeHelper.isInterceptor(declaration.type()))) {
throw new CircularDependencyException(List.of(prevComponent.declaration().toString(), declaration.toString()), declaration);
throw new CircularDependencyException(List.of(prevComponent.declaration(), declaration), declaration);
}
for (var inStackFrame : processing.resolutionStack()) {
if (!(inStackFrame instanceof ProcessingState.ResolutionFrame.Component componentFrame) || componentFrame.declaration() != declaration) {
continue;
}
if (dependencyClaim.type().getKind() != TypeKind.DECLARED) {
throw new CircularDependencyException(List.of(prevComponent.declaration().toString(), declaration.toString()), componentFrame.declaration());
throw new CircularDependencyException(List.of(prevComponent.declaration(), declaration), componentFrame.declaration());
}
if (dependencyClaimTypeElement.getKind() != ElementKind.INTERFACE && (dependencyClaimTypeElement.getKind() != ElementKind.CLASS || dependencyClaimTypeElement.getModifiers().contains(Modifier.FINAL))) {
throw new CircularDependencyException(List.of(prevComponent.declaration().toString(), declaration.toString()), componentFrame.declaration());
throw new CircularDependencyException(List.of(prevComponent.declaration(), declaration), componentFrame.declaration());
}
var proxyDependencyClaim = new DependencyClaim(
dependencyClaimType, Set.of(CommonClassNames.promisedProxy.canonicalName()), dependencyClaim.claimType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
import ru.tinkoff.kora.kora.app.annotation.processor.component.DependencyClaim;
import ru.tinkoff.kora.kora.app.annotation.processor.component.ResolvedComponent;
import ru.tinkoff.kora.kora.app.annotation.processor.declaration.ComponentDeclaration;
import ru.tinkoff.kora.kora.app.annotation.processor.exception.DuplicateDependencyException;

import javax.lang.model.element.*;
import javax.lang.model.type.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static ru.tinkoff.kora.kora.app.annotation.processor.component.DependencyClaim.DependencyClaimType.*;

Expand All @@ -37,12 +36,7 @@ public static ComponentDependency.SingleDependency findDependency(ProcessingCont
return null;
}

var deps = dependencies.stream()
.map(ComponentDependency.SingleDependency::component)
.map(Objects::toString)
.collect(Collectors.joining("\n")).indent(2);

throw new ProcessingErrorException("More than one component matches dependency claim " + dependencyClaim.type() + ":\n" + deps, forDeclaration.source());
throw new DuplicateDependencyException(dependencies, dependencyClaim, forDeclaration);
}

public static List<ComponentDependency.SingleDependency> findDependencies(ProcessingContext ctx, List<ResolvedComponent> resolvedComponents, DependencyClaim dependencyClaim) {
Expand Down Expand Up @@ -152,15 +146,14 @@ public static ComponentDeclaration findDependencyDeclarationFromTemplate(Process
if (declarations.size() == 1) {
return declarations.get(0);
}
var exactMatch = declarations.stream().filter(d -> ctx.types.isSameType(
d.type(),
dependencyClaim.type()
)).toList();
var exactMatch = declarations.stream()
.filter(d -> ctx.types.isSameType(d.type(), dependencyClaim.type()))
.toList();
if (exactMatch.size() == 1) {
return exactMatch.get(0);
}
var deps = declarations.stream().map(Objects::toString).collect(Collectors.joining("\n")).indent(2);
throw new ProcessingErrorException("More than one component matches dependency claim " + dependencyClaim.type() + ":\n" + deps, forDeclaration.source());

throw new DuplicateDependencyException(dependencyClaim, forDeclaration, declarations);
}

public static List<ComponentDeclaration> findDependencyDeclarationsFromTemplate(ProcessingContext ctx, ComponentDeclaration forDeclaration, List<ComponentDeclaration> sourceDeclarations, DependencyClaim dependencyClaim) {
Expand Down Expand Up @@ -326,8 +319,7 @@ public static ComponentDeclaration findDependencyDeclaration(ProcessingContext c
return nonDefaultComponents.get(0);
}

var deps = declarations.stream().map(Objects::toString).collect(Collectors.joining("\n")).indent(2);
throw new ProcessingErrorException("More than one component matches dependency claim " + dependencyClaim.type() + ":\n" + deps, forDeclaration.source());
throw new DuplicateDependencyException(dependencyClaim, forDeclaration, declarations);
}

public static List<ComponentDeclaration> findDependencyDeclarations(ProcessingContext ctx, List<ComponentDeclaration> sourceDeclarations, DependencyClaim dependencyClaim) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
package ru.tinkoff.kora.kora.app.annotation.processor.exception;

import com.squareup.javapoet.TypeName;
import ru.tinkoff.kora.annotation.processor.common.CommonClassNames;
import ru.tinkoff.kora.annotation.processor.common.ProcessingError;
import ru.tinkoff.kora.annotation.processor.common.ProcessingErrorException;
import ru.tinkoff.kora.kora.app.annotation.processor.declaration.ComponentDeclaration;

import java.util.List;
import java.util.stream.Collectors;

public class CircularDependencyException extends ProcessingErrorException {
public CircularDependencyException(List<String> cycle, ComponentDeclaration source) {
super(String.format("There's a cycle in graph: \n\t%s", String.join("\n\t", cycle)), source.source());

public CircularDependencyException(List<ComponentDeclaration> cycle, ComponentDeclaration declaration) {
super(getError(cycle, declaration));
}

private static ProcessingError getError(List<ComponentDeclaration> cycle,
ComponentDeclaration declaration) {
var deps = cycle.stream()
.map(c -> String.format("- %s", c.declarationString()))
.collect(Collectors.joining("\n", "Cycle dependency candidates:\n", "")).indent(2);

if (declaration.tags().isEmpty()) {
return new ProcessingError("Encountered circular dependency in graph for source type: " + TypeName.get(declaration.type()) + " (no tags)\n"
+ deps
+ "\nPlease check that you are not using cycle dependency in %s, this is forbidden.".formatted(CommonClassNames.lifecycle),
declaration.source());
} else {
var tagMsg = declaration.tags().stream()
.collect(Collectors.joining(", ", "@Tag(", ")"));
return new ProcessingError("Encountered circular dependency in graph for source type: " + TypeName.get(declaration.type()) + " with " + tagMsg + "\n"
+ deps
+ "\nPlease check that you are not using cycle dependency in %s, this is forbidden.".formatted(CommonClassNames.lifecycle),
declaration.source());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ru.tinkoff.kora.kora.app.annotation.processor.exception;

import com.squareup.javapoet.TypeName;
import ru.tinkoff.kora.annotation.processor.common.ProcessingError;
import ru.tinkoff.kora.annotation.processor.common.ProcessingErrorException;
import ru.tinkoff.kora.kora.app.annotation.processor.component.ComponentDependency;
import ru.tinkoff.kora.kora.app.annotation.processor.component.DependencyClaim;
import ru.tinkoff.kora.kora.app.annotation.processor.declaration.ComponentDeclaration;

import java.util.List;
import java.util.stream.Collectors;

public class DuplicateDependencyException extends ProcessingErrorException {

public DuplicateDependencyException(DependencyClaim claim,
ComponentDeclaration declaration,
List<ComponentDeclaration> foundDeclarations) {
super(List.of(getErrorForDeclarations(claim, declaration, foundDeclarations)));
}

public DuplicateDependencyException(List<ComponentDependency.SingleDependency> foundDeclarations,
DependencyClaim claim,
ComponentDeclaration declaration) {
super(List.of(getErrorForDependencies(claim, declaration, foundDeclarations)));
}

private static ProcessingError getErrorForDeclarations(DependencyClaim claim,
ComponentDeclaration declaration,
List<ComponentDeclaration> foundDeclarations) {
var deps = foundDeclarations.stream()
.map(c -> String.format("- %s", c.declarationString()))
.collect(Collectors.joining("\n", "Candidates for injection:\n", "")).indent(2);

return getError(claim, declaration, deps);
}

private static ProcessingError getErrorForDependencies(DependencyClaim claim,
ComponentDeclaration declaration,
List<ComponentDependency.SingleDependency> foundDeclarations) {
var deps = foundDeclarations.stream()
.map(ComponentDependency.SingleDependency::component)
.map(c -> String.format("- %s", c.declaration().declarationString()))
.collect(Collectors.joining("\n", "Candidates for injection:\n", "")).indent(2);

return getError(claim, declaration, deps);
}

private static ProcessingError getError(DependencyClaim claim,
ComponentDeclaration declaration,
String deps) {
if (claim.tags().isEmpty()) {
return new ProcessingError("More than one component matches dependency type: " + TypeName.get(claim.type()) + " (no tags)\n"
+ deps
+ "\nPlease check that injection dependency is declared correctly or that @DefaultComponent annotation is not missing if was intended.",
declaration.source());
} else {
var tagMsg = claim.tags().stream()
.collect(Collectors.joining(", ", "@Tag(", ")"));
return new ProcessingError("More than one component matches dependency type: " + TypeName.get(claim.type()) + " with " + tagMsg + "\n"
+ deps
+ "\nPlease check that injection dependency is declared correctly or that @DefaultComponent annotation is not missing if was intended.",
declaration.source());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ void unresolvedDependency() {
void testCircularDependency() {
assertThatThrownBy(() -> testClass(AppWithCircularDependency.class))
.isInstanceOfSatisfying(CompilationErrorException.class, e -> SoftAssertions.assertSoftly(s -> {
s.assertThat(e.getMessage()).startsWith("There's a cycle in graph: ");
s.assertThat(e.getMessage()).startsWith("Encountered circular dependency in graph for source type:");
s.assertThat(e.diagnostics.get(0).getSource().getName()).isEqualTo("src/test/java/ru/tinkoff/kora/kora/app/annotation/processor/app/AppWithCircularDependency.java");
}));
}
Expand All @@ -194,7 +194,7 @@ void appWithFactory() throws Throwable {
// testClass(AppWithFactories5.class).init();; TODO больше не нужно
assertThatThrownBy(() -> testClass(AppWithFactories6.class))
.isInstanceOf(CompilationErrorException.class)
.hasMessageStartingWith("There's a cycle in graph:");
.hasMessageStartingWith("Encountered circular dependency in graph for source type");
testClass(AppWithFactories7.class).init();
testClass(AppWithFactories8.class).init();
testClass(AppWithFactories9.class).init();
Expand Down Expand Up @@ -261,11 +261,7 @@ void appWithComponentDescriptorCollisionAndDirect() {
.isInstanceOfSatisfying(CompilationErrorException.class, e -> SoftAssertions.assertSoftly(s -> {
var error = e.getDiagnostics().stream().filter(d -> d.getKind() == Diagnostic.Kind.ERROR).findFirst().get();
s.assertThat(error.getMessage(Locale.US))
.startsWith("More than one component matches dependency claim ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithComponentCollisionAndDirect.Class1:");

s.assertThat(error.getMessage(Locale.US)).contains("FromModuleComponent[type=ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithComponentCollisionAndDirect.Class1, module=MixedInModule[element=ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithComponentCollisionAndDirect], method=c1()");
s.assertThat(error.getMessage(Locale.US)).contains("FromModuleComponent[type=ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithComponentCollisionAndDirect.Class1, module=MixedInModule[element=ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithComponentCollisionAndDirect], method=c2()");
s.assertThat(error.getMessage(Locale.US)).contains("FromModuleComponent[type=ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithComponentCollisionAndDirect.Class1, module=MixedInModule[element=ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithComponentCollisionAndDirect], method=c3()");
.startsWith("More than one component matches dependency type: ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithComponentCollisionAndDirect.Class1");
}));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class DependencyModuleHintProvider(private val resolver: Resolver) {
if (tags.isEmpty()) {
return """
Missing component: ${type.toTypeName()}
Component can be provided by standard Kora module you may forgot to plug it:
Component is provided by standard Kora module you may forgot to plug it:
Gradle dependency: implementation("$artifact")
Module interface: $module
""".trimIndent()
Expand All @@ -55,7 +55,7 @@ class DependencyModuleHintProvider(private val resolver: Resolver) {

return """
Missing component: ${type.toTypeName()} with $tagForMsg
Component can be provided by standard Kora module you may forgot to plug it:
Component is provided by standard Kora module you may forgot to plug it:
Gradle dependency: implementation("$artifact")
Module interface: $module
""".trimIndent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ru.tinkoff.kora.kora.app.ksp.component.DependencyClaim.DependencyClaimTyp
import ru.tinkoff.kora.kora.app.ksp.component.ResolvedComponent
import ru.tinkoff.kora.kora.app.ksp.declaration.ComponentDeclaration
import ru.tinkoff.kora.kora.app.ksp.exception.CircularDependencyException
import ru.tinkoff.kora.kora.app.ksp.exception.DuplicateDependencyException
import ru.tinkoff.kora.kora.app.ksp.exception.NewRoundException
import ru.tinkoff.kora.kora.app.ksp.exception.UnresolvedDependencyException
import ru.tinkoff.kora.kora.app.ksp.extension.ExtensionResult
Expand Down Expand Up @@ -142,15 +143,7 @@ object GraphBuilder {
}
}
if (results.size > 1) {
val deps = templates.stream().map { Objects.toString(it) }
.collect(Collectors.joining("\n"))
.prependIndent(" ")
throw ProcessingErrorException(
"""
More than one component matches dependency claim ${dependencyClaim.type}:
$deps
""".trimIndent(), declaration.source
)
throw DuplicateDependencyException(dependencyClaim, declaration, templates)
}
throw exception!!
}
Expand Down Expand Up @@ -538,7 +531,7 @@ object GraphBuilder {
if (frame !is ProcessingState.ResolutionFrame.Component || frame.declaration !== declaration) {
continue
}
val circularDependencyException = CircularDependencyException(listOf(prevFrame.declaration.toString(), declaration.toString()), frame.declaration)
val circularDependencyException = CircularDependencyException(listOf(prevFrame.declaration, declaration), frame.declaration)
if (claimTypeDeclaration !is KSClassDeclaration) throw circularDependencyException
if (claimTypeDeclaration.classKind != ClassKind.INTERFACE && !(claimTypeDeclaration.classKind == ClassKind.CLASS && claimTypeDeclaration.isOpen())) throw circularDependencyException
val proxyDependencyClaim = DependencyClaim(
Expand Down
Loading