Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (106)
games submitted by our members
Games in WIP (533)
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  
  Type casting to a class known only at runtime?  (Read 3000 times)
0 Members and 1 Guest are viewing this topic.
Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Posted 2004-07-26 09:55:25 »

How would one go about type casting an object to a class that is loaded at runtime via a class loader?

I currently load an serialized instance of the run-time known object from a file and so i need to cast to the run-time known object before i can use it.

Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #1 - Posted 2004-07-26 10:54:15 »

Use reflection. java.lang.reflect.* IIRC.

malloc will be first against the wall when the revolution comes...
Offline cfmdobbie

Senior Member


Medals: 1


Who, me?


« Reply #2 - Posted 2004-07-26 11:13:02 »

Might be simpler than that, blah.  Moogie, you are deserializing one of your objects, and the reference you are passed is an Object?  If you know what the type is, and you can "hard code" it, a simple cast will do the job:

1  
2  
3  
4  
5  
6  
Object theObject = deserializeMyObject();
if(theObject instanceof MyClass)
{
  MyClass myClass = (MyClass)theObject;
  myClass.myMethod();
}


If you can't use the name of the class in the source code (don't know anything about the class ahead of deserialization) then yes, you'll need to use Reflection to inspect the class members and manipulate them with Field and Method objects - see the java.lang.reflect package as mentioned above.

Hellomynameis Charlie Dobbie.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #3 - Posted 2004-07-26 11:53:57 »

Ah, i thought there might be a nice easy way of doing it via templates.... guess not.

cfmdobbie, It is highly possible that the program will not know the class to cast to and as such will request the appropriate class via a custom class loader.

hmm, i will havet to read up on my reflection me thinks!

thanks anyway guys!
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #4 - Posted 2004-07-26 11:58:38 »

What kind of classes are you loading?
Maybe you could define an interface which those classes should implement. Then you can cast it to that interface.
I was thinking that probably your program must know *something* about the classes being loaded in order to use them.

Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #5 - Posted 2004-07-26 12:10:28 »

Quote
What kind of classes are you loading?
Maybe you could define an interface which those classes should implement. Then you can cast it to that interface.
I was thinking that probably your program must know *something* about the classes being loaded in order to use them.


The classes at the moment inhert from a common super class. would it be sufficent to cast to that super class? even if the sub class may contain other methods?
Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #6 - Posted 2004-07-26 12:23:01 »

Quote


The classes at the moment inhert from a common super class. would it be sufficent to cast to that super class? even if the sub class may contain other methods?



It sounds like you really need to learn about interfaces (as in the java keyword, unfortunately a common word in programming Smiley).

"interface" in java IMHO (others here disagree Smiley) is really a synonym for "abstract datatype", i.e. it lets you define new types in java.

So, what erikd is suggesting is that you create a new type of your choosing (by writing an interface) and make all your imported things of that type.

e.g. if you are loading modules you might create a "module" type which is defined as always having a "getName" method. When loading the modules, you would typecast them directly to "module"
1  
2  
module importedModule = (module) myMethodToImportAModule();
System.out.println( "imported module = "+importedModule.getName() );

Although convention says you should call it Module instead of module Smiley.

malloc will be first against the wall when the revolution comes...
Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #7 - Posted 2004-07-26 12:39:32 »

I do understand interfaces in java. The super class i am currently using can probably be redesigned to be an interface as there is little program logic in the superclass... i'll just make sure the classes that use the interface include that logic.

What i did not know is that you could type cast to an interface... you learn new things every day Smiley

I will give that a go.
Offline princec

JGO Kernel


Medals: 342
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #8 - Posted 2004-07-26 13:24:58 »

Seeing as the program does not know what the class will be in advance, it can't very well call any methods on it can it? So it's an Object whatever way you look at it.

If you're expecting to be able to call methods on it, create an interface that exposes these methods and cast it to that.

Cas Smiley

Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #9 - Posted 2004-07-26 13:29:57 »

Quote

What i did not know is that you could type cast to an interface... you learn new things every day Smiley


Good point. This is the kind of thing that I find is helped if people learn from the start that interface == ADT. If you start off thinking of it as a full type, then you more naturally assume it is typecastable Smiley..

malloc will be first against the wall when the revolution comes...
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline cfmdobbie

Senior Member


Medals: 1


Who, me?


« Reply #10 - Posted 2004-07-26 13:47:01 »

Agreed - the day I realised I could directly refer to a reference of interface type was a happy, happy day.


Converting everything to use interfaces isn't actually necessary - you can still use your superclass:

1  
2  
SuperClass myClass = (SuperClass)getSerializedThingy();
myClass.myMethod();


But whichever way you do it, methods that aren't declared in the superclass/interface cannot be accessed via that reference - you'll still need to cast the object to the specific class if you want to use them.

