Initializing public static final variables in a constructor

I am trying to create a class Version

for my application that will read the version numbers from the manifest at boot time and then simply reference, for example, Version.MAJOR

and such wherever I need it elsewhere. However, I am having problems with this. Here is 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 variables static final

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

Reading this question gave me some idea of ​​not using public static final

. Should I use public static

with getter methods?

+3


source to share


4 answers


I would:



  • remove recent modifiers
  • reduce visibility from public to private.
  • provide (static) getters for required fields
+3


source


If you make sure you always assign to fields final

exactly once, the compiler is 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;
    }
}

      

+6


source


If you are using fields public final

, you need to assign default values ​​as they are constants. Change visibility to private and remove the final modifier and provide getters / setters. This should be the best way to solve your problem.

0


source


you can remove the block of code associated with showing the manifest from the Version class and put it in a separate class - for example (ManifestReader) - and initialize the version instances directly with the actual values ​​in the constructor.

I would change "public static final" to "private final" (not static) because if you have more than one instance of the version class, everyone should have their own appcode, major minor, etc.

next to getter () for accessing private final fields!

0


source







All Articles