1
public static Properties prop;

private static UnionAuthProperties unionAuthProperties;

private UnionAuthProperties() {
    try {
        prop = PropertiesUtil.getPropertiesFromClassPath("unionauth.properties");
    } catch (Exception e) {
        LOG.error("{}",e);
    }
}

public static synchronized UnionAuthProperties getInstance() {
    if (unionAuthProperties == null) {
        unionAuthProperties = new UnionAuthProperties();  #27
    }
    return unionAuthProperties;
}

private final String URL_REQUEST = prop.getProperty("url.request");   #32

The last statement URL_REQUEST causes:

threw exception
java.lang.NullPointerException
    at UnionAuthProperties.<init>(UnionAuthProperties.java:32)
    at UnionAuthProperties.getInstance(UnionAuthProperties.java:27)
    at UnionAuthClient.<init>(UnionAuthClient.java:9)

based on my knowledge, instance no matter final or not are initiated after constructor [1] while the final ones have to be assigned before the end of constructor [2]. So why prop is NULL when URL_REQUEST is initialized?

EDIT: If right after super() and this(...) complete, instances are initialized, then the final instance REDIRECT_URI should be initialized to null or blank. However this prints REDIRECT_URI as REDIRECT_URI:

public class Test {
        private static Properties prop;

        public static void main(String[] args) {
            Test a = new Test();
        }

        public Test() {
            // The following code should run after private final String REDIRECT_URI;
            try {
                System.out.println();
            } catch (Exception e) {}
            REDIRECT_URI = "REDIRECT_URI";
            System.out.println(REDIRECT_URI);
        }

        private final String REDIRECT_URI;
    }

And I also tried to change the constructor like this:

private UnionAuthProperties() {
     prop = new Properties();
}

still NPE.

Community
  • 1
  • 1
Tiina
  • 4,285
  • 7
  • 44
  • 73

1 Answers1

1

http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5

Items 1-3 specify calling explicit or implicit variations of super() and this()

Item 4 says execute instance variable initializers from top to bottom. That means all fields final and non-final that are not inside the constructor, just fields of the new instance are initialized now.

Item 5 says execute rest of the body of this constructor, where rest in your case starts with try { prop = .... Rest means "without super() or this()"

Hence prop.getProperty("url.request") is executed before prop is initialized in rest of the body of constructor.

I would move prop initialization to getInstance() function.

Here's the order in which your code executes (initializations and constructor code)

// 1. when class is loaded (because it is `static`) effectively same as public static Properties prop = null;
public static Properties prop; 

// 2. when class is loaded; effectively same as unionAuthProperties = null
private static UnionAuthProperties unionAuthProperties;

private UnionAuthProperties() {
    try {
        // 5. executing constructor code
        prop =     PropertiesUtil.getPropertiesFromClassPath("unionauth.properties");
    } catch (Exception e) {
        LOG.error("{}",e);
    }
}

public static synchronized UnionAuthProperties getInstance() {
    if (unionAuthProperties == null) {
        // 3. creating new instance (first only constructor called, assignment is later)
        unionAuthProperties = new UnionAuthProperties();  #27
    }
    return unionAuthProperties;
}

// 4. `execute instance variable initializers` in top to bottom order
// prop is null yet
private final String URL_REQUEST = prop.getProperty("url.request");
Mikhail Boyarsky
  • 2,908
  • 3
  • 22
  • 37
  • I believe the deal is with `static` fields initialization order. This is a part of Class initialization procedure. http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4.2 I updated my answer with order of execution of your code. – Mikhail Boyarsky Jan 07 '17 at 14:35
  • Why prop = PropertiesUtil...... is at the 5th aka "the rest of the body of the constructor"? I understand static means belonging to class(loaded together with JVM), while not-static means belonging to object (which needs to be instantiated first, i.e., at runtime after constructor finished). – Tiina Jan 09 '17 at 00:47
  • @Tiina because according to Java specification chapter 12.5 instance variables (non-static members of class) are initalized before executing actual constructor code. – Mikhail Boyarsky Jan 09 '17 at 14:22
  • ok then instance initialized between this(), super() and other parts. – Tiina Jan 12 '17 at 07:43