You can trap signals, either by using internal API:
import sun.misc.Signal;
import sun.misc.SignalHandler;
public class NoStop {
public static void main(final String[] args) {
SignalHandler ignoreHandler = sig -> System.out.println("Ignoring signal " + sig);
Signal.handle(new Signal("INT"), ignoreHandler);
or with jnr-posix
:
import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;
import jnr.posix.SignalHandler;
public class NoStop {
public static void main(final String[] args) {
SignalHandler ignoreHandler = sig -> System.out.println("Ignoring signal " + sig);
POSIX posix = POSIXFactory.getPOSIX();
posix.signal(Signal.SIGINT, ignoreHandler);
With that, typing ^C
has no effect, and typing ^D
results in null
String read from System.in
, which you can handle in your application logic.
The first one is using internal API, and the compiler complains:
Signal is internal proprietary API and may be removed in a future release
But it can come in handy to work around your issue, and sometimes it's OK. In your case it's trivial to compartmentalize to a minuscule scope, and find an alternative if the API actually disappears. If I had to, I'd pick the internal API in this particular case (bringing jnr-posix
for that is overkill, but deserved a mention).
Tested on Mac & Linux, Java 8 & 9.
If you don't like the compiler warnings, invoke the methods using reflection(*).
Alternatively, you could launch your java
program with a command line wrapper that would intercept signals for you (which you'd have to develop in C, this answer shows how). (I checked if rlwrap
does that, I'm a bit disappointed it does not).
(*) (not saying it's better, just thought it could be a useful example)
private static void trapSignalsUsingReflection() {
try {
Class signalClass = Class.forName("sun.misc.Signal");
Class signalHandlerInterface = Class.forName("sun.misc.SignalHandler");
Object signal = signalClass.getDeclaredConstructor(String.class).newInstance("INT");
Object handler = Proxy.newProxyInstance(
NoStop.class.getClassLoader(),
new Class[]{signalHandlerInterface},
(proxy, method, args) -> {
System.out.println("Ignoring signal: " + args[0]);
return null;
});
Method handleMethod = signalClass.getMethod("handle", signalClass, signalHandlerInterface);
handleMethod.invoke(null, signal, handler);
}
catch(ClassNotFoundException|IllegalAccessException|InstantiationException|NoSuchMethodException|InvocationTargetException e) {
throw new RuntimeException("Oops, internal API has changed, quick," +
"go to https://stackoverflow.com/a/34188676/8022004 & tell dimo414 he was wrong", e);
}
}