Java 9 (JNLP) problem while loading bibliothek.util.workarounds.Java6Workaround class dependencies


#1

Hi,

Looks like there is a bug with Java 9 running application with JNLP when com.sun.awt.AWTUtilities and com.sun.awt.AWTUtilities.Translucency classes need to be loaded in Java6Workaround. The java.lang.IllegalAccessError is thrown as a result. Here is the exact error:

java.lang.RuntimeException: Exception in application: java.lang.IllegalAccessError: class
bibliothek.util.workarounds.Java6Workaround … cannot access class
com.sun.awt.AWTUtilities … because module java.desktop does not export
com.sun.awt …

Since the Java6Workaround class is included inside the latest (1.1.2) dockingframes core build there is no simple way to avoid that error. I would suggest either to make that workarounds library optional or use Java reflection mechanism so that the illegal access errors can be handled (though with the reflection may run slower). Attaching updated Java6Wrokaround class code, which uses the reflection to avoid the com.sun.awt.AWTUtilities and com.sun.awt.AWTUtilities.Translucency loading:

package bibliothek.util.workarounds;

import java.awt.Component;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Window;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import bibliothek.gui.DockController;
import bibliothek.gui.dock.StackDockStation;
import bibliothek.gui.dock.station.stack.DnDAutoSelectSupport;

/**
 * Workarounds necessary for Java 1.6.
 * @author Benjamin Sigg
 */
public class Java6Workaround implements Workaround{
	/** whether to print any warnings */
	private static boolean printWarnings = false;
	
	/**
	 * Sets whether the methods of the {@link Java6Workaround} can print warnings or not. Calling this method
	 * affects <b>all</b> workarounds. The default behavior is <b>not</b> to print warnings.
	 * @param printWarnings whether to print warnings
	 */
	public static void setPrintWarnings( boolean printWarnings ){
		Java6Workaround.printWarnings = printWarnings;
	}
	
	/**
	 * Tells whether all {@link Java6Workaround}s are allowed to print warnings.
	 * @return whether to print warnings
	 * @see #setPrintWarnings(boolean)
	 */
	public static boolean isPrintWarnings(){
		return printWarnings;
	}
	
	/** ensures the warning message is printed out at most once */
	private boolean invocationTargetException = false;
	
	@Override
	public void setup( DockController controller ){
		controller.getProperties().set( StackDockStation.DND_AUTO_SELECT_SUPPORT, new DnDAutoSelectSupport() );
	}
	
	public void markAsGlassPane( Component component ){
		try {
			Class<?> awtUtilitiesClass = Class.forName( "com.sun.awt.AWTUtilities" );
			Method setComponentMixingCutoutShapeMethod = awtUtilitiesClass.getMethod( "setComponentMixingCutoutShape", Component.class, Shape.class );
			setComponentMixingCutoutShapeMethod.invoke( null, component, new Rectangle() );
		}
		catch (ClassNotFoundException ex) {
			// ignore
		}
		catch (NoSuchMethodException ex) {
			// ignore
		}
		catch (SecurityException ex) {
			// ignore
		}
		catch (IllegalAccessException ex) {
			// ignore
		}
		catch (IllegalArgumentException ex) {
			// ignore
		}
		catch (InvocationTargetException ex) {
			// ignore
		}
	}
	
	public boolean supportsPerpixelTranslucency( Window window ){
		// AWTUtilities.isTranslucencySupported(Translucency)
		
		try {
			Class<?> awtUtilitiesClass = Class.forName( "com.sun.awt.AWTUtilities" );
			Class<?> translucencyClass = Class.forName( "com.sun.awt.AWTUtilities.Translucency" );
			Method isTranslucencySupportedMethod = awtUtilitiesClass.getMethod( "isTranslucencySupported", translucencyClass );
			Field PERPIXEL_TRANSLUCENT = translucencyClass.getField( "PERPIXEL_TRANSLUCENT" );
			isTranslucencySupportedMethod.invoke( null, PERPIXEL_TRANSLUCENT.get(null) );
		}
		catch (ClassNotFoundException ex) {
			// ignore
		}
		catch (NoSuchMethodException ex) {
			// ignore
		}
		catch (SecurityException ex) {
			// ignore
		}
		catch (IllegalAccessException ex) {
			// ignore
		}
		catch (IllegalArgumentException ex) {
			// ignore
		}
		catch (InvocationTargetException ex) {
			// ignore
		}
		catch (Exception ex) {
			if( printWarnings && !invocationTargetException ){
				invocationTargetException = true;
				ex.printStackTrace();
			}
		}
		return false;
	}
	
