Bug 59933 - IllegalAccessError POILogger.log
Summary: IllegalAccessError POILogger.log
Status: RESOLVED FIXED
Alias: None
Product: POI
Classification: Unclassified
Component: POI Overall (show other bugs)
Version: unspecified
Hardware: Other other
: P2 blocker with 1 vote (vote)
Target Milestone: ---
Assignee: POI Developers List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-08-03 09:37 UTC by Andreas
Modified: 2016-09-21 16:46 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andreas 2016-08-03 09:37:13 UTC
Hi!

Since version 3.13 there is an issue with the logger and the changed POILogger: 

Whenever in the DocumentHelper class in the method trySetXercesSecurityManager and within the catch block (line 84) the logger is called, an IllegalAccessError is thrown by the logger instance call: 

logger.log(POILogger.WARN, "SAX Security Manager could not be setup", t);

Exception: 
java.lang.IllegalAccessError: tried to access method org.apache.poi.util.POILogger.log(ILjava/lang/Object;Ljava/lang/Throwable;)V from class org.apache.poi.util.DocumentHelper

This happens always if a xlsx workbook is contructed. 

When some of you fix this in the POILogger, please also change the order of SecurityManager whereas the in a server environment (e.g. JEE and JBoss) the org.apache.xerces.util.SecurityManager might probably more often in use: 

Should be: 

 "org.apache.xerces.util.SecurityManager"
 "com.sun.org.apache.xerces.internal.util.SecurityManager",
           
Thank you in advance,
Andreas
Comment 1 Nick Burch 2016-08-03 09:57:01 UTC
I don't see why DocumentHelper shouldn't be able to call POILogger, and I haven't noticed any issues with it elsewhere. Are you able to put together a small junit test case that triggers this IllegalAccessError?

Based on the comments in the code, we're trying the JDK built-in one first, as that's what we think most people are more likely to be using. It tries the other one if not, so you shouldn't miss out!
Comment 2 Andreas 2016-08-03 10:02:38 UTC
Ok, you are right, order should be ok. 

To keep things simple, put a line before the return statement. 

logger.log(POILogger.INFO, "SAX Security Manager setup"); 

If you see the changed method signature, all should clear, or not?

Kind regards,
Andreas
Comment 3 Nick Burch 2016-08-03 10:23:21 UTC
I added your logger statement to just before the return statement, and re-ran several of the XSSF unit tests. The logger statement worked just fine
Comment 4 Andreas 2016-08-03 11:45:56 UTC
I tried a bit more debugging and think I found it. 

Inspecting the NullLogger object, which is returned in the DocumentHelper

 private static POILogger logger = POILogFactory.getLogger(DocumentHelper.class);

there is a missing @Override annotation for the method public void log(int level, Object obj1, final Throwable exception): 

   /**
     * Log a message
     *
     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
     * @param obj1 The object to log.
     */

    @Override
    public void log(final int level, final Object obj1)
    {
        // do nothing
    }

    /**
     * Log a message
     *
     * @param level One of DEBUG, INFO, WARN, ERROR, FATAL
     * @param obj1 The object to log.  This is converted to a string.
     * @param exception An exception to be logged
     */
    public void log(int level, Object obj1, final Throwable exception) {
        // do nothing
    }

For probably that reason, the abstract method from the POILogger is called and the exception reflecting it: 

Caused by: java.lang.IllegalAccessError: tried to access method org.apache.poi.util.POILogger.log(ILjava/lang/Object;Ljava/lang/Throwable;)V from class org.apache.poi.util.DocumentHelper
	at org.apache.poi.util.DocumentHelper.trySetXercesSecurityManager(DocumentHelper.java:84)
	at org.apache.poi.util.DocumentHelper.<clinit>(DocumentHelper.java:57)


Try using it with a call before the return should prove it (where t can be null for testing purpose): 

logger.log(POILogger.WARN, "SAX Security Manager - test logger", t);

BTW the older 3.12 version of the NullLogger class has the annotation above the method. 

Can you confirm?

Kind regards, 
Andreas
Comment 5 Andreas 2016-08-05 09:37:42 UTC
Ok, I downloaded the 3.14 source from here:

https://www.apache.org/dyn/closer.lua/poi/release/src/poi-src-3.14.tar.gz

I did a few changes in 2 class files and compiled the source with Java 8, 32 bit. 

