34

I am almost certain this is impossible, but it's worth a try.

I am writing a command line interface for a certain tool. I am talking about a Java application that invokes another Java application. The tool calls System.exit after execution, which in turn terminates my own execution environment. I don't want that.

Is there any way to ignore System.exit calls?

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Tiago Veloso
  • 8,513
  • 17
  • 64
  • 85
  • 3
    Possible duplicate of [Java: How to test methods that call System.exit()?](http://stackoverflow.com/questions/309396/java-how-to-test-methods-that-call-system-exit). Even though the title of that question may be misleading, it's the same question: prevent external code from System.exiting. – R. Martinho Fernandes Apr 05 '11 at 09:32

5 Answers5

27

Yes, this is possible using a SecurityManager. Try the following

class MySecurityManager extends SecurityManager {
  @Override public void checkExit(int status) {
    throw new SecurityException();
  }

  @Override public void checkPermission(Permission perm) {
      // Allow other activities by default
  }
}

In your class use the following calls:

myMethod() {
    //Before running the external Command
    MySecurityManager secManager = new MySecurityManager();
    System.setSecurityManager(secManager);

    try {
       invokeExternal();
    } catch (SecurityException e) {
       //Do something if the external code used System.exit()
    }
}
MaxNoe
  • 14,470
  • 3
  • 41
  • 46
theomega
  • 31,591
  • 21
  • 89
  • 127
  • 3
    I suggest also overriding the `checkPermission` method of the SecurityManager to avoid security exceptions related to other privileged operations. – Emmanuel Bourg Jun 27 '16 at 09:55
  • @theomega I used your code, but i now get access denied for every file i want to read – Elad Benda Jun 14 '17 at 08:14
  • 1
    @EmmanuelBourg I used the code in the answer, but i now get "access denied" error for every file i want to read – Elad Benda Jun 14 '17 at 08:15
  • Probably generally correct solution is to get previous security manager, and if present, delegate all other methods onto it. – Ondřej Fischer Nov 02 '21 at 12:36
  • Libraries like system-lambda https://github.com/stefanbirkner/system-lambda take care of delegating the security manager calls to the previously installed security manager (if any). Also, setSecurityManager() is deprecated as of Java 17, so this approach won't work in the future. – Fr Jeremy Krieg Feb 18 '22 at 10:39
3

You can break your application in two parts. The first one gets started by the tool. Then you launch the second part of your application as a new process. Then the host application kills your first part, but the second part is still running.

This way the first part of your app is just the startup for the second part which is in turn your real application.

codymanix
  • 28,510
  • 21
  • 92
  • 151
3

Java 17 update:

A lot of the earlier answers to this question mention the use of a custom SecurityManager. This was correct at the time. But as of Java 17, System.setSecurityManager() is deprecated for removal, so this approach won't work in the future.

Fr Jeremy Krieg
  • 482
  • 5
  • 13
  • 4
    Yes, story here : https://openjdk.java.net/jeps/411 The new API related in this jeps, to solve the System::exit is not yet defined... https://bugs.openjdk.java.net/browse/JDK-8199704 Maybe somewhere else. – pleutre Mar 22 '22 at 09:06
2

Set the SecurityManager to ignore System.exit(), unless it comes from your code.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

Regarding to this (@Vonc answer) you should use Security Manager:

Try modifying the TestCase to run with a security manager that prevents calling System.exit, then catch the SecurityException.

Community
  • 1
  • 1
lukastymo
  • 26,145
  • 14
  • 53
  • 66