But that's okay - if you know you need to call a certain method, you know what class you expect your reference to be, so can cast it!

Hellomynameis Charlie Dobbie.
Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #11 - Posted 2004-07-26 22:15:03 »

thanks for all the help!

<sigh> the world would be a better place if we could progamatically load and add classes to the default classloader at run time so that we need not do anthing extra to use the classes. but i am sure the ambiguity is what is stopping this from happening.
Offline cfmdobbie

Senior Member


Medals: 1


Who, me?


« Reply #12 - Posted 2004-07-26 22:47:40 »

But once you deserialise your object and cast to a subclass, it's just the same as any other object in your application.  There's no "compile time" versus "run time" difference if you can do that cast.  If you really don't know enough to make that cast, then in the absence of a class definition you'll have to go through a reflection system - that's no failing of the classloader.

I think you may have the wrong end of the stick somewhere - maybe you'd better just post the code you've currently got and describe what you're trying to do, and we'll see what we can suggest?  I suspect a bit of rearchitecting may be in order.

Hellomynameis Charlie Dobbie.
Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #13 - Posted 2004-07-27 03:51:28 »

I belive that what you have suggested will be sufficent. I will not be able to program the changes until Wednesday but i am confident that it will work.

I am programing a distributed network architecture for intelligent sensor agents.

The problem i am trying to resolve is the fact that some agents request a command to be performed on another agent in the network who potentially does not have the code to perform the command. In this case the target agent will request the appropriate code from the other agent (i.e. a class) it loads this via a classloader.

As well as being asked to perform a  command, serialized objects are sent to the target agent which then will be passed as parameters to a method in the command.

Since i now know that i can type cast to an interface i shold be able to run that method.



hmm... thinking just now... what happens if the command loaded via the class loader internally type casts to classes unknown? (or loaded via the classloader) will it have a run-time error if so can i get around it?
Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #14 - Posted 2004-07-27 04:10:56 »

thinking some more...

I will be able to catch the exception if the class loaded via the classloader creates a new object of unknown type and then handle it.

Offline DanK

Junior Member




Javver games rock yawel!


« Reply #15 - Posted 2004-07-27 05:57:59 »

Interfaces wouldn't be much good for anything if you couldn't reference an object as it's interface type.

How unknown are the classes you are loading, and more importantly, is there a lot of different possibilities? If there are only a few possible classes being loaded then you could use instanceof to determine what to cast the class to... but if it's loading classes based on something that is typed in by the user or from a file that'd be different.

Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #16 - Posted 2004-07-27 13:17:13 »

The classes can be, by design and nature, radically diverse. The only common attributes about the classes being loaded is that they (at the moment) extend from a common super class and that they all will implement a method called process with the signature:

public Object[]  process (Object[] arg)

the arg object array is an array consiting of serialized objects and the return object array will contain the results of the processing.
Offline Breakfast

Senior Member




for great justice!


« Reply #17 - Posted 2004-07-27 14:11:42 »

Sounds like a job for an interface to me.
Offline erikd

JGO Ninja


Medals: 16
Projects: 4
Exp: 14 years


Maximumisness


« Reply #18 - Posted 2004-07-28 09:51:43 »

Quote
The classes can be, by design and nature, radically diverse. The only common attributes about the classes being loaded is that they (at the moment) extend from a common super class and that they all will implement a method called process with the signature:

public Object[]  process (Object[] arg)

the arg object array is an array consiting of serialized objects and the return object array will contain the results of the processing.


If that is the one method you need to call, you can define an interface with that method and cast to the interface.
If there are other methods, do you know beforehand what other methods you need to call? I would guess so, and you could interface to those as well.

Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #19 - Posted 2004-07-28 23:30:33 »

Quote


If that is the one method you need to call, you can define an interface with that method and cast to the interface.
If there are other methods, do you know beforehand what other methods you need to call? I would guess so, and you could interface to those as well.


The only method that is required of the loaded class is the process method. Loading a class and type casting it to the interface is not a problem... the problem is that this loaded class may use classes unknown to the current class loader... how would i go about loading in classes required by this loaded class?

maybe it is not as difficult as i seem to make it out to be... which classloader will be used by the runtime environment when trying to load/find classes that are used in the loaded class? If it is the classloader that actually loaded the class then i should be able to modify my classloader implementation else if it is the default classloader i believe i may be in trouble... unless i can set the default classloader to be my own.
Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #20 - Posted 2004-07-29 00:13:16 »

after some strange queies to google and sun search i belive i have found my answer...

In the article:

http://java.sun.com/j2se/1.3/docs/guide/security/spec/security-spec.doc5.html


it is said that this is the order of determing which class loader is used:

-When loading the first class of an application, a new instance of the URLClassLoader is used.
-When loading the first class of an applet, a new instance of the AppletClassLoader is used.
-When java.lang.Class.ForName is directly called, the primordial class loader is used.
-If the request to load a class is triggered by a reference to it from an existing class, the class loader for the existing class is asked to load the class.

