Open dagmararaczak opened 3 months ago
I don't think what you want is completely possible, cause ArchUnit doesn't track any syntax tree. I.e. if one call is nested into another call in a lambda or something like that isn't really part of the available information. That being said, what you can test is that the origin of each call of a service has to be a lambda and you could also test that your loginfo
is called in the same places. But that's of course just a heuristic. But maybe it's good enough (potentially with some fuzzy matching like the line number doesn't need to be an exact match or something like that 🤷). In any case, it's not the prettiest thing 😉
classes().that().haveSimpleNameEndingWith("Service")
.should(new ArchCondition<JavaClass>("only be called through log infrastructure") {
@Override
public void check(JavaClass service, ConditionEvents events) {
Set<JavaMethodCall> callsOfService = service.getMethodCallsToSelf();
Set<JavaMethodCall> logInfoCalls = callsOfService.stream()
.map(JavaMethodCall::getOrigin)
.flatMap(clazz -> clazz.getMethodCallsFromSelf().stream())
.filter(callFromSomeOrigin ->
callFromSomeOrigin.getTargetOwner().isEquivalentTo(Loginfo.class) &&
callFromSomeOrigin.getTarget().getName().equals("call")
)
.collect(toSet());
Predicate<JavaMethodCall> existsLogInfoCallWithSameLineNumberAs = (JavaMethodCall call) ->
logInfoCalls.stream().anyMatch(logInfoCall ->
logInfoCall.getOrigin().equals(call.getOrigin()) &&
logInfoCall.getLineNumber() == call.getLineNumber()
);
callsOfService.stream()
.filter(call -> !call.isDeclaredInLambda() || !existsLogInfoCallWithSameLineNumberAs.test(call))
.forEach(call -> events.add(SimpleConditionEvent.violated(call, call.getDescription())));
}
})
I assumed something like this:
class MyService {
void action() {
}
}
class MyOther {
Logger logger;
MyService myService;
void callServiceOkay() {
logger.loginfo("okay").call(() -> myService.action());
}
void callServiceWrong() {
myService.action();
}
}
class Logger {
Loginfo loginfo(String info) {
return new Loginfo();
}
}
class Loginfo {
void call(Runnable runnable) {
runnable.run();
}
}
You'd probably have to adjust it to your use case...
Hi,
Is it possible to do it in any way with ArchUnits ?
I have in one module classes whose names end with "Service" I would like to check if every public method from this is wrapped in different classes.
into something like this logger.loginfo("name of method").call(() → my service method) in some other method? Also, Logger class is in a different module.
So I would like to have something like check if my service method is called in the call method by loginfo.