Search code examples
javaeclipseexeclassloaderbirt

How to load a class file encrypted or protected by jar2exe from unprotected context, for example, Eclipse Birt?


I used Eclipse Birt Engine 4.4.2 (birt-runtime-4_4_2) in my project, And when i encrypt java classes with Jar2exe, even with not hiding "C:\fx.jar|META-INF*|com\javafx**" , Birt Engine class loader is not able to load report handler classes, Is there a way to pass this error?

    Error.ScriptClassNotFoundError ( 1 time(s) )
detail : org.eclipse.birt.report.engine.api.EngineException: Class com.osyslocal.management.view.report.handler.stimgun.general.ReportHandler not found.
    at org.eclipse.birt.report.engine.executor.EventHandlerManager.loadClass(EventHandlerManager.java:104)
    at org.eclipse.birt.report.engine.executor.EventHandlerManager.getInstance(EventHandlerManager.java:75)
    at org.eclipse.birt.report.engine.executor.EventHandlerManager.getInstance(EventHandlerManager.java:49)
    at org.eclipse.birt.report.engine.script.internal.ScriptExecutor.getInstance(ScriptExecutor.java:195)
    at org.eclipse.birt.report.engine.script.internal.ReportScriptExecutor.handleInitialize(ReportScriptExecutor.java:86)
    at org.eclipse.birt.report.engine.api.impl.EngineTask.loadDesign(EngineTask.java:1962)
    at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.doRun(RunAndRenderTask.java:99)
    at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.run(RunAndRenderTask.java:77)
    at com.osyslocal.management.view.results.analysis.AnalyzeResult.createReport(AnalyzeResult.java:376)
    at com.osyslocal.management.view.ui.ProjectView.showReport(ProjectView.java:1015)
    at com.osyslocal.management.view.results.stimgun.AnalyzeStimgunResult$1.execute(AnalyzeStimgunResult.java:90)
    at mysystem.controller.TaskManager$2.run(TaskManager.java:145)
    at org.eclipse.swt.widgets.RunnableLock.run(Unknown Source)
    at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Unknown Source)
    at org.eclipse.swt.widgets.Display.runAsyncMessages(Unknown Source)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
    at org.eclipse.jface.window.Window.runEventLoop(Window.java:826)
    at org.eclipse.jface.window.Window.open(Window.java:802)
    at com.osyslocal.management.view.ui.Main$7.run(Main.java:463)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
    at com.osyslocal.management.view.ui.Main.main(Main.java:456)
Caused by: java.lang.ClassNotFoundException: com.osyslocal.management.view.report.handler.stimgun.general.ReportHandler
    at org.eclipse.birt.core.framework.URLClassLoader.findClass1(URLClassLoader.java:188)
    at org.eclipse.birt.core.framework.URLClassLoader$1.run(URLClassLoader.java:156)
    at org.eclipse.birt.core.framework.URLClassLoader$1.run(URLClassLoader.java:1)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.eclipse.birt.core.framework.URLClassLoader.findClass(URLClassLoader.java:151)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at org.eclipse.birt.report.engine.executor.ApplicationClassLoader.loadClass(ApplicationClassLoader.java:79)
    at org.eclipse.birt.report.engine.executor.EventHandlerManager.loadClass(EventHandlerManager.java:99)
    ... 20 more

Solution

  • Problem: According to the solution provided by the jar2exe official website, Every class has a ClassLoader that loads the class.

    The ClassLoader of protected (encrypted) classes, is a special ClassLoader, while the ClassLoader of unprotected classes is another ClassLoader. When the program is to load a class or resource, it will use the ClassLoader of the current class by default, such as "Class.forName()". So in the Eclipse Birt program is to load protected resource within an unprotected class, the ClassLoader of the unprotected class cannot load the protected resources. In this problem, the program tried to load ReportHandler class from an unprotected ApplicationClassLoader class.

    Solution: When a generated exe file runs, The context ClassLoader of the current thread, is a Special ClassLoader. So we tried to download the source of Eclipse Birt Engine and then changed the body of loadClass(className) method of ApplicationClassLoader class and replaced the following line:

    Thread.currentThread().getContextClassLoader().loadClass(className);
    

    Therefore the program sends the className as an argument containing the FQDN of the protected class (ReportHandler). Then successfully the modified and compiled ApplicationClassLoader class in the Eclipse Birt jar file runs the program without failure. The final edited version of the method is as follows:

    public Class loadClass( String className ) throws ClassNotFoundException
        {
            return Thread.currentThread().getContextClassLoader().loadClass(className);
        }