Question

I'm trying to make a Version class for my app that will read version numbers from the manifest at load time and then just reference for example Version.MAJOR and such wherever I need it elsewhere. However, I'm having issues doing so. Here's my current code:

 public class Version {

    public static final int APPCODE;
    public static final int MAJOR;
    public static final int MINOR;
    public static final char RELEASE;
    public static final int BUILD;

    static {

        try {
            Class clazz = Version.class;
            String className = clazz.getSimpleName() + ".class";
            String classPath = clazz.getResource(className).toString();
            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"));
            }
        } catch (IOException e) {
            System.exit(9001);
        }
    }
}

It won't compile, because the static final variables might not be initialized (for example if the wrong manifest is loaded or there's an exception loading it) and I can't figure out what the correct procedure to do this is.

Reading this question has given me some insight to not use public static final. Should I rather be using public static with getter methods?

Was it helpful?

Solution 2

I would:

  • remove the final modifiers
  • reduce the visibility from public to private.
  • provide (static) getters for the needed fields

OTHER TIPS

If you make sure that you always assign to the final fields exactly once, the compiler will be happy:

public class Version {

    public static final int APPCODE;
    public static final int MAJOR;
    public static final int MINOR;
    public static final char RELEASE;
    public static final int BUILD;

    static {
        int appcode = 0;
        int major = 0;
        int minor = 0;
        char release = 0;
        int build = 0;
        try {
            Class clazz = Version.class;
            String className = clazz.getSimpleName() + ".class";
            String classPath = clazz.getResource(className).toString();
            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"));
            }
        } catch (IOException e) {
            System.exit(9001);
        }
        APPCODE = appcode;
        MAJOR = major;
        MINOR = minor;
        RELEASE = release;
        BUILD = build;
    }
}

If you are using public final fields you have to assign default values because those are constants. Change the visibility to private and remove the final modifier and provide getters/setters. This should be the best way to solve your problem.

you can remove block of code dealing with reading manifest from Version class and put it into a separate class - for instance (ManifestReader) - and initialize version instances directly with actual values in constructor.

i would change the "public static final" to "private final" (not static) because if you have more than one instance of Version class all must have their own appcode, major minor etc !!

beside provide getter() to access private final fields!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top