How to hide warning “Illegal reflective access” in java 9 without JVM argument?

前端 未结 9 1296
Happy的楠姐
Happy的楠姐 2020-12-02 09:28

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         


        
9条回答
  •  鱼传尺愫
    2020-12-02 10:23

    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:

    1. Lock System.err so that no other thread can write to it.
    2. Spawn 2 threads that call setAccessible on the out field. One of them will hang when trying to show the warning, but the other will complete.
    3. Set the 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.
    4. Wait for the second thread to end and restore the 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.

提交回复
热议问题