RPTools.net

Discussion and Support

Skip to content

It is currently Tue Oct 17, 2017 11:00 pm 






Reply to topic  [ 22 posts ]  Go to page 1, 2  Next

Previous topic | Next topic 

  Print view

Author Message
User avatar  Offline
Dragon
 
Joined: Wed Jul 03, 2013 4:58 am
Posts: 350
 Post subject: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Sat Sep 07, 2013 6:28 am 
Ed Note: If this should be in a different section of the Forum the I apologize and request that admin move it to the correct section

I am trying to write a modification to MapTool (for my own purpose and anyone else that likes the mod) which is based on Java 7's nio function. However, for users who are not using Java 7, I can provide similar (but slightly watered down) functionality using pre Java 7 io functions.

It was suggested to me to Class to try to call the Java 7 Class and if this fails resort to using the Java 6 version. I found the following existing example in MapTool.java:

Code:
try {
   Class<?> appClass = Class.forName("com.apple.eawt.Application");
   Method getApplication = appClass.getDeclaredMethod("getApplication", (Class[]) null);
   Object appl = getApplication.invoke(null, (Object[]) null);
   Method setDockIconImage = appl.getClass().getDeclaredMethod("setDockIconImage", new Class[] { java.awt.Image.class });
   // If we couldn't grab the image for some reason, don't set the dock bar icon!  Duh!
   if (img != null)
      setDockIconImage.invoke(appl, new Object[] { img });
      if (MapToolUtil.isDebugEnabled()) {
      // For some reason Mac users don't like the dock badge icon.  But from a development standpoint I like seeing the
      // version number in the dock bar.  So we'll only include it when running with MAPTOOL_DEV on the command line.
      Method setDockIconBadge = appl.getClass().getDeclaredMethod("setDockIconBadge", new Class[] { java.lang.String.class });
      String vers = getVersion();
      vers = vers.substring(vers.length() - 2);
      vers = vers.replaceAll("[^0-9]", "0"); // Convert all non-digits to zeroes
      setDockIconBadge.invoke(appl, new Object[] { vers });
   }
} catch (Exception e) {
   log.info("Cannot find/invoke methods on com.apple.eawt.Application; use -X command line options to set dock bar attributes", e);
}


As far as I can tell the first part tries to call the getApplication class in com.apple.eawt.Application and then does some things with it if successful or drops to the log.info if the loading and/or invoking of the class is unsuccessful.

If I am correct the relevant part to invoking the class (and thus determining if it is available) can be summarized with:

Code:
try {
   Class<?> appClass = Class.forName("[i]file_in_which_the_class_is_defined[/i]");
   Method getApplication = appClass.getDeclaredMethod("[i]class_name[/i]", (Class[]) null);
   Object appl = getApplication.invoke(null, (Object[]) null);
} catch (Exception e) {
   // Class was not loaded
}


For my solution, I wrote two classes: one Java 6 class and one Java 7 class. I use the above to try to invoke the Java 7 class first and the if that fails I try the Java 6 class. The corresponding code looks like this:

Code:
// Clean up the cache
try
{
   Class<?> java7CacheClass = Class.forName("net.rptools.maptool.client.CacheCleanerJava7");
   Method getJava7CacheApplication = java7CacheClass.getDeclaredMethod("CheckCacheSize", (Class[]) null);
   getJava7CacheApplication.invoke(null, (Object[]) null);
}
catch(Exception x)
{
   try
   {
      Class<?> java6CacheClass = Class.forName("net.rptools.maptool.client.CacheCleanerJava6");
      Method getJava6CacheApplication = java6CacheClass.getDeclaredMethod("CheckCacheSize", (Class[]) null);
      getJava6CacheApplication.invoke(null, (Object[]) null);
   }
   catch(Exception x2)
   {
      MapTool.showWarning("Unable To Load Java6- or Java7+ CacheCleaner Implementation.");
   }
}


As far as I can tell this should try to load the Java 7 class, if that fails try to load the Java 6 class and if that fails displays the warning.
When I try this on my Win8 machine using Java 7 it correctly runs the Java 7 branch of the code. However, when I try the same code on my Ubuntu machine running Java 6 then the program cores before it gets to the Java 6 branch. I believe that my Ubuntu Java 6 machine is set up correctly because it can run an unmodified version of MapTool without any problems.