	public boolean supportsPerpixelTransparency( Window window ){
		if( window instanceof Dialog && !((Dialog)window).isUndecorated() ){
			return false;
		}
		if( window instanceof Frame && !((Frame)window).isUndecorated() ){
			return false;
		}
		
		try{
			return supportsPerpixelTranslucency(window);
		}
		catch( NoClassDefFoundError ex ){
			// ignore
		}
		catch( NoSuchFieldError ex ){
			// ignore
		}
		return false;
	}
	
	public boolean setTranslucent( Window window ){
		if( !supportsPerpixelTranslucency( window )){
			return false;
		}
		
		try {
			Class<?> awtUtilitiesClass = Class.forName( "com.sun.awt.AWTUtilities" );
			Method setWindowOpaqueMethod = awtUtilitiesClass.getMethod( "setWindowOpaque", Window.class, boolean.class );
			setWindowOpaqueMethod.invoke( null, window, false );
		}
		catch (ClassNotFoundException ex) {
			// ignore
		}
		catch (NoSuchMethodException ex) {
			// ignore
		}
		catch (SecurityException ex) {
			// ignore
		}
		catch (IllegalAccessException ex) {
			// ignore
		}
		catch (IllegalArgumentException ex) {
			// ignore
		}
		catch (InvocationTargetException ex) {
			// ignore
		}
		catch( Exception ex ){
			if( printWarnings && !invocationTargetException ){
				invocationTargetException = true;
				ex.printStackTrace();
			}
		}
		return false;
	}
	
	public boolean setTransparent( Window window, Shape shape ){
		if( !supportsPerpixelTransparency( window )){
			return false;
		}
		
		try {
			Class<?> awtUtilitiesClass = Class.forName( "com.sun.awt.AWTUtilities" );
			Method setWindowShapeMethod = awtUtilitiesClass.getMethod( "setWindowShape", Window.class, Shape.class );
			setWindowShapeMethod.invoke( null, window, shape );
		}
		catch (ClassNotFoundException ex) {
			// ignore
		}
		catch (NoSuchMethodException ex) {
			// ignore
		}
		catch (SecurityException ex) {
			// ignore
		}
		catch (IllegalAccessException ex) {
			// ignore
		}
		catch (IllegalArgumentException ex) {
			// ignore
		}
		catch (InvocationTargetException ex) {
			// ignore
		}
		catch( Exception ex ){
			if( printWarnings && !invocationTargetException ){
				invocationTargetException = true;
				ex.printStackTrace();
			}
		}
		return false;
	}
}

Regards,
Zilvinas


#2

Hi,

I would also add a class for Java 9 workaround. Following design of the previous workaround classes.

package bibliothek.util.workarounds;

import java.awt.Component;
import java.awt.Rectangle;
import java.awt.Shape;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Java9Workaround extends Java7Workaround{
	
	public void markAsGlassPane( Component component ){
		try {
			Method setComponentMixingCutoutShapeMethod = Component.class.getMethod( "setComponentMixingCutoutShape", Shape.class );
			setComponentMixingCutoutShapeMethod.invoke( null, new Rectangle() );
		}
		catch (NoSuchMethodException ex) {
			System.out.println(ex.getMessage());
		}
		catch (SecurityException ex) {
			System.out.println(ex.getMessage());
		}
		catch (IllegalAccessException ex) {
			System.out.println(ex.getMessage());
		}
		catch (IllegalArgumentException ex) {
			System.out.println(ex.getMessage());
		}
		catch (InvocationTargetException ex) {
			System.out.println(ex.getMessage());
		}
	}

}

Regards,
Zilvinas


#3

Beni hasn’t been here recently, but maybe an @Beni will help. (Not sure about his notification settings…)


#4

Sorry, I did not notice your message.

I’ll include your workaround ASAP.


#5

Thanks for bringing this issue to my attention. I have updated Java6Workaround and included Java9Workaround.

I have not much experience with Java 9, and could not reproduce your original error (ok, I admit, I did only try to reproduce the issue for about 10 minutes before giving up. 5 of these 10 minutes were spent downloading and installing Java 9). But the important libraries should not contain any other “evil” imports.


#6

Thank you Beni for the update!

In order to reproduce it in Java 9 you need to use Java Web Start. Restrictions take place only when application is executed through JNLP. But in upcoming versions (Java 10, 11) it might affect regular jars as well.