Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class.getResource(className) giving me NullPointerException

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.

like image 666
ldam Avatar asked Mar 12 '13 20:03

ldam


2 Answers

You are getting NullPointerException because the method call clazz.getResource(className) is returning null which means the resource specified by className cannot be found.
Put your resource file in a folder and set it as resource folder. Check this answer on SO for more information.
You can also check this SO answer for detials about recource folders.

like image 75
Mohammad Banisaeid Avatar answered Oct 02 '22 00:10

Mohammad Banisaeid


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.

like image 27
Stephan Avatar answered Oct 02 '22 02:10

Stephan