As far as I know the Java 7 Class uses nio and thus is not pre Java 7 compatible but the Java 6 Class code does not use any Java 7 functions and thus should be Java 6 compatible.

I am enclosing a Diff Path for my modifications which includes the source code for the two (Java 6 and Java 7) new classes.

Attachment:
CacheCleaner_Rev5_Patch_For_MapTool-1.3.b89.txt [17.14 KiB]
Downloaded 80 times


Can anyone point me in the right direction as to why my Java 6 / Java 7 compatibility does not seem to be working?

_________________
"We often compare ourselves to the U.S. and often they come out the best,
but they only have the right to bare arms, while we have the right to bare breasts"
The Right To Bare Breasts by Bowser & Blue


Last edited by Azhrei on Mon Sep 09, 2013 12:38 pm, edited 1 time in total.
moved to Developer Notes


Top
 Profile  
 
User avatar  Offline
Site Admin
 
Joined: Mon Jun 12, 2006 12:20 pm
Posts: 12101
Location: Tampa, FL
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Mon Sep 09, 2013 12:37 pm 
Close. When you call getDeclaredMethod() you're not passing a class name, but the name of the method within the class that you want to invoke. The class name has already been specified when you called forName() (the parameter isn't a file name, but a fully qualified class name).

You're probably getting a null reference back from the getDeclaredMethod() and that's causing the crash.

You might be able to get some more info by Google'ing that method name. You can look at documentation for JDBC since its drivers are often loaded using forName() and there will be a LOT of examples based around it. (Well, unless the example has been updated to use JNDI, but many haven't been because that's a lot more configuration for simple use cases.)


Top
 Profile  
 
 Offline
Dragon
 
Joined: Sun Sep 04, 2011 6:01 am
Posts: 260
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Mon Sep 09, 2013 1:16 pm 
I suggest you use
Code:
System.getProperty("java.version")
instead of relying on exceptions. BTW, Azhrei's explanation of your problem doesn't explain a core dump. Are you sure you saw a core dump?


Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Wed Jul 03, 2013 4:58 am
Posts: 350
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Tue Sep 10, 2013 12:37 am 
Azhrei wrote:
Close. When you call getDeclaredMethod() you're not passing a class name, but the name of the method within the class that you want to invoke. The class name has already been specified when you called forName() (the parameter isn't a file name, but a fully qualified class name).


You are right. However, as far as I can tell that is what my code does (I just explained it incorrectly).

In my code the Class is CacheCleanerJava7 and the public Method to call inside that class is CheckCacheSize.

Azhrei wrote:
You're probably getting a null reference back from the getDeclaredMethod() and that's causing the crash.

You might be able to get some more info by Google'ing that method name. You can look at documentation for JDBC since its drivers are often loaded using forName() and there will be a LOT of examples based around it. (Well, unless the example has been updated to use JNDI, but many haven't been because that's a lot more configuration for simple use cases.)


You lost me a little here. I can't possible google the CheckCacheSize method (of CacheCleanerJava7) because I wrote it. Are you suggesting that I google the forName() of Class?

_________________
"We often compare ourselves to the U.S. and often they come out the best,
but they only have the right to bare arms, while we have the right to bare breasts"
The Right To Bare Breasts by Bowser & Blue


Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Wed Jul 03, 2013 4:58 am
Posts: 350
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Tue Sep 10, 2013 12:40 am 
username wrote:
I suggest you use
Code:
System.getProperty("java.version")
instead of relying on exceptions. BTW, Azhrei's explanation of your problem doesn't explain a core dump. Are you sure you saw a core dump?


As far as I know, I can't use that method (there is even a note about it in the MapTool source code) because if you don't use the Class method of invoking the class at runtime, the class gets compiled into the code (even if the logic never runs it) and this will prevent the executable from running on machines which can not run that class (i.e. machines that do not have Java 7)...which is exactly what I am trying to avoid.

