views:

482

answers:

3

I've been given no other choice but to access a set of classes, which I cannot modify, with this structure through reflection. Using the method shown in the main method below however, throws a NullPointerException. The null pointer being "table" in the constructor when f1.get(null) is called.

I am unable to instantiate the classes beforehand because the only constructor is the one shown, which is private. So there is no way for me to explicitly set table either.

Anyone know of a way for me to reflectively call Legacy.A?

public class Legacy { 
 public static final Legacy A = new Legacy("A");
 public static final Legacy B = new Legacy("B");

 private String type0;
 private static Map<String, Legacy> table = new HashMap<String, Legacy>();

 private Legacy(String id) {
  type0 = id;
  table.put(type0, this);
 }

    public static void main(String[] args) throws Exception {
  Field f1 = Legacy.class.getDeclaredField("A");
  Object o = f1.get(null); 
 }
}

In before "Reflection == BAD!!!"

+6  A: 

The order of the static initializers is wrong, table must come before the constructor calls.

This is the reason that you get the exception when the class is loaded and initialized. This has nothing to do with reflection.

starblue
A: 

I tried this, because I couldn't see what was wrong with your example. It worked if I reordered the declarations:

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class Legacy {
    private String type0;
    private static Map< String, Legacy > table = new HashMap< String, Legacy >();

    private Legacy( String id ) {
     type0 = id;
     table.put( type0, this );
    }
    public static final Legacy A = new Legacy( "A" );
    public static final Legacy B = new Legacy( "B" );

    public static void main( String[] args ) throws Exception {
     Field f1 = Legacy.class.getDeclaredField( "A" );
     Object o = f1.get( null );
    }
}

The static declarations need the (preceding) constructor.

Steve B.
+1  A: 

Since this is confusing, I would write it like this:

public class Legacy {   
        static {
          table = new HashMap<String, Legacy>();
          A = new Legacy("A");
          B = new Legacy("B");
        }

        public static final Legacy A;
        public static final Legacy B;

        private String type0;
        private static Map<String, Legacy> table;

        private Legacy(String id) {
                type0 = id;
                table.put(type0, this);
        }

    public static void main(String[] args) throws Exception {
                Field f1 = Legacy.class.getDeclaredField("A");
                Object o = f1.get(null);        
        }
}

This way, even if the members change location (due to refactoring, line alignment or whatever) the code will always work.

Aviad Ben Dov