最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - How does one write an ArchUnit specification that a constructor or method should never be called? - Stack Overflow

programmeradmin2浏览0评论

Certain frameworks require the empty constructor of a class to be present, e.g. a JakartaEE stateless service, but they do not have the appropriate dependencies injected. I would like to annotate these constructors with something like a DoNotUse annotation (with a reason), and then use ArchUnit to check if no one is actually using it.

Something like this:

        ArchRuleDefinition.noConstructors()
                .that()
                .areAnnotatedWith(DoNotUse.class)
                .should()
                .beCalled();

But beCalled or beUsed AFAIK does not exist. I solved it now by adding a never matching condition:

        ArchRuleDefinition.constructors()
                .that()
                .areAnnotatedWith(DoNotUse.class)
                .should()
                .onlyBeCalled()
                .byClassesThat()
                .haveSimpleName("ThisOnPurposeDoesNotMatchAnything");

How do I write a beCalled or the inverse neverBeCalled?

Certain frameworks require the empty constructor of a class to be present, e.g. a JakartaEE stateless service, but they do not have the appropriate dependencies injected. I would like to annotate these constructors with something like a DoNotUse annotation (with a reason), and then use ArchUnit to check if no one is actually using it.

Something like this:

        ArchRuleDefinition.noConstructors()
                .that()
                .areAnnotatedWith(DoNotUse.class)
                .should()
                .beCalled();

But beCalled or beUsed AFAIK does not exist. I solved it now by adding a never matching condition:

        ArchRuleDefinition.constructors()
                .that()
                .areAnnotatedWith(DoNotUse.class)
                .should()
                .onlyBeCalled()
                .byClassesThat()
                .haveSimpleName("ThisOnPurposeDoesNotMatchAnything");

How do I write a beCalled or the inverse neverBeCalled?

Share Improve this question asked Mar 13 at 12:29 tbeernottbeernot 2,6405 gold badges26 silver badges32 bronze badges 6
  • why create a method/constructor that should never be called? – Stultuske Commented Mar 13 at 12:29
  • you can usually declare those empty constructors to be private, the frameworks will stick pick them up – Rick Commented Mar 13 at 12:40
  • Some frameworks do require public default constructors. Even if it could be avoided in this case, it's a valid question. – kapex Commented Mar 13 at 12:42
  • 1 I already explained that: frameworks like JakartaEE require those constructors. When using WildFly you can suffice with a protected constructor (because the generated proxies will extend the class), not private. But then IntelliJ will place an error marker on those classes and your code base is all red. – tbeernot Commented Mar 13 at 12:46
  • I don't have an answer but sometimes it helps to reverse the order, even though it look less intuitive. Instead "this should not be called" reverse it to "nothing should call this" e.g. create a rule: no classes should call constructors annotated with DoNotUse. – kapex Commented Mar 13 at 13:02
 |  Show 1 more comment

1 Answer 1

Reset to default 0

You can use a custom condition using convenient factory methods for ArchConditions and DescribedPredicates:

import static com.tngtech.archunit.base.DescribedPredicate.describe;
import static com.tngtech.archunit.lang.conditions.ArchConditions.be;

// ...

    ArchRule rule =  ArchRuleDefinition.noConstructors()
            .that().areAnnotatedWith(DoNotUse.class)
            .should(be(describe("called", ctor -> !ctor.getCallsOfSelf().isEmpty())));

If you want more descriptive error messages indicating where the unwanted call happens (cf. comment), you can use a custom ArchCondition like this:

import static com.tngtech.archunit.lang.SimpleConditionEvent.satisfied;

// ...

    ArchRule rule = ArchRuleDefinition.noConstructors()
            .that().areAnnotatedWith(DoNotUse.class)
            .should(new ArchCondition<JavaConstructor>("be called") {
                @Override
                public void check(JavaConstructor constructor, ConditionEvents events) {
                    constructor.getCallsOfSelf().forEach(call ->
                        events.add(satisfied(call, call.getDescription()))
                    );
                }
            });

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论