I believe the last point applies to me... am i correct in thinking that the existing class is the class i have just loaded via my custom classloader? If so then all the classes referenced in the loaded class will be asked to be loaded firstly by my custom classlader. Which is exactly what i want and so i will be able to include code in my custom class loader to load these referenced classes. Infact i think that little code will need to be added.

I will now try and implement a simple case to test this.


Offline swpalmer

JGO Coder




Where's the Kaboom?


« Reply #21 - Posted 2004-07-29 01:46:26 »

yes, I think you have it figured correctly.  Let us know how it goes.

Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #22 - Posted 2004-07-29 01:52:00 »

Quote
I believe the last point applies to me... am i correct in thinking that the existing class is the class i have just loaded via my custom classloader? If so then all the classes referenced in the loaded class will be asked to be loaded firstly by my custom classlader. Which is exactly what i want and so i will be able to include code in my custom class loader to load these referenced classes. Infact i think that little code will need to be added.


I'm not entirely compos mentis right now, but I'm pretty sure you've got that right.

The point is that when you load a funky class from an external resource (via a custom classloader), you - the java programmer - only have to load that one class, and the JVM will automatically discover and deal with every class reference / object instantiation / typecast / etc generated by that class and assume that they all live in the same place (i.e. classloader) as the original.

This is the correct assumption for all complex cases, and all non-complex cases are automatically and trivially solved by the fact that classloaders have to delegate to their parent classloader already.

malloc will be first against the wall when the revolution comes...
Offline moogie

JGO Knight


Medals: 12
Projects: 6
Exp: 10 years


Java games rock!


« Reply #23 - Posted 2004-07-29 04:37:48 »

Good news!

I seem to have correctly interpreted/dechiphered the paper i linked to earlier!

My test program worked exactly how i expected it to!

Program logic as follows:

Tester creates an instance of TestClassLoader.
Tester attempts to load the class Foo.

TestClassLoader looks to see whether parent classloaders are able find/load the class Foo and fails causing the method findClass(...) fomr TestClassLoader to be called.
TestClassLoader.findClass(...) attempts to load the class from a directory not in the class path (in this case "test" is used) and is successful and so creates a class from the Foo.class file located in the test directory.

Internally Foo makes use of a class called Bar which is likewise unknown to the default classloader and so the classloader who loaded the Foo instance (i.e. the TestClassLoader instance) is called to find the Bar class.

As with the Foo class, it eventually is found in the "test" directory. (This is the part which i was unsure about)

And now all the classes are loaded the program can run correctly. Yay!


Test program below:


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
public class Foo implements TestInterface
{
      public Foo()
      {
            System.out.println("new Foo Instance");
      }
      public Object[] process (Object[] obj)
      {
            Bar bar = new Bar();
            bar.displayMessage();
            return null;
      }

}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
public class Bar 
{
      public Bar()
      {
            System.out.println("new Bar Instance");
      }
      public void displayMessage()
      {
            System.out.println("It worked! hazzah!");
      }


}


1  
2  
3  
4  
5  
public interface TestInterface 
{
      public Object[] process(Object[] obj);

}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
public class Tester {

      public static void main(String[] args) throws Exception
      {
            ClassLoader testClassLoader =new TestClassLoader();
            Class FooClass= testClassLoader.loadClass("Foo");
            TestInterface foo = (TestInterface) FooClass.newInstance();
            Object[] results = foo.process(new Object[0]);  
      }
}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
public class TestClassLoader extends ClassLoader
{


      public Class findClass(String name)
      {
            byte[] b = loadClassData(name);
            return defineClass(name, b, 0, b.length);
      }
           
      private byte[] loadClassData(String name)
      {
            byte[] b=null;
            try
            {
                  File file=new File("test\\"+name+".class");
                  FileInputStream fis=new FileInputStream (file);
                  b = new byte[(int)file.length()];
                  int read=fis.read(b);
                  if (read!=file.length()) throw new Exception("Bytes read not equal to the expected amount");
            }
            catch (Exception e)
            {
                  e.printStackTrace();
                  System.exit(1);
            }
            return b;
      }

}
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.

pw (26 views)
2014-07-24 01:59:36

Riven (25 views)
2014-07-23 21:16:32

Riven (19 views)
2014-07-23 21:07:15

Riven (22 views)
2014-07-23 20:56:16

ctomni231 (51 views)
2014-07-18 06:55:21

Zero Volt (46 views)
2014-07-17 23:47:54

danieldean (37 views)
2014-07-17 23:41:23

MustardPeter (40 views)
2014-07-16 23:30:00

Cero (56 views)
2014-07-16 00:42:17

Riven (55 views)
2014-07-14 18:02:53
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
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!