Issue
I have made a platform independent library that I want to use on a J2SE and Android project. Within this library I have a Version
class that loads its version details from the manifest. On PC this works well, on Android I'm getting a NullPointerException
and I can't figure out why.
This is my class:
public class Version {
private static int APPCODE = 12354;
private static int MAJOR;
private static int MINOR;
private static char RELEASE;
private static int BUILD;
private static int PROTOCOL;
static {
try {
Class clazz = Version.class;
String className = clazz.getSimpleName() + ".class";
String classPath = clazz.getResource(className).toString(); //NullPointerException
if (classPath.startsWith("jar")) {
String manifestPath = classPath.substring(0,
classPath.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF";
Manifest manifest = new Manifest(new URL(manifestPath).openStream());
Attributes attr = manifest.getMainAttributes();
//APPCODE = Integer.parseInt(attr.getValue("APPCODE"));
MAJOR = Integer.parseInt(attr.getValue("MAJOR"));
MINOR = Integer.parseInt(attr.getValue("MINOR"));
RELEASE = attr.getValue("RELEASE").charAt(0);
BUILD = Integer.parseInt(attr.getValue("BUILD"));
PROTOCOL = Integer.parseInt(attr.getValue("PROTOCOL"));
} else {
System.err.println("Couldn't find manifest, reverting to test mode");
MAJOR = 0;
MINOR = 0;
RELEASE = 'n';
BUILD = 0;
//APPCODE = 12354;
}
} catch (IOException e) {
System.err.println("Failed to load manifest file. " + e);
MAJOR = 0;
MINOR = 0;
RELEASE = '0';
BUILD = 0;
//APPCODE = 12354;
PROTOCOL = 0;
} catch (NumberFormatException e) {
System.err.println("Failed to load manifest file. " + e);
MAJOR = 0;
MINOR = 0;
RELEASE = '0';
BUILD = 0;
//APPCODE = 12354;
PROTOCOL = 0;
}
}
public static int getProtocol() {
return PROTOCOL;
}
public static int getAppCode() {
return APPCODE;
}
public static int getBuildNumber() {
return BUILD;
}
public static int getMajor() {
return MAJOR;
}
public static int getMinor() {
return MINOR;
}
public static char getRelease() {
return RELEASE;
}
}
(Please excuse the System.err.println()
lines, those are for debugging on PC).
Why would this work fine on PC but not on Android?
Full stack trace:
03-12 22:13:11.687: E/AndroidRuntime(11780): FATAL EXCEPTION: main
03-12 22:13:11.687: E/AndroidRuntime(11780): java.lang.ExceptionInInitializerError
03-12 22:13:11.687: E/AndroidRuntime(11780): at com.logandam.wififileshare.android.MainActivity.onCreate(MainActivity.java:24)
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.Activity.performCreate(Activity.java:4465)
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1052)
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1932)
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1993)
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread.access$600(ActivityThread.java:127)
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1159)
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.os.Handler.dispatchMessage(Handler.java:99)
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.os.Looper.loop(Looper.java:137)
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread.main(ActivityThread.java:4507)
03-12 22:13:11.687: E/AndroidRuntime(11780): at java.lang.reflect.Method.invokeNative(Native Method)
03-12 22:13:11.687: E/AndroidRuntime(11780): at java.lang.reflect.Method.invoke(Method.java:511)
03-12 22:13:11.687: E/AndroidRuntime(11780): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
03-12 22:13:11.687: E/AndroidRuntime(11780): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
03-12 22:13:11.687: E/AndroidRuntime(11780): at dalvik.system.NativeStart.main(Native Method)
03-12 22:13:11.687: E/AndroidRuntime(11780): Caused by: java.lang.NullPointerException
03-12 22:13:11.687: E/AndroidRuntime(11780): at com.logandam.wififileshare.net.Version.<clinit>(Version.java:30)
03-12 22:13:11.687: E/AndroidRuntime(11780): ... 15 more
Update: className
= Version.class
on both PC and Android. Using getName()
instead of getSimpleName()
breaks on PC and still doesn't work on Android.
Solution
I am not 100% sure but I don't think that this mechanism works under Android as it does in a real JVM (since dalvik is essentially not a JVM). I think (and I might be wrong here), that in the packaged APK, the JAR does no longer exist and therefore your path to the resource probably is wrong. The classes of your JAR are converted to the dex file format and added to the classes.dex
file. Therefore you cannot resolve a resource like foo.bar.class
because it does not exist in the classpath.
Try to put the Version information into a text (or other resource) file and add it into the JAR and read that. The resource file should be added properly and you should be able to read it with the mechanism.
Answered By - Stephan
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.