Unless you are suggesting to still use the runtime Class invoking but use the above code to determine which to use. Hmm...I could work. I'll give that a try.

_________________
"We often compare ourselves to the U.S. and often they come out the best,
but they only have the right to bare arms, while we have the right to bare breasts"
The Right To Bare Breasts by Bowser & Blue


Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Wed Jul 03, 2013 4:58 am
Posts: 350
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Tue Sep 10, 2013 4:56 am 
username wrote:
I suggest you use
Code:
System.getProperty("java.version")
instead of relying on exceptions. BTW, Azhrei's explanation of your problem doesn't explain a core dump. Are you sure you saw a core dump?


MapTool detects the JAVA version and makes it available via:

Code:
MapTool.JAVA_VERSION


Just to see how this is determined, I look at the source code and it seems that it uses:

Code:
System.getProperty("java.specification.version");


"specification" is inserted between "java" and "version"


Was that a typo on your part or does java.version and java.specification.version get different properties?

_________________
"We often compare ourselves to the U.S. and often they come out the best,
but they only have the right to bare arms, while we have the right to bare breasts"
The Right To Bare Breasts by Bowser & Blue


Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Wed Jul 03, 2013 4:58 am
Posts: 350
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Tue Sep 10, 2013 5:41 am 
Okay...I took everyone's suggestion and applied the following changes:

1. I am using MapTool.JAVA_VERSION to determine if I should use the Java 7 or Java 6 Class
2. I have made the two classes use different methods (so that I could...)
3. I only invoke the Java 7 class using the runtime Class method. I have now added the Java 6 class as a normal compile time class.

The modified code looks like:

Code:
// Clean up the cache
if(MapTool.JAVA_VERSION>=1.7)
{
   try
   {
      Class<?> java7CacheClass = Class.forName("net.rptools.maptool.client.CacheCleanerJava7");
      Method getJava7CacheApplication = java7CacheClass.getDeclaredMethod("CheckCacheSizeViaJava7", (Class[]) null);
      getJava7CacheApplication.invoke(null, (Object[]) null);
   }
   catch(Exception x2)
   {
      MapTool.showWarning("Unable To Load Java7+ CacheCleaner Implementation.");
      CacheCleanerJava6.CheckCacheSizeViaJava6();
   }
}
else
{
   CacheCleanerJava6.CheckCacheSizeViaJava6();
}


However when I run this on my Ubuntu Java 6 VM, I still get the same error:

Quote:
lordashes@lordashes-VirtualBox:~/Documents/MapTool_CGE_3$ java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)
lordashes@lordashes-VirtualBox:~/Documents/MapTool_CGE_3$ ./LaunchMapTool.sh
Executing maptool-1.3.b89.CGEwS.v3.2.jar ...
Exception in thread "main" java.lang.UnsupportedClassVersionError: net/rptools/maptool/client/LaunchInstructions : Unsupported major.minor version 51.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: net.rptools.maptool.client.LaunchInstructions. Program will exit.


I checked LaunchInstructions.java and all it seems to do is setup the memory and run the main program. I tried increasing the amount of memory to MapTool (in the .SH file) but got the same results. I am confused as to what the major.minor version seems to be referring to. It can't be the Java version because that does not have 51.0 in it at all.

As I said, normally I would conclude that my Java installation is incorrect or not compatible but I am able to run the unmodified MapTool on it, so either my modification still uses some Java 7 code somewhere or something specific that I added is not implemented in the Java 6 implementation that I am using.

_________________
"We often compare ourselves to the U.S. and often they come out the best,
but they only have the right to bare arms, while we have the right to bare breasts"
The Right To Bare Breasts by Bowser & Blue


Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Wed Jul 03, 2013 4:58 am
Posts: 350
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Tue Sep 10, 2013 6:32 am 
I googled the problem and some people say that this problem is causes when you compile the application using a JDK that is a newer version than the JRE you are using to run it on.

Since my development machine is using Java 7 (and has only Java 7 installed) but I am trying to get it running on Java 6 this would be, in my case, true.

It seems that in Eclipse you can select the compile compatibility level but you need the respective level JDK/JRE installed. I will see if I can get a Java 6 JDK/JRE installed and see if that resolves my issue.

