bigdestroyer bigdestroyer - 5 months ago 21
Java Question

Illegal forward reference in enum

I have an enum and I'm trying to pass a final static variable as parameter in constructor. Problem is that first statement in enums has to be a instance itself, but in that case, final variable is not defined yet. See the code and you will understand:

public enum ParseResource {

PUSH(API_URL); //Error: illegal forward reference

private final static String API_URL = "https://api.parse.com/1";

private String url;
private ParseResource(String url) {
this.url = url;
}
}


and the other option:

public enum ParseResource {

//Illegal in enums, first statement has to be an instance
private final static String API_URL = "https://api.parse.com/1";

PUSH(API_URL);

private ParseResource(String url) {
this.url = url;
}
}


How can I solve it? Thanks.

Answer

There are four possible solutions that I know of:

  1. Most robust to minor differences in the code, like if we e.g. had to initialize API_URL via a method call:

    public enum ParseResource {
        PUSH(Constants.API_URL);
    
        private static class Constants {
            private final static String API_URL =
                "https://api.parse.com/1";
        }
    
        private String url;
        private ParseResource(String url) { this.url = url; }
    }
    
  2. This works because API_URL is a constant variable (initialized with a String literal) and we access it with a qualified name which avoids the forward reference error:

    public enum ParseResource {
        PUSH(ParseResource.API_URL);
    
        private final static String API_URL = "https://api.parse.com/1";
    
        private String url;
        private ParseResource(String url) { this.url = url; }
    }
    

    This behavior is specified by 8.3.2: "Note that static fields that are constant variables are initialized before other static fields. [...] Such fields will never be observed to have their default initial values [...].".

    (In other scenarios where API_URL was not a constant variable, avoiding the forward reference error by using a qualified name could create a problem.)

  3. Maybe convoluted, but interesting I guess:

    public enum ParseResource {
        PUSH("https://api.parse.com/1");
    
        private final static String API_URL = PUSH.url;
    
        private String url;
        private ParseResource(String url) { this.url = url; }
    }
    
  4. This is bad and nobody should use it, because getApiUrl() will return null if API_URL is not a constant variable (i.e. it's not final and/or not initialized with a String literal):

    public enum ParseResource {
        PUSH(getApiUrl());
    
        private final static String API_URL = "https://api.parse.com/1";
        private static String getApiUrl() { return API_URL; }
    
        private String url;
        private ParseResource(String url) { this.url = url; }
    }