Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java/Scala reflection: Get class methods in order and force object init

I have a class with a few objects as inner methods.

I also asked this question a while ago and got a good answer, but that leads to fatal errors in servlet containers. Scala cannot consistently generate a TypeTag when the URLClassLoader asks for a class.

The project in question is open-source, found here.

The current approach is found here, but it doesn't preserve order. object members are correctly initialised, but in a random order.

Question: How can you collect class members:

  • in the order they are defined
  • in a thread-safe way
  • filter them by a super type
  • and greedy initliase the objects(referencing module.instance) ?

Update:

  • Don't suggest answers based on the links here, they've been tested and known to fail.
  • Using a val instead of object is not an option, for stylistic reasons.
  • getMethods or getDeclaredFields is known not to guarantee order. If this is somehow possible, it's likely with Scala reflection.
like image 1000
flavian Avatar asked Mar 14 '14 13:03

flavian


1 Answers

From http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getDeclaredFields():

public Field[] getDeclaredFields() throws SecurityException

Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields. The elements in the array returned are not sorted and are not in any particular order. This method returns an array of length 0 if the class or interface declares no fields, or if this Class object represents a primitive type, an array class, or void. See The Java Language Specification, sections 8.2 and 8.3.

(my emphasis). Similar language is explicitly in the documentation for getDeclaredMethods(), but not in that for getDeclaredClasses() (but can IMO be considered implicit there).

So no, you cannot rely on ordering from Java reflection on the JVM; in practice, I have seen the order vary based on the architecture of the running JVM (32- vs. 64-bit).

If you really must initialize the objects in a particular order (why?), you could use a naming convention and sort manually; however, it would probably be better to change the code to be order-independent.

Update

It appears that you may be able to get something from the Scala reflection API:

trait EarlyInit {
  val mirror = runtimeMirror(this.getClass.getClassLoader)
  val reflection  = mirror.reflect(this)

  mirror
    .classSymbol(this.getClass)
    .toType
    .members
    .sorted    /// This method is documented to return members "in declaration order"
    .filter(_.isModule)
    .foreach(m => reflection.reflectModule(m.asModule).instance)
  }
}

See the API docs:

Sorts the symbols included in this scope so that: 1) Symbols appear in the linearization order of their owners. 2) Symbols with the same owner appear in same order of their declarations. 3) Synthetic members (e.g. getters/setters for vals/vars) might appear in arbitrary order.

However, this will not be guaranteed to work in general, particularly for mixed Java/Scala projects (since there really is no way to get members of a Java class in declaration order). Also, be aware that Scala runtime reflection is not thread-safe and generally not considered production ready.

I still feel that you would be better served by modifying your design to be order independent, possibly by encoding the dependencies differently.

like image 128
espenhw Avatar answered Oct 05 '22 19:10

espenhw