_________________
"We often compare ourselves to the U.S. and often they come out the best,
but they only have the right to bare arms, while we have the right to bare breasts"
The Right To Bare Breasts by Bowser & Blue


Top
 Profile  
 
 Offline
Dragon
 
Joined: Wed Oct 19, 2011 1:07 am
Posts: 958
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Tue Sep 10, 2013 7:30 am 
If you're using Eclipse for Java EE, you can convert your project to faceted form and change the Java compiler compliance to Java 6. This is if you want to avoid installing multiple JDKs and JREs on your system. Just go into your project properties and on the left pane, you'll find the list item for "Project Facets". It should be straightforward from there. I hope this helps.

_________________
My stuff for the community:
Donate to the Mote Project
The Mote Project's G+ community
Mote on Facebook
Fully Customizable Calendar Drop-in


Top
 Profile  
 
 Offline
Dragon
 
Joined: Sun Sep 04, 2011 6:01 am
Posts: 260
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Tue Sep 10, 2013 1:37 pm 
java.version gves you the exact version (including patch level) while java.specification.version gives you the specification the impleentation complies with. I don't know, whether OpenJDK uses a different java.version prefix. So, yes, the specification version is probably better.

With the exception you saw, Lee's suggestion is probably best. You can achieve the same thing with a javac switch that forces it to generate output for a 1.6 JVM. Note that you still need to do the checks, because the imports you rely on are available during compile time and not during runtime. But you can avoid the reflection API (and probably the try/catch). Just invoke the method directly.

Code:
// Clean up the cache
if(MapTool.JAVA_VERSION>=1.7)
{
   CacheCleanerJava7.checkCacheSizeViaJava7();
}
else
{
   CacheCleanerJava6.checkCacheSizeViaJava6();
}


(Note that I have lowercased the method names according to convention.) Maybe you can even combine this into one class?


Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Wed Jul 03, 2013 4:58 am
Posts: 350
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Tue Sep 10, 2013 9:22 pm 
Lee wrote:
If you're using Eclipse for Java EE, you can convert your project to faceted form and change the Java compiler compliance to Java 6. This is if you want to avoid installing multiple JDKs and JREs on your system. Just go into your project properties and on the left pane, you'll find the list item for "Project Facets". It should be straightforward from there. I hope this helps.


Thanks for the suggestion...I will give it a try.

Edit:

I checked and it seems that I am running Eclipse for Java Development and not Eclipse for Java EE Development.

I think the easiest solution would be for me to get a Java 6 JDK for the VM that I am testing my Java 6 stuff on. This way I don't need to touch my Java 7 development workstation, I can keep the Eclipse version that I have now, but still compile to 1.6 (Java 6) compatibility.

I guess the alternative would be to download Eclipse for Java EE and use that instead of my current version.

_________________
"We often compare ourselves to the U.S. and often they come out the best,
but they only have the right to bare arms, while we have the right to bare breasts"
The Right To Bare Breasts by Bowser & Blue


Last edited by Lord.Ashes on Tue Sep 10, 2013 9:47 pm, edited 2 times in total.

Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Wed Jul 03, 2013 4:58 am
Posts: 350
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Tue Sep 10, 2013 9:38 pm 
username wrote:
java.version gves you the exact version (including patch level) while java.specification.version gives you the specification the impleentation complies with. I don't know, whether OpenJDK uses a different java.version prefix. So, yes, the specification version is probably better.


Good to know.

username wrote:
With the exception you saw, Lee's suggestion is probably best. You can achieve the same thing with a javac switch that forces it to generate output for a 1.6 JVM. Note that you still need to do the checks, because the imports you rely on are available during compile time and not during runtime. But you can avoid the reflection API (and probably the try/catch). Just invoke the method directly.

Code:
// Clean up the cache
if(MapTool.JAVA_VERSION>=1.7)
{
   CacheCleanerJava7.checkCacheSizeViaJava7();
}
else
{
   CacheCleanerJava6.checkCacheSizeViaJava6();
}



