Bug - Fixed Java 14 no longer compatible with (current) OSXAdapter

Veracity

Developer
Staff member
Copied from Croft's post in the KoLmafia thread in G-D:

Code:
[croft@Voyager KoL]$ java -jar KoLmafia-20276.jar

KoLmafia v20.7 r20276
Released on July 30, 2020

Currently Running on Mac OS X
Local Directory is /Users/croft/Library/Application Support/KoLmafia
Using Java 14

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by apple.dts.samplecode.osxadapter.OSXAdapter (file:/Users/croft/Games/KoL/KoLmafia-20276.jar) to constructor com.apple.eawt.Application()
WARNING: Please consider reporting this to the maintainers of apple.dts.samplecode.osxadapter.OSXAdapter
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
This version of Mac OS X does not support the Apple EAWT.  ApplicationEvent handling has been disabled (java.lang.ClassNotFoundException: com.apple.eawt.ApplicationListener)
This version of Mac OS X does not support the Apple EAWT.  ApplicationEvent handling has been disabled (java.lang.ClassNotFoundException: com.apple.eawt.ApplicationListener)
OSXAdapter could not access the About Menu
He is running (Java 14 on) macOS 10.15 - Catalina.
I am running (Java 8 on) macOS 10.14 - Mojave.

I suppose I should look into this.
 

Veracity

Developer
Staff member
We use the following methods from the OSXAdapter package:

Code:
./KoLCharacter.java:2586:				OSXAdapter.setDockIconBadge( String.valueOf( adventuresLeft ) );
./swingui/GenericFrame.java:207:		OSXAdapter.setWindowCanFullScreen( this, true );
./CreateFrameRunnable.java:355:			OSXAdapter.setQuitHandler( KoLmafia.class,
./CreateFrameRunnable.java:357:			OSXAdapter.setAboutHandler( KoLmafia.class,
./CreateFrameRunnable.java:359:			OSXAdapter.setPreferencesHandler( KoLmafia.class,
./KoLmafia.java:498:		OSXAdapter.setDockIconImage( JComponentUtilities.getImage( "limeglass.gif" ).getImage() );

Java 9 provides os-independent support for the About, Quit, and Preferences handlers in java.awt.Desktop.
Java 9 provides os-independent support for icon badge and icon image in java.awt.Taskbar.
Supposedly, in Java 9, windows are fullscreenable by default.

Isn't it nice that we now require Java 8? :)

OSXAdapter uses reflection to get com.apple.eawt objects and lookup and invoke methods on them.
I suppose we could do the same thing to get Java 9 Desktop and Taskbar objects and use those in place of com.apple.eawt - which would fix Catalina, since that class is removed there.
Maybe I should upgrade from Java 8 to Java 9 so I can experiment.

Sigh.
 

Veracity

Developer
Staff member
Sweet. I installed OpenJDK 14.0.2. I have a couple of bash functions that let me trivially switch JDK versions.

Code:
function setjdk() {
  if [ $# -ne 0 ]; then
   removeFromPath '/System/Library/Frameworks/JavaVM.framework/Home/bin'
   if [ -n "${JAVA_HOME+x}" ]; then
    removeFromPath $JAVA_HOME
   fi
   export JAVA_HOME=`/usr/libexec/java_home -v $@`
   export PATH=$JAVA_HOME/bin:$PATH
  fi
 }
function removeFromPath() {
  export PATH=$(echo $PATH | sed -E -e "s;:$1;;" -e "s;$1:?;;")
}

With my Java 8 JDK:

Code:
bash-3.2$ setjdk 1.8.0_172
bash-3.2$ java -jar dist/KoLmafia-20.7.jar 

KoLmafia v20.7 r20282
Released on July 30, 2020

Currently Running on Mac OS X
Local Directory is /Users/Brianna/Library/Application Support/KoLmafia
Using Java 1.8.0_172
Everything works as normal.

With the Java 14 JDK:

Code:
bash-3.2$ setjdk 14.0.2
bash-3.2$ java -jar dist/KoLmafia-20.7.jar 

KoLmafia v20.7 r20282
Released on July 30, 2020

Currently Running on Mac OS X
Local Directory is /Users/Brianna/Library/Application Support/KoLmafia
Using Java 14.0.2

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by apple.dts.samplecode.osxadapter.OSXAdapter (file:/src/kolmafia/dist/KoLmafia-20.7.jar) to constructor com.apple.eawt.Application()
WARNING: Please consider reporting this to the maintainers of apple.dts.samplecode.osxadapter.OSXAdapter
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
This version of Mac OS X does not support the Apple EAWT.  ApplicationEvent handling has been disabled (java.lang.ClassNotFoundException: com.apple.eawt.ApplicationListener)
This version of Mac OS X does not support the Apple EAWT.  ApplicationEvent handling has been disabled (java.lang.ClassNotFoundException: com.apple.eawt.ApplicationListener)
OSXAdapter could not access the About Menu
java.lang.NoSuchMethodException: com.apple.eawt.Application.setEnabledAboutMenu(boolean)
	at java.base/java.lang.Class.getDeclaredMethod(Class.java:2553)
	at apple.dts.samplecode.osxadapter.OSXAdapter.setAboutHandler(OSXAdapter.java:114)
	at net.sourceforge.kolmafia.CreateFrameRunnable.addOSXMenuItems(CreateFrameRunnable.java:357)
	at net.sourceforge.kolmafia.CreateFrameRunnable.decorate(CreateFrameRunnable.java:335)
	at net.sourceforge.kolmafia.CreateFrameRunnable.runConstruction(CreateFrameRunnable.java:302)
	at net.sourceforge.kolmafia.CreateFrameRunnable.createFrame(CreateFrameRunnable.java:182)
	at net.sourceforge.kolmafia.CreateFrameRunnable.run(CreateFrameRunnable.java:164)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:306)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
... and more similar exceptions...
I should have everything I need to address this issue at my leisure.
 

Veracity

Developer
Staff member
I updated the title of this bug report, since the issue is Java 14, not Catalina per se.
 

gausie

D̰͕̝͚̤̥̙̐̇̑͗̒e͍͔͎͈͔ͥ̉̔̅́̈l̠̪̜͓̲ͧ̍̈́͛v̻̾ͤe͗̃ͥ̐̊ͬp̔͒ͪ
Staff member
I use jenv for exactly this. I don't think its too early to move to J9 fwiw. I think on projects like this developer experience is just as important as user experience
 

Veracity

Developer
Staff member
I have heavily whacked OSXAdapter to detect if you are using at least Java 9 (by looking at the Enum tags for Desktop.Action and seeing if "APP_ABOUT" is included; even if I compile it with target of 1.8, if my jdk is 14, that enum tag will be present. I just can't use it in code.)

If I find the enum tag, all the OSXAdapter methods now use Desktop or Taskbar objects to register event handlers. Otherwise, they use the old Application object which is no longer supported.

With this change:

- "About KoLmafia" menu item pops up our custom About frame
- "Preferences" menu item opens our Preferences Frame
- "Quit" goes through KoLmafia.quit, which saves settings, logs you out, etc.
- The dock icon is the lime glass again
- The dock icon badge is the number of turns you have available.

Which is to say, it seems to work just as well - with no error messages or stack traces - as it did with my Java 8 JDK.

I'll submit it, with some trepidation, since it is very unfamiliar to me - but I've done all the testing that I can do, I think.
I'm sure somebody will complain if something is still broken - or newly broken.

Revision 20284
 

Veracity

Developer
Staff member
Croft says it works correctly for him, over on G-D.

I’m marking this fixed, although I want to turn on lint logging so I can see more details of Java 14’s reporting of unsafe or unchecked operations as well as deprecated APIs.
 

MCroft

Developer
Staff member
This confused the heck out of me, because of the name similarities (Croft != MCroft) and because I was meaning to come report it here (or try to fix it myself).

I can report that I can compile and execute the fix with Java 13/OpenJ9 on Big Sur. There's a few more deprecated methods, but nothing is so deprecated that it fails.
 

Croft

Member
This confused the heck out of me, because of the name similarities (Croft != MCroft) and because I was meaning to come report it here (or try to fix it myself).

I can report that I can compile and execute the fix with Java 13/OpenJ9 on Big Sur. There's a few more deprecated methods, but nothing is so deprecated that it fails.

>.>
<.<
 

gausie

D̰͕̝͚̤̥̙̐̇̑͗̒e͍͔͎͈͔ͥ̉̔̅́̈l̠̪̜͓̲ͧ̍̈́͛v̻̾ͤe͗̃ͥ̐̊ͬp̔͒ͪ
Staff member
Dedication to multi abuse
 

MCroft

Developer
Staff member
I want to turn on lint logging so I can see more details of Java 14’s reporting of unsafe or unchecked operations as well as deprecated APIs.

I just ran test-compile target with the addition of <compilerarg value="-Xlint"/> to the compile target (and setting the javac task source and target to 13 (because that's what I've got installed).

I got about 100 warnings back, although many of them are duplicates (WarningThing.add("Sun"), WarningMethod.add("Mon"), etc.). 13 deprecated messages (about 5 when dups are removed), the rest unchecked call/conversion/cast.

Want my list? or I can install Java 14 and get you that version. In either case, it may well be a new feature request instead of an OS X adapter bug.
 

Veracity

Developer
Staff member
Thanks. I changed the compile task to look like this:

Code:
	<target name="compile" depends="init,version">

		<javac
			compiler="modern"
			source="14"
			target="14"
			srcdir="${lib}"
			destdir="${build}"
			failonerror="false"
			debug="on"
			debuglevel="lines,vars,source"
			deprecation="off"
			encoding="utf-8"
			nowarn="on"
			includeantruntime="false"
			errorProperty="compile.failed">
			<classpath>
				<pathelement path="${classpath}"/>
				<fileset dir="${lib}/jar">
					<include name="**/*.jar"/>
				</fileset>
			</classpath>
                        <compilerarg value="-Xlint"/>
		</javac>

		<fail if="compile.failed" message="Failed to compile third-party libraries" />

		<copy todir="${build}" preservelastmodified="true">
			<fileset dir="${lib}">
				<exclude name="**/*.jar" />
				<exclude name="**/*.java" />
			</fileset>
		</copy>

		<replace
			file="${KoLConstants}"
			token="REVISION = null"
			value="REVISION = "${revision}"" />

		<javac
			compiler="modern"
			source="14"
			target="14"
			srcdir="${src}"
			destdir="${build}"
			classpath="${build}"
			failonerror="false"
			debug="on"
			debuglevel="lines,vars,source"
			deprecation="off"
			encoding="utf-8"
			nowarn="on"
			includeantruntime="false"
			errorProperty="compile.failed">
                        <compilerarg value="-Xlint"/>
		</javac>

		<replace
			file="${KoLConstants}"
			token="REVISION = "${revision}""
			value="REVISION = null" />

		<replace
			file="${KoLConstants}"
			token="RELEASED = false"
			value="RELEASED = true" />

		<fail if="compile.failed" message="Failed to compile KoLmafia source code" />

		<copy todir="${build}" preservelastmodified="true">
			<fileset dir="${src}">
				<exclude name="**/*.jar" />
				<exclude name="**/*.java" />
			</fileset>
		</copy>

	</target>
That checks for "lib" and "src".

Most of the ones in "lib" are in HTMLCleaaner, although some are in OSXAdapter and LockableListModel.

I have a ton of deprecations and unchecked warnings in "src". Some of them amuse me.

For example, did you know that "new Integer( int )" is deprecated because "It is rarely appropriate to use this constructor."?

I believe that, since Java will autobox an int into an Integer for you. Of course, we are storing into a Object, since we might store an Integer or a Double or a String...

Which might be poor code, but KoLmafia has its share of such.

We hit 100 warnings in about a dozen files. Hard to believe those are the only ones deserving of warnings.

I might make a Bug report with my modification to the "compile" task, but since I think it is truncating error reporting after 100 (unless there are EXACTLY 100 warnings, which is suspicious), I don't think putting in a list of warnings is necessary.
 

xKiv

Active member
For example, did you know that "new Integer( int )" is deprecated because "It is rarely appropriate to use this constructor."?

IIRC it's because new Integer(int) always creates a new object. You are supposed to use Integer.valueOf(int) instead, it will use cached objects for some predetermined range of small ints (-128..127 or something, but any implementation can change this). This can be important for performance (you are not pointlessly creating and throwing away many many "sameish" objects -> fewer garbage collections)
 

Veracity

Developer
Staff member
Sweet. We have our own IntegerPool cache which does that. I should get rid of it and use the native implementation.
 

MCroft

Developer
Staff member
We hit 100 warnings in about a dozen files. Hard to believe those are the only ones deserving of warnings.

I might make a Bug report with my modification to the "compile" task, but since I think it is truncating error reporting after 100 (unless there are EXACTLY 100 warnings, which is suspicious), I don't think putting in a list of warnings is necessary.

You could set <compilerargs line="-Xmaxwarns 2000"/> on javac to 2000

I got 1595 warnings.
 

Veracity

Developer
Staff member
Well ... yours seems to be doing much larger range than expected ...
Yes. It is enough to hold all itemIds, which are common map keys.
I changed IntegerPool to use Integer.valueOf() when initializing its cache.
We have a lot of code which doesn't use either IntegerPool or Integer.valueOf. I got rid of all the "new Integer" cases, but there is still plenty of implicit boxing being used: simply passing an int as a key or a value, for example.

I spent the afternoon grinding through a bunch of compiler warnings. With Java 14, we are now down to 2267 of them.
I opened a new Bug Report to track this work.
I wouldn't mind not being the only one working on it. ;)
 
Top