Idiom for forcing class loading?

T

Tom Anderson

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?

Before i came to it, the code looked like:

void initialise() {
Class.forName("com.example.Foo");
}

I didn't like that, because it's using a string constant where it could be
using something strongly typed, and so not getting enabling refactoring
and inspection in the IDE. I had a bit of a debate with my pair, and we
changed it to:

void initialise() {
Class.forName(Foo.class.getName());
}

Which works, solves the problem, and is clearly bonkers.

What's a good idiom? One option would be to call a no-op method on the
class literal:

void initialise() {
Foo.class.getName();
}

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? Does
anyone have any other idioms? How about any opinions on which idiom is
best, or at least most idiomatic?

Thanks,
tom
 
M

markspace

Tom said:
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?

Well, rule #1 is "if it ain't broke don't fix it", so this whole
enterprise is dubious to me.

However, I don't see why these classes won't be loaded in any of the
examples you presented. The only issue I see is that an optimizer may
decide that the objects are "not used" and optimize them away. That is,
actually remove the statements referencing the classes.

Thus you might want to actually do something with the classes:

void initialise() {
Class[] loadedClasses = new Class[] {Foo.class, Bar.class, Baz.class};

Logger logger = Logger.getLogger( "x" );
for( Class c : loadedClasses ) {
logger.config( "Loaded class: "+c.getName() );
}
}

Replace "x" with the class name in which initialise() is declared.

This may also be bonkers, but it's a safe kind of bonkers, I think.
 
T

Tom Anderson

Tom said:
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?

Well, rule #1 is "if it ain't broke don't fix it", so this whole
enterprise is dubious to me.

Son, you may wish to look into getting a new rule provider. If it ain't
broke but it's smelly, it's going to break, so fix it now before it does.
However, I don't see why these classes won't be loaded in any of the
examples you presented. The only issue I see is that an optimizer may
decide that the objects are "not used" and optimize them away. That is,
actually remove the statements referencing the classes.

Since class loading is side-effectual, i don't think an optimiser is free
to do that. Although i admit i'm a bit shaky about the rules on this.
Thus you might want to actually do something with the classes:

void initialise() {
Class[] loadedClasses = new Class[] {Foo.class, Bar.class, Baz.class};

Logger logger = Logger.getLogger( "x" );
for( Class c : loadedClasses ) {
logger.config( "Loaded class: "+c.getName() );
}
}

Replace "x" with the class name in which initialise() is declared.

This may also be bonkers, but it's a safe kind of bonkers, I think.

It at least makes it look like something useful is being done, which is
what matters!

I also considered:

void initialise() {
loadClass(Foo.class);
}

void loadClass(Class cl) {
// do nothing!
}

!

tom
 
T

Tom Anderson

Tom said:
[...]
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.

tom
 
L

Lew

Tom said:
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.
 
A

Alessio Stalla

Tom said:
[...]
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.
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
 
M

Mike Schilling

Tom said:
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.
 
A

Arne Vajhøj

Tom said:
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?

Before i came to it, the code looked like:

void initialise() {
Class.forName("com.example.Foo");
}

I didn't like that, because it's using a string constant where it could
be using something strongly typed, and so not getting enabling
refactoring and inspection in the IDE. I had a bit of a debate with my
pair, and we changed it to:

void initialise() {
Class.forName(Foo.class.getName());
}

Which works, solves the problem, and is clearly bonkers.

What's a good idiom? One option would be to call a no-op method on the
class literal:

void initialise() {
Foo.class.getName();
}

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? Does
anyone have any other idioms? How about any opinions on which idiom is
best, or at least most idiomatic?

I don't think the problem is common enough to make a solution idiomatic.

I would without thinking twice:
- read class names from config file
- use Class.forName to initialize them

Arne
 
K

Kevin McMurtrie

Tom Anderson said:
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?

Before i came to it, the code looked like:

void initialise() {
Class.forName("com.example.Foo");
}

I didn't like that, because it's using a string constant where it could be
using something strongly typed, and so not getting enabling refactoring
and inspection in the IDE. I had a bit of a debate with my pair, and we
changed it to:

void initialise() {
Class.forName(Foo.class.getName());
}

Which works, solves the problem, and is clearly bonkers.

What's a good idiom? One option would be to call a no-op method on the
class literal:

void initialise() {
Foo.class.getName();
}

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? Does
anyone have any other idioms? How about any opinions on which idiom is
best, or at least most idiomatic?

Thanks,
tom

You can access a non-optimizable static field or static method. A
constructor for an instance of the class is the safest bet.

Self-registering classes are not the best design. Under extremely rare
circumstances, references from live classes to the registration
container might not exist during a GC - then it's suddenly empty. In a
web server or other application with multiple ClassLoaders, it might not
be clear where things are going. For the work I've done, there were
enough problems to justify not using JDBC driver self-registration with
DriverManager.

