Checking if assertions are enabled
Asked Answered
C

4

5

You can enable/disable assert on the ClassLoader.

But how can you determine if they are already enabled?

(I want to take some code paths that perform expensive checks only if the JVM is invoked with assertions enabled.)

Conservancy answered 28/5, 2013 at 9:7 Comment(0)
K
5
boolean assertEnabled = false;

try {
   assert false;
} catch (AssertionError e) {
   assertEnabled = true;
}
Kidder answered 28/5, 2013 at 9:13 Comment(0)
R
15
public static boolean areAssertsEnabled() {
  boolean assertsEnabled = false;
  assert assertsEnabled = true; // Intentional side effect!!!
  return assertsEnabled;
}
Ramiform answered 28/5, 2013 at 9:13 Comment(3)
Shouldn't there be a catch in there in case asserts are enabled?Conservancy
No, because 'assertsEnabled = true;' evaulates to true, so if assertions ARE enabled, then the assertion succeeds. This is based on an example from Oracle's documentation at: docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.htmlRamiform
If I could accept multiple answers I would accept this too! My static analyser complained about the side-effect in an assert so I went with the try/catch to keep it quiet and to make the code less 'aha' for those who follow.Conservancy
K
5
boolean assertEnabled = false;

try {
   assert false;
} catch (AssertionError e) {
   assertEnabled = true;
}
Kidder answered 28/5, 2013 at 9:13 Comment(0)
C
2
ManagementFactory.getRuntimeMXBean().getInputArguments().contains("-ea");
Compote answered 28/5, 2013 at 9:12 Comment(1)
Will this work for the synonym -enableassertions?Autry
A
0

The sibling answer is correct. But I question the utility and the generality of this approach. (Jump to “Alternative approach” for another way to deal with this problem.)

The simplest way for assertions to be enabled is if they are enabled for all classes.

-ea

or:

-enableassertions

In that case you can store that fact in one variable and use it throughout your program:

public class Main {

    public static boolean assertsEnabled = false;
    static {
        assert assertsEnabled = true;
    }
[…]
}

But say I have classes

Main, A, B, C

And:

-ea:Main -ea:A

I.e. assertions are only enabled for Main and A. The intent must thus be that assertions inside B and C shouldn’t be run.

Given this:

public class Main {

    public static boolean assertsEnabled = false;
    static {
        assert assertsEnabled = true;
    }
    public static void main(String[] args) {
        System.out.println("Hello from main()");
        m();
        assert A.print();
        A.print2();
        assert B.print();
        B.print2();
        assert C.print();
        C.print2();
    }

    private static void m() {
        if (assertsEnabled) {
            System.out.println("  main() again (using static variable)");
        }
    }
}

It is clear how the print() methods will be handled: they will be run since -ea:Main. If -da:Main() then they will not be run.

m() will print the string since we know that assertsEnabled.

The print2() functions look like this:

// C
    public static void print2() {
        if (Main.assertsEnabled) {
            System.out.println("  assert inside C (using variable from Main)");
        }
    }

Here, it is also clear what will happen: the program will print that string since -ea:Main and the way we initialized Main.assertsEnabled. But hold on: assertions are disabled for C (effectively -da:C). So is this really what we intended? Perhaps. Or perhaps we just used the static variable belonging to Main as it was convenient enough, and didn’t consider that this run in Main:


    public static boolean assertsEnabled = false;
    static {
        assert assertsEnabled = true;
    }

Will behave differently than the exact same code which would be copy-pasted into C.

So code that acts differently based on the assertion inclusion of other classes seems potentially confusing. Let’s instead just copy–paste this snippet into every class which uses assertions:

    private static boolean assertsEnabled = false;
    static {
        assert assertsEnabled = true;
    }

And use it like this:

if (assertsEnabled) {
  // Error checking
}

But I think there is a more straightforward approach.

Alternative approach

OP:

I want to take some code paths that perform expensive checks only if the JVM is invoked with assertions enabled.

  1. For any block of code X which is only supposed to be run if assertions are enabled
  2. Make a static method x() with return type boolean
  3. Just put return true to satisfy the type checker (could also be whatever you want to assert, but since you want to check if assertions are enabled and then run some code it seems that the checks are more involved than what one single boolean expression can conveniently achieve)
  4. Put X inside the method body
  5. Put assert in front of all invocations of x()
assert x();
[…]
private static boolean x() {
    // X
}

For example:

private static boolean x() {
    var setup = new Setup();
    assert ...;
    assert ...;
    [more setup and preparation]
    assert ...;
    return true;
}

Interleaving regular code and assertion code

The “time how long this runs” problem: sometimes you have cross-cutting concerns. In this case, you might want to run some assertion-only code, then the regular code, and then finally the other part of the assertion-only code (which uses the first part).

The Java article on assertions covers how to approach this problem:

Occasionally it is necessary to save some data prior to performing a computation in order to check a postcondition. You can do this with two assert statements and a simple inner class that saves the state of one or more variables so they can be checked (or rechecked) after the computation. […]

Here’s a more simplified and hand-wavy example:

    private static void doWork(Work work) {
        ConsistencyCheck cc = null;
        assert ((cc = new ConsistencyCheck(work)) != null);
        doWorkInner(work);
        assert cc.check(work);
    }

The only overhead here (if it isn’t removed by the JIT as dead code) when running with assertions disabled would be to initialize an object to null, which shouldn’t be expensive.

Autry answered 6/1, 2023 at 22:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.