I just tried to run my server with Java 9 and got next warning:
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective acce
I've come up with a way to disable that warning without using Unsafe nor accessing any undocumented APIs. It works by using Reflection to set the FilterOutputStream::out field of System.err to null.
Of course, attempting to use Reflection will actually throw the warning we're trying to supress, but we can exploit concurrency to work around that:
System.err so that no other thread can write to it.setAccessible on the out field. One of them will hang when trying to show the warning, but the other will complete.out field of System.err to null and release the lock on System.err. The second thread will now complete, but no warning will be displayed.out field of System.err.The following code demostrates this:
public void suppressWarning() throws Exception
{
Field f = FilterOutputStream.class.getDeclaredField("out");
Runnable r = () -> { f.setAccessible(true); synchronized(this) { this.notify(); }};
Object errorOutput;
synchronized (this)
{
synchronized (System.err) //lock System.err to delay the warning
{
new Thread(r).start(); //One of these 2 threads will
new Thread(r).start(); //hang, the other will succeed.
this.wait(); //Wait 1st thread to end.
errorOutput = f.get(System.err); //Field is now accessible, set
f.set(System.err, null); // it to null to suppress the warning
} //release System.err to allow 2nd thread to complete.
this.wait(); //Wait 2nd thread to end.
f.set(System.err, errorOutput); //Restore System.err
}
}
This code will work even if --illegal-access is set to "warn" or "debug", since these modes don't show the warning more than once for the same caller.
Also, instead of restoring the original state of System.err, you can also set its out field to a custom OutputStream, so you can filter future warnings.