views:

165

answers:

3

Is it possible to get the class type from inside the static initialization block?

This is a simplified version of what I currently have::

class Person extends SuperClass {

   String firstName;

   static{
      // This function is on the "SuperClass":
      //  I'd for this function to be able to get "Person.class" without me
      //  having to explicitly type it in but "this.class" does not work in 
      //  a static context.
      doSomeReflectionStuff(Person.class);     // IN "SuperClass"
   }
}

This is closer to what I am doing, which is to initialize a data structure that holds information about the object and its annotations, etc... Perhaps I am using the wrong pattern?

public abstract SuperClass{
   static void doSomeReflectionStuff( Class<?> classType, List<FieldData> fieldDataList ){
      Field[] fields = classType.getDeclaredFields();
      for( Field field : fields ){
         // Initialize fieldDataList
      }
   }
}

public abstract class Person {

   @SomeAnnotation
   String firstName;

   // Holds information on each of the fields, I used a Map<String, FieldData>
   //  in my actual implementation to map strings to the field information, but that
   //  seemed a little wordy for this example
   static List<FieldData> fieldDataList = new List<FieldData>();

   static{
      // Again, it seems dangerous to have to type in the "Person.class"
      //   (or Address.class, PhoneNumber.class, etc...) every time.
      //   Ideally, I'd liken to eliminate all this code from the Sub class
      //   since now I have to copy and paste it into each Sub class.
      doSomeReflectionStuff(Person.class, fieldDataList);
   }
}

Edit

I picked the accepted answer based on what applied best to my problem, however it seems to me that all three of the current answers have their merits.

+1  A: 

yes, I use this often to initialize a static Log variable :

e.g. :

public class Project implements Serializable, Cloneable, Comparable<Project> {
    private static final Logger LOG = LoggerFactory.getLogger(Project.class);
    ...
Peter Tillemans
+1  A: 

To get a class at runtime, you could do something along the lines of

public class Test {
public static void main(String[] args) {
    try{
        throw new Exception();
    }
    catch(Exception e){
        StackTraceElement[] sTrace = e.getStackTrace();
        // sTrace[0] will be always there
        String className = sTrace[0].getClassName();
        System.out.println(className);

    }
}

}

Not pretty but will do the job (ripped from http://www.artima.com/forums/flat.jsp?forum=1&amp;thread=155230).

This means you still make a call from the subclass (so is in the stack trace), but you don't need to include the XXX.class as an argument.

DaveC
+1  A: 

No, it's not possible without grabbing the stacktrace (which is imo nastier than your initial approach and for which I would in any way prefer Thread#getStackTrace() above new Exception()).

Rather do that job in a non-static initializer (or the default constructor) of the abstract class where you check the initialized status.

public abstract class SuperClass {

    {
        if (!isInitialized(getClass())) {
            initialize(getClass());
        }
    }

}

The called methods in turn can be safely static.

BalusC
Thanks for your answer, thats definitely a lot cleaner than what I have. What would you say to the efficiency argument that "isInitialized(getClass())" would be called every time an instance of the object is created?
DutrowLLC
It's at least cheaper than initializing it again and again everytime. If you store it as a `HashMap` key and use `fieldDataMap.containsKey(getClass())`, then the cost is very little.
BalusC