Fix 1)
To fix the IllegalAccessError, the abstract methods in the POILogger class are changed to public instead of protected:

abstract public void log(int level, Object obj1);
abstract public void log(int level, Object obj1, final Throwable exception);

Fix 2)

Put the @Override annotation above the method: 

@Override 
    public void log(int level, Object obj1, final Throwable exception) {
        // do nothing
    }
Comment 6 Dominik Stadler 2016-08-05 11:14:54 UTC
I don't think those two changes should make a difference, @override is a pure compile-time thing and not reflected in the bytecode in the .class/.jar file. Also protected should be fine and iwould usually fail during compile time if access is too strict.

Can you try to recompile the sources in their original state and see if that alone alreafy makes it work.
Comment 7 Andreas 2016-08-05 11:47:31 UTC
You might be right, but in that real case the IllegalAccess error is gone. 
The application server run with Java 1.8.0_72 and a JRE runtime error happens - probably a Oracle bug or a desired behaviour for such kind of declaration (abstract protected and override it with public).
 
There is nothing special I did, and I can't provide you a simple TestCase. As I mententioned before - try a logging with the method signature of the throwable and see yourself with Java 8. 

Kind regards,
Andreas
Comment 8 Andreas 2016-08-09 14:15:36 UTC
Please consider 

- the runtime is Java 8 in a JBoss 6 server environment

- the POILogger class in the DocumentHelper has no public log method (it is protected) - that leads to an IllegalAccess exception: 

private static POILogger logger = POILogFactory.getLogger(DocumentHelper.class);

Please change methods to public in POILogger and the thrill is gone:

abstract public void log(int level, Object obj1);
abstract public void log(int level, Object obj1, final Throwable exception);
Comment 9 Nick 2016-09-19 12:24:48 UTC
Anyone got a work around on this ? Running Iseries ( as400;systemi;whatever ibm wants to call it ).
Comment 10 Javen O'Neal 2016-09-21 02:21:24 UTC
I think I have fixed this in r1761662. The problem is that the signature of log(int, Object...) is identical to log(int, Object) or log(int, Object, final Throwable). We are relying on the visibility of the last two to make the log(int, Object...) the version that gets called.
Looking at the code, Java must prefer non-varargs over varargs functions when the signature is otherwise compatible, which is why Andreas had issues with NullLogger calling the log methods that were protected in POILogger but public in NullLogger.

We are silently falling back to using a NullLogger for the DocumentHelper class, hopefully because the org.apache.poi.util.POILogger system property has not been set and not a different reason. POILogFactory [1] seems to be catching and suppressing exceptions in multiple locations.

Could you verify this fix with the latest trunk release?

[1] POILogFactory https://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/util/POILogFactory.java?view=log
Comment 11 Javen O'Neal 2016-09-21 02:53:04 UTC
I fixed the accidental accessibility elevation from protected to public in the remaining logging classes in r1761665.

This does not introduce any backwards compatibility issues because log(int, Object...) is still public and will catch any of the old uses.
Comment 12 Nick 2016-09-21 06:47:15 UTC
(In reply to Javen O'Neal from comment #10)
> I think I have fixed this in r1761662. The problem is that the signature of
> log(int, Object...) is identical to log(int, Object) or log(int, Object,
> final Throwable). We are relying on the visibility of the last two to make
> the log(int, Object...) the version that gets called.
> Looking at the code, Java must prefer non-varargs over varargs functions
> when the signature is otherwise compatible, which is why Andreas had issues
> with NullLogger calling the log methods that were protected in POILogger but
> public in NullLogger.
> 
> We are silently falling back to using a NullLogger for the DocumentHelper
> class, hopefully because the org.apache.poi.util.POILogger system property
> has not been set and not a different reason. POILogFactory [1] seems to be
> catching and suppressing exceptions in multiple locations.
> 
> Could you verify this fix with the latest trunk release?
> 
> [1] POILogFactory
> https://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/util/
> POILogFactory.java?view=log

Sorted downloaded the beta1 release 3.16 problem gone Thanks !!!
Comment 13 Javen O'Neal 2016-09-21 16:46:59 UTC
@backwards compatibility: this is backwards compatible with any class using a logger, but not for classes subclassing POI logger. They will need to change log to _log and optionally drop the accessibility to protected.