TNG / ArchUnit

A Java architecture test library, to specify and assert architecture rules in plain Java
http://archunit.org
Apache License 2.0
3.17k stars 287 forks source link

How To : validate return type is not `void` #1265

Closed omuomugin closed 5 months ago

omuomugin commented 5 months ago

I'm trying to check that method which is annotated with ApiResponse should return with something.

@ApiResponse
public void endpoint() {

}

// actual code is Kotlin like below
@ApiResponse
fun endpoint(): Unit { // Unit is wrapper of Void in Kotlin 

}

neither of check is not working. Is there any way to check return type is void ? (code below is Kotlin, feel free to ask me to write in Java)

val allClassesInController = ClassFileImporter()
    .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
    .importPackages("some.target.package")

val rule: ArchRule = ArchRuleDefinition.methods()
    .that().areAnnotatedWith(ApiResponse::class.java)
    .should().notHaveRawReturnType(Unit::class.java) // I'm using Kotlin but guessing `Unit` is just a wrapper for `Void` so it won't be a problem
    .orShould().notHaveRawReturnType(Void.TYPE)
    .orShould().notHaveRawReturnType(Void::class.java)
    .orShould().notHaveRawReturnType("void")
    .orShould().notHaveRawReturnType(Void::class.simpleName)
    .orShould().notHaveRawReturnType(Void::class.qualifiedName)
    .orShould().notHaveRawReturnType(Void::class.javaObjectType)
    .because("methods should not return void")

rule.check(allClassesInController)
hankem commented 5 months ago

This is mostly a logical confusion (that happened to me several times, too):

For different and mutually exclusive properties X and Y, a rule

M should (not have X) or should (not have Y).

is always satisfied:

Your rule should work as expected when you use

M should (not have X) and should (not have Y).


To answer the actual question: For methods with void return type, method.getRawReturnType() returns a JavaClass equivalent to void.class, whose name is "void".

FYI: ArchUnit also has another way to describe anti-patterns:

no M should (have X) or should (have Y).

So the most concise definition of your rule is probably:

noMethods().that().areAnnotatedWith(ApiResponse.class).should().haveRawReturnType("void")
omuomugin commented 5 months ago

is always satisfied:

This is so right !! Thanks for your help

noMethods().that().areAnnotatedWith(ApiResponse.class).should().haveRawReturnType("void")

this worked as expected!