From: Lew on
Tom Anderson wrote:
> We have a class which does some setup in a static block that needs to
> happen early in the lifecycle of the app (this is a dubious design, but
> there you go - it's largely forced on us from without). Thus, it needs to
> get loaded early. We have an initialiser class which runs at a suitable
> time, so that's where we'll load the class. What's the best way to do
> this?
....
> I could just store it in a local:
>
> void initialise() {
>         Class foo = Foo.class;
> }
>
> Since i [sic] actually have several classes, i [sic] could put them in an array:
>
> void initialise() {
>         Class[] loadedClasses = new Class[] {Foo.class, Bar.class, Baz.class};
>
> }
>
> Am i [sic] right in thinking that all of these will force loading of Foo?
>

Yes, but not initialization. If all you need is loading, you're fine,
but if you need initialization, you're not..

Mere reference to the 'class' literal is forbidden to initialize the
class. JLS 12.4.1
<http://java.sun.com/docs/books/jls/third_edition/html/
execution.html#12.4.1>

This restriction is enforced in Sun JVMs starting with Java 5.

'Class.forName( String )' is documented to cause initialization but
'Class#getName()' is not so documented.
<http://java.sun.com/javase/6/docs/api/java/lang/Class.html#forName
(java.lang.String)>
<http://java.sun.com/javase/6/docs/api/java/lang/Class.html#getName()>

It may be, however, that the latter is one of the "certain reflective
methods in class Class" to which the JLS refers, but without explicit
documentation of such it's a fragile promise/premise.

--
Lew
From: Thomas Pornin on
According to Tom Anderson <twic(a)urchin.earth.li>:
> But that's a bit hackish too. I could just store it in a local:
>
> void initialise() {
> Class foo = Foo.class;
> }
>
> Since i actually have several classes, i could put them in an array:
>
> void initialise() {
> Class[] loadedClasses = new Class[] {Foo.class, Bar.class, Baz.class};
> }
>
> Am i right in thinking that all of these will force loading of Foo?

You are right in that the class Foo will be _loaded_, but that is not
what you want. You want the class to be loaded _and_ initialized, and
here the Foo class is not initialized.

Class initialization occurs upon first "access": read or write to a
static field (not counting the pre-initialized final fields of a
'primitive enough' type to be inlined in the caller), call to a static
method, or creation of an instance. Note that creating an array of Foo
is not sufficient to get the Foo class initialized.

The standard JDK does not feature any direct method for initializing a
class; the least indirect one is Class.forName() (there are two
versions, one of which accepts a boolean which lets you find a class by
name without initializing it, the exact opposite of what you are looking
for).


--Thomas Pornin
From: Thomas Pornin on
According to Lew <lew(a)lewscanon.com>:
> <http://java.sun.com/javase/6/docs/api/java/lang/Class.html#getName()>
>
> It may be, however, that the latter is one of the "certain reflective
> methods in class Class" to which the JLS refers, but without explicit
> documentation of such it's a fragile promise/premise.

Actually, calling Class.getName() on Sun's JDK 6 is not sufficient to
get the class initialized (try it !).


--Thomas Pornin
From: Alessio Stalla on
On 18 Nov, 20:06, Tom Anderson <t...(a)urchin.earth.li> wrote:
> On Wed, 18 Nov 2009, Peter Duniho wrote:
> > Tom Anderson wrote:
> >> [...]
> >> Am i right in thinking that all of these will force loading of Foo?
>
> > I think so.  But I haven't checked the spec to make sure.
>
> >> Does anyone have any other idioms? How about any opinions on which idiom is
> >> best, or at least most idiomatic?
>
> > I find the question ironic.  :)  The fact is, you've got some clearly
> > non-idiomatic scenario, where for some reason your code has managed to become
> > dependent on the initialization of a class that it does not in fact refer to
> > in the process of being dependent on it.
>
> > Given that violation of a very fundamental assumption one normally could make
> > in a Java program, asking for an idiomatic solution to the violation seems
> > sort of silly to me.  Your code is already broken; any work-around is
> > destined to be non-idiomatic.  :)
>
> What's really happening is more like this:
>
> class FooMangler implements Mangler {
>         static {
>                 ManglerRegistry.register("foo", FooMangler.class);
>         }
>
> }
>
> class ManglingParser extends org.xml.sax.helpers.DefaultHandler {
>         public void startElement (String uri, String localName, String qName, Attributes attrs) throws SAXException {
>                 String manglerName = attrs.getValue("mangler");
>                 Mangler mangler = ManglerRegistry.lookup(manglerName);
>                 mangler.mangle(qName, attrs);
>         }
>
> }
>
> The idea is that manglers can take care of registering themselves - as
> long as they're loaded. This is an old and fairly well-known pattern (at
> least, not wildly obscure - in terms of birds, about as common as a
> kingfisher is in England), although i certainly wouldn't say it's a good
> one, or even a non-dubious one. 'Broken' is a bit too strong, although
> only a bit.

If you have control on the source code of the mangler, I would do like
this:

class FooMangler implements Mangler {
public static void autoregister() {}
...
}

and to initialize it, FooMangler.autoregister();

else, Class.forName(FooMangler.class.getName()) is the safest bet: it
always initializes the class and fails at compile time if FooMangler
is ever renamed (provided that the file containing the Class.forName
is recompiled!).

Alessio
From: Mike Schilling on
Tom Anderson wrote:
> Hi chaps,
>
> We have a class which does some setup in a static block that needs
> to
> happen early in the lifecycle of the app (this is a dubious design,
> but there you go - it's largely forced on us from without). Thus, it
> needs to get loaded early. We have an initialiser class which runs
> at
> a suitable time, so that's where we'll load the class. What's the
> best way to do this?

Add a static method to the class, called e.g. initialize(), and call
it.