Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (491)
Games in Android Showcase (112)
games submitted by our members
Games in WIP (556)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Linkage and class name resolution  (Read 1991 times)
0 Members and 1 Guest are viewing this topic.
Offline dishmoth
« Posted 2006-11-08 15:21:16 »

Short version:  Can I omit a class from a JAR file (knowing that that class is never actually used) without the JVM throwing a NoClassDefFoundError exception?

Longer version:  My game includes within it a couple of mini-games that I've set up so that they can be played as stand-alone games.  Now, the JAR file for the full game is quite big, so I'm thinking that for the stand-alone mini-games I should be able to put them in much smaller JAR files by omitting the unused classes.  Trouble is, I can't simply omit classes from the JAR (classes that are mentioned, but that I know are never actually used) because the JVM still tries to load them.

A bit of reading up (http://java.sun.com/docs/books/jls/third_edition/html/execution.html) tells me that when the JVM loads a new class, it is optional whether or not it resolves all of the other class names mentioned by the loaded class, and how deep it goes in recursing this.  In principle, a JVM could complete the recursion and load up every class mentioned in the JAR as soon as it is launched ("static resolution").

So, my question is whether it's possible to tell the JVM not to load a class (and, specifically, not to throw a NoClassDefFoundError if the class cannot be loaded) until that class is explicitly used. 

(I had thought it was possible to do this by calling the Class.forName("MyClass") method, and catching the exception at that point, but that doesn't seem to stop the JVM still trying to load the class at a later time.)

Does this make sense to anyone, or am I talking complete gibberish?  Smiley

Thanks for any suggestions!
Simon

Offline Kova

Senior Member





« Reply #1 - Posted 2006-11-08 15:51:44 »

I don't really understand VM anything better then you do, but if VM tries to load them that means some of your other classes are using (or just importing) them ? I can't see how they could be loaded if they aren't used.
Offline dishmoth
« Reply #2 - Posted 2006-11-08 16:27:00 »

I don't really understand VM anything better then you do, but if VM tries to load them that means some of your other classes are using (or just importing) them ? I can't see how they could be loaded if they aren't used.

Mini example:

1  
2  
3  
4  
5  
if ( game == SpaceInvaders ) {
  return new Invader();
else if ( game == Pacman ) {
  return new Ghost();
}


If you're playing Space Invaders, you never need to instantiate a Ghost object.  So an Invaders-only version of the JAR file could omit the Ghost class altogether, right?

Sadly not, because the JVM can look at the above code as soon as the game is launched and decide it needs to load both the Invader class and the Ghost class immediately.  No Ghost class means NoClassDefFoundError.

So I'm looking for a way to tell the JVM not to complain about the missing Ghost class until it tries to execute the code that instantiates that class (which, if we're playing Space Invaders, should never happen).

Bit of an odd example (it screams out "factory pattern"!) but hopefully a bit clearer than before.
Simon

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline c_lilian

Senior Member


Projects: 1


Java games will probably rock someday...


« Reply #3 - Posted 2006-11-08 17:11:51 »

Basically, you'd have create an interface for the mini game and when needed instanciate it with reflection.

MiniGame g = (MiniGame) Class.forName("package.MiniGameImpl");

like that your only prerequisite for the jar is the interface, hopefully much lighter than the full class and linked subclasses.

Lilian Smiley


Offline Kova

Senior Member





« Reply #4 - Posted 2006-11-08 18:17:09 »

So Simon, you won't / can't edit your source and just remove code that uses other classes? I can't really complain about JVM behaving that way becouse if it wouldn't there would be much more problems then comfort in cases like this.
My next try would be to create empty classes with same name and replace the originals so JVM would not complain about not having them around.

EDIT:
about your example... are you sure it is that way? How about really creating one and test it, becouse in my game I use mysql jdbc driver to connect to database. If don't include mysql jar file my game starts fine, and only complains about missing class file when I actually run part of game that communicates with database.

java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

at java.net.URLClassLoader$1.run(Unknown Source)
   at java.security.AccessController.doPrivileged(Native Method)
   at java.net.URLClassLoader.findClass(Unknown Source)
   at java.lang.ClassLoader.loadClass(Unknown Source)
   at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
   at java.lang.ClassLoader.loadClass(Unknown Source)
   at java.lang.ClassLoader.loadClassInternal(Unknown Source)
   at java.lang.Class.forName0(Native Method)
   at java.lang.Class.forName(Unknown Source)
   at viktorije.ViktorijeDatabase.DBconnect(ViktorijeDatabase.java:29)
   at viktorije.ViktorijeDatabase.DBaddToServerList(ViktorijeDatabase.java:78)
   at viktorije.ViktorijePanel.addToServerList(ViktorijePanel.java:1321)
   at viktorije.ActionHandler.mousePressed(ActionHandler.java:198)
   at java.awt.Component.processMouseEvent(Unknown Source)
   at java.awt.Component.processEvent(Unknown Source)
   at java.awt.Container.processEvent(Unknown Source)
   at java.awt.Window.processEvent(Unknown Source)
   at java.awt.Component.dispatchEventImpl(Unknown Source)
   at java.awt.Container.dispatchEventImpl(Unknown Source)
   at java.awt.Window.dispatchEventImpl(Unknown Source)
   at java.awt.Component.dispatchEvent(Unknown Source)
   at java.awt.EventQueue.dispatchEvent(Unknown Source)
   at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
   at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
   at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
   at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
   at java.awt.EventDispatchThread.run(Unknown Source)
Offline Mr_Light

Senior Member




shiny.


« Reply #5 - Posted 2006-11-08 19:07:08 »

Quote
   at java.lang.Class.forName(Unknown Source)
reflextively loaded. it can't predict reflexion so it can't resolve stuff this has cons and pro's appearandly.

anyways, I'd create stubs make sure your dependies are alrightyou could alo do it reflextively abuse the exception to check if the game is there to allow access to it

It's harder to read code than to write it. - it's even harder to write readable code.

The gospel of brother Riven: "The guarantee that all bugs are in *your* code is worth gold." Amen brother a-m-e-n.
Offline dishmoth
« Reply #6 - Posted 2006-11-09 10:48:01 »

Thanks for the suggestions, folks!

Yes, the obvious solution would be to comment out the offending lines - but that's a bit of a one-off hack, and I'd prefer to put something more permanent in place.

I agree that the "correct" solution would be to refactor the code to use trivial base classes, and to have the proper classes created by reflection if they're actually being used in the game.  But to put things into perspective, all I'm trying to do here is make a JAR file smaller.  Call me lazy, but refactoring the code to achieve this seems a little disproportionate. Wink

So in the end I'm probably just going to live with the fact that the JAR is rather larger than it needs to be.

BUT...  Can anyone explain to me why the following code works?  It's from http://www.java-gaming.org/forums/index.php?topic=5488.15.

1  
2  
3  
4  
5  
6  
7  
8  
9  
webstart = true;
try {
    Class.forName("javax.jnlp.ServiceManager");
    // this causes to go and see if the service is available
   ServiceManager.lookup("javax.jnlp.PersistenceService");
} catch (Exception e) {
    System.err.println("MuffinProvider: No webstart detected");
    webstart = false;
}


The code provides Muffin-like functionality (persistent storage) whether or not it's running under WebStart.  The thing is, if we're not running under WebStart, then the class javax.jnlp.ServiceManager doesn't exist (and so Class.forName() throws an exception).  But somehow the code is still allowed to to refer explicitly to the ServiceManager class.  Why doesn't the JVM try to load that class when it is launched?

Cheers,
Simon

Offline Kova

Senior Member





« Reply #7 - Posted 2006-11-09 12:52:19 »

You never get to ServiceManager since exception is thrown (and you catch it). When exception is thrown thread execution halts (and is resumed in catch() if there is one).
Offline dishmoth
« Reply #8 - Posted 2006-11-09 21:45:19 »

You never get to ServiceManager since exception is thrown (and you catch it). When exception is thrown thread execution halts (and is resumed in catch() if there is one).

Yes, and that's exactly the behaviour I'm looking for!  Smiley  The ServiceManager class doesn't exist (unless you're running under WebStart) but the JVM doesn't seem unhappy that its name is mentioned in the code.  So how come it won't let me run a JAR file that omits some classes that are never used?  What am I missing?
Simon

Offline Abuse

JGO Knight


Medals: 12


falling into the abyss of reality


« Reply #9 - Posted 2006-11-09 23:38:23 »

If you read the JLS; in particular :-

http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html

all your questions will be answered.

Make Elite IV:Dangerous happen! Pledge your backing at KICKSTARTER here! https://dl.dropbox.com/u/54785909/EliteIVsmaller.png
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Kova

Senior Member





« Reply #10 - Posted 2006-11-10 00:21:45 »

You never get to ServiceManager since exception is thrown (and you catch it). When exception is thrown thread execution halts (and is resumed in catch() if there is one).

Yes, and that's exactly the behaviour I'm looking for!  Smiley  The ServiceManager class doesn't exist (unless you're running under WebStart) but the JVM doesn't seem unhappy that its name is mentioned in the code.  So how come it won't let me run a JAR file that omits some classes that are never used?  What am I missing?
Simon