Maybe I am misunderstanding but I was under the impression that as soon as you include a class that uses Java 7 in an application, the application will refuse to run on a Java 6 machine regardless if the application execution actually reaches a point that instances the class. This is what I understood from the comments in the MapTool.java source code file. This was the reason why Azhrei suggested using the Class<?> method invoking (as is used in MapTool.java for a slightly different purpose) in the first place.

username wrote:
(Note that I have lower cased the method names according to convention.) Maybe you can even combine this into one class?


Thanks...I should try more to be consistent with conventions...

_________________
"We often compare ourselves to the U.S. and often they come out the best,
but they only have the right to bare arms, while we have the right to bare breasts"
The Right To Bare Breasts by Bowser & Blue


Top
 Profile  
 
 Offline
Dragon
 
Joined: Wed Oct 19, 2011 1:07 am
Posts: 958
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Wed Sep 11, 2013 12:06 pm 
Lord.Ashes wrote:
Edit:

I checked and it seems that I am running Eclipse for Java Development and not Eclipse for Java EE Development...

...I guess the alternative would be to download Eclipse for Java EE and use that instead of my current version.


You should still try to see if your Eclipse already has this feature. I'm going with what I know from way back when I started using Eclipse. For all I know, they might have gone ahead in the interim and put the feature in all Eclipse versions for Java, not just EE.

_________________
My stuff for the community:
Donate to the Mote Project
The Mote Project's G+ community
Mote on Facebook
Fully Customizable Calendar Drop-in


Top
 Profile  
 
User avatar  Offline
Site Admin
 
Joined: Mon Jun 12, 2006 12:20 pm
Posts: 12101
Location: Tampa, FL
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Thu Sep 12, 2013 12:48 am 
Lord.Ashes wrote:
Maybe I am misunderstanding but I was under the impression that as soon as you include a class that uses Java 7 in an application, the application will refuse to run on a Java 6 machine regardless if the application execution actually reaches a point that instances the class.

Yep, you're correct. Unfortunately.

Your use of a method name that starts with a capital letter threw me off -- standard convention in Java is class names are capitalized but method names are camelback and start with a lowercase letter. :)

It looks like your code should work. When you single-step it, which line does it die on? If the JVM crashes with a core dump, there's clearly a problem inside the JVM. Likely a bug in the C implementation of the various functions.


Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Wed Jul 03, 2013 4:58 am
Posts: 350
 Post subject: Re: MapTool - Development - Java 6 vs Java 7 coding
PostPosted: Fri Sep 13, 2013 7:08 am 
Okay. I got Eclipse installed in my Ubuntu Java 6 setup along with a Java 6 JDE.

I compiled the unmodified MapTool source code no problem and was able to run it.

However, when I added the code modification I was no longer able to compile and/or run it because it contained the Java 7 code.

So I am stuck...

If I compile it in Java 7 then it won't run under a Java 6 JRE (even if I avoid the Java 7 code by checking version or using exceptions).
If I compile it using Java 6 then I can not include any Java 7 code.

I am starting to think that the easiest solution to to compile the Java 6 version with the java 6 code and the Java 7 code with the Java 7 compiler and then create a script that will use the appropriate version.

I was really starting to warm up to Java until this compatibility issue came to light. I guess if you either stick to writing all Java 6 or all Java 7 code then you don't have this issue (assuming you compile with the corresponding compiler version) but I find it difficult to believe that it isn't a more common question how to leverage some Java 7 functionality if the user has it but still be able to run it on Java 6.

_________________
"We often compare ourselves to the U.S. and often they come out the best,
but they only have the right to bare arms, while we have the right to bare breasts"
The Right To Bare Breasts by Bowser & Blue


Top
 Profile  
 
Display posts from previous:  Sort by  
Reply to topic  [ 22 posts ]  Go to page 1, 2  Next

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:

Who is online

In total there are 3 users online :: 0 registered, 0 hidden and 3 guests (based on users active over the past 5 minutes)
Most users ever online was 243 on Sun Nov 04, 2012 6:14 am

Users browsing this forum: No registered users and 3 guests





cron

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group

Style based on Andreas08 by Andreas Viklund

Style by Elizabeth Shulman