Consider a configuration parameter that is a list of classes that your
registration container should load when it initializes.
 
R

Roedy Green

How about a dummy loadEarly/init static method that does nothing or
triggers static init code.
 
J

Jim Janney

Tom Anderson said:
Tom said:
[...]
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.

To me what smells here is that ManglerRegistry is using static
methods. I'd prefer creating an instance of ManglerRegistry,
registering the appropriate manglers with it, and keeping a reference
to it in the ManglingParser. This requires more coding, obviously,
but gives you more flexibility in that different parsers can use
different registries. Also, it allows registering the same mangler
more than once under different names, which can sometimes be useful.
 
T

Tom Anderson

Tom said:
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>

Aha! I had no idea this was the case! Thanks, and thanks to everyone else
who pointed it out.
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.

Quite so!

tom
 
T

Tom Anderson

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();

We have indeed done it like that in similar situations. I can't remember
why we didn't do it like that here - i think someone didn't like the idea
of having a method which 'did nothing'. I'll mention this to my colleagues
when we next pass by this bit of code.

tom
 
T

Tom Anderson

I don't think the problem is common enough to make a solution idiomatic.

It seems not.
I would without thinking twice:
- read class names from config file
- use Class.forName to initialize them

The set of classes that need loading is very much static and code-like; it
isn't the kind of thing that *needs* configuration at runtime. Given that,
is reading a file really the right thing to do? How about putting the
names in a string array?

tom
 
T

Tom Anderson

Self-registering classes are not the best design. Under extremely rare
circumstances, references from live classes to the registration
container might not exist during a GC - then it's suddenly empty. In a
web server or other application with multiple ClassLoaders, it might not
be clear where things are going. For the work I've done, there were
enough problems to justify not using JDBC driver self-registration with
DriverManager.

Consider a configuration parameter that is a list of classes that your
registration container should load when it initializes.

Sadly, the registration container is third-party, and i can't change it.

Annoyingly, the system it's in has a dependency injection framework with a
nice layering mechanism that lets modules we build add to the
configuration of components defined by others. If the container was a
component in this framework, adding classes to its to-do list would be as
simple as putting their names in a file. But it isn't!

tom
 
T

Tom Anderson

To me what smells here is that ManglerRegistry is using static methods.
I'd prefer creating an instance of ManglerRegistry, registering the
appropriate manglers with it, and keeping a reference to it in the
ManglingParser. This requires more coding, obviously, but gives you
more flexibility in that different parsers can use different registries.

You're absolutely right, of course, and if i was in charge, that's how it
would be done. Sadly, the ManglerRegistry is supplied by someone else,
their parsing code depends on it, and we need their parsing code. All very
annoying.

tom
 
L

Little Green Man

You're absolutely right, of course, and if i was in charge, that's how it
would be done. Sadly, the ManglerRegistry is supplied by someone else,
their parsing code depends on it, and we need their parsing code. All very
annoying.

Consider shopping around for an alternative that does the same job.
Preferably open source.
 
J

Jim Janney

Tom Anderson said:
You're absolutely right, of course, and if i was in charge, that's how
it would be done. Sadly, the ManglerRegistry is supplied by someone
else, their parsing code depends on it, and we need their parsing
code. All very annoying.

Ah. In that case, I'd probably just get rid of the static blocks and
do the registration directly in your initializer: that is, change

void initialise() {
Class.forName(Foo.class.getName());
}

to

void initialise() {
ManglerRegistry.register("foo", FooMangler.class);
}


Since you have to reference each class in the initializer anyway, it
doesn't look as if the static blocks are buying you anything.
 
L

Lew

Jim said:
Ah.  In that case, I'd probably just get rid of the static blocks and
do the registration directly in your initializer: that is, change

void initialise() {
        Class.forName(Foo.class.getName());

}

to

void initialise() {
        ManglerRegistry.register("foo", FooMangler.class);

Did you mean'Foo.class'?
}

Since you have to reference each class in the initializer anyway, it
doesn't look as if the static blocks are buying you anything.

As pointed out upthread a couple of times, merely referencing the
'class' literal will not initialize the 'FooMangler' class. Since
tom's goal is to initialize the classes that are being registered,
your suggestion will not work unless the 'ManglerRegistry.register()'
call invokes a method in 'FooMangler' or does one of the other things
that initializes the class, some of which have been suggested in this
conversation already.
 
D

Dangling Pointer

Did you mean'Foo.class'?



As pointed out upthread a couple of times, merely referencing the
'class' literal will not initialize the 'FooMangler' class. Since
tom's goal is to initialize the classes that are being registered

The goal was to register the classes. Tom wanted to initialize the
classes because doing so would make them self-register, but if they
can be registered directly, so much the better (as long as
registration is idempotent, so subsequent initialization of the
classes doesn't cause some sort of problems via "double
registration").

Of course, this depends on the apparently-closed-source API he's using
exposing a manual registration method, as well as on idempotency of
registration.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top