you don't load classes reflexively (or whatever mr_light said). When you do usual class creation existence of those classes is checked compile / start time (?) and you get error instantly if they are missing. When you load classes using Class.forName() then they are reflextively loaded, as I can understand from reply of mr_light, and JVM checks if it exist at runtime at that line, so you can catch exception JVM throws if class is missing. This is first time I hear about it so I can't tell you anything besides this Smiley
Offline dishmoth
« Reply #11 - Posted 2006-11-10 16:15:17 »

Quote from: Abuse
If you read the JLS; in particular :-

http://java.sun.com/docs/books/vmspec/2nd-edition/html/ConstantPool.doc.html

all your questions will be answered.

Thanks for the pointer.  One read-through hasn't been enough to answer my question, but I'll keep trying!
Simon

Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #12 - Posted 2006-11-11 02:34:06 »

Mini example:

1  
2  
3  
4  
5  
if ( game == SpaceInvaders ) {
  return new Invader();
else if ( game == Pacman ) {
  return new Ghost();
}



There is a right way and a wrong way to do this:

right: game is a public static final boolean

wrong: anything else that lacks the final part (IIRC)

If you do it the right way, you have just *guaranteed* to the compiler that game will never be anything else *and everything will Just Work*. If you do it the wrong way, you've just told the compiler that it could be anything, and therefore it can/should try to load everything.

Modulo some more complex / clever tricks you can do around this, which I don't think you're interested in. I.e. the first question is simply: have you tried setting game to be final and static?

malloc will be first against the wall when the revolution comes...
Offline dishmoth
« Reply #13 - Posted 2006-11-12 12:01:51 »

There is a right way and a wrong way to do this:

right: game is a public static final boolean

wrong: anything else that lacks the final part (IIRC)

If you do it the right way, you have just *guaranteed* to the compiler that game will never be anything else *and everything will Just Work*.

Aha!  Yes, that's the sort of trick I was looking for.  Thanks!

I've added a public static final flag that protects the bits of my code that refer to non-minigame classes from inside the minigame, and when I switch that on the JVM makes no attempt to load those non-existent classes.  Exactly as you say!

So that's less code for me to upload to JGF now.  Wink

Cheers,
Simon

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Nickropheliac (15 views)
2014-08-31 22:59:12

TehJavaDev (23 views)
2014-08-28 18:26:30

CopyableCougar4 (29 views)
2014-08-22 19:31:30

atombrot (41 views)
2014-08-19 09:29:53

Tekkerue (38 views)
2014-08-16 06:45:27

Tekkerue (35 views)
2014-08-16 06:22:17

Tekkerue (25 views)
2014-08-16 06:20:21

Tekkerue (35 views)
2014-08-16 06:12:11

Rayexar (72 views)
2014-08-11 02:49:23

BurntPizza (49 views)
2014-08-09 21:09:32
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!