问题
I have a compiled executable JAR file that fails on Windows platforms.
The reason for this is because I want to properly integrate certain OS X-specific properties — such as the About window.
Even though I specifically cordoned off the code using a conditional, the JAR is still crashing with a NoClassDefFoundError
on the very first line of execution.
if (isOSX()) {
com.apple.eawt.Application application = com.apple.eawt.Application.getApplication();
application.setAboutHandler(new com.apple.eawt.AboutHandler() {
@Override
public void handleAbout(com.apple.eawt.AppEvent.AboutEvent ae) {
new AboutWindow();
}
});
application.setDefaultMenuBar(MenuSystem.createMenu());
}
Is it possible to include this code in my JAR file so I can have one consistent codebase?
回答1:
Have you tried loading the surrounding class dynamically using Class.forName ?
Class.forName("com.myproject.ClassContainingApple");
This way you can refer to all your Apple-specific classes inside one class, and dynamically load it in your isOSX()
branch. You have to do it this way since you're not able to load a class that refers to other unavailable classes - you'll have to determine if you're in OSX, and only then load up anything referring to OSX-only classes.
An extensible way to do this if you have more OS-specific requirements is to name your class after the OS and then load a classname based upon the detected OS. e.g. call your classes WindowsExtensions
, OSXExtensions
, LinuxExtensions
etc. (you will have to look up the appropriate names - I'm just providing examples)
e.g. here's an example of usage:
String className = ""java.util.ArrayList";
Class cls = Class.forName(className);
List list = (List)cls.newInstance();
回答2:
Using Brian's answer as a base, I was able to use the following code to set the Mac dock icon image using OS X specific methods. Unlike the other answer, this answer includes a complete example and does not have the problem of trying to cast the object to a OS X specific class object.
What the code does:
- Instead of importing the OS X specific library, this code uses Class.forName(String) to get the
Class
object associated with the OS X specific class. In this example, thecom.apple.eawt.Application
library is used to set the dock icon image. - Reflection is then used to invoke the methods from the OS X specific class.
getClass()
is used to get the Application object, andgetMethod().invoke()
is used to call thegetApplication()
andsetDockIconImage()
methods.
I've included comments showing the code that would be normally used in a OS X exclusive program, to make it clear what the reflection code is replacing. (If you are creating a program that only needs to run on Mac, see How do you change the Dock Icon of a Java program? for the code needed to set the dock icon image.)
// Retrieve the Image object from the locally stored image file
// "frame" is the name of my JFrame variable, and "filename" is the name of the image file
Image image = Toolkit.getDefaultToolkit().getImage(frame.getClass().getResource(fileName));
try {
// Replace: import com.apple.eawt.Application
String className = "com.apple.eawt.Application";
Class<?> cls = Class.forName(className);
// Replace: Application application = Application.getApplication();
Object application = cls.newInstance().getClass().getMethod("getApplication")
.invoke(null);
// Replace: application.setDockIconImage(image);
application.getClass().getMethod("setDockIconImage", java.awt.Image.class)
.invoke(application, image);
}
catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException
| InstantiationException e) {
e.printStackTrace();
}
Although this code works, this method still seems to be a messy workaround, and it would be great if anyone has any other suggestions on how to include OS X specific code in a program used on Mac and Windows.
回答3:
This is not possible the way you do it because java is loading all classes that a class (may) use during the instantiation of the class, so the named class is not available.
You could try to put the code in another class in your project and instantiate this class only if your are running on OSX.
If this does not work either you have to use reflection because then the VM only can detect this class when you load it via reflection.
HTH
来源:https://stackoverflow.com/questions/13400926/how-can-i-call-an-os-x-specific-method-for-my-cross-platform-jar