• Post Reply Bookmark Topic Watch Topic
  • New Topic

loading a class via reflection without knowing the full qualified path ?  RSS feed

 
litzhr litzhr
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi there

I d like to load a class via reflection and call the constructor of the class object. My problem is that I dont know the full qulified name e.g. org.xyz.Classname bur only the Classname.

I tried different things but none seem to work:

1.

//does not suffice, full qualified name required

2.

//if i do not pass the full qualified name i get a ClassNotFoundException

3. I tried to consruct a class object with my own classloader , calling:



This almost works. I get a class Object without knowing the full qulified path. I can transform a filename into a raw array of bytes and I get the class out of it. But there is still a problem: If there are more than on classes defined in the same textfile I get an InvocationTargetException.

It looks like this:


As you can see there is the class TransformationDemo_jButton1_actionAdapter class defined in the same classfile. The problem is now that the twoButtons constructor calls the TransfomationDemo_jButton1_actionAdapter constructor and this leads to InvocationTargetException. I dont know if this is a java bug because it should be possible.

Can you help me?
 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I suppose you load the classes from class files, not from java (text) files?

The TransformationDemo_jButton1_actionAdapter should get compiled to its own classfile, regardless of wether it's defined in the same source code file or not. Your problem possibly is that you need to load that class, too.

What exactly does the exception look like you get (including stack trace and nested exceptions)?
 
Nick George
Ranch Hand
Posts: 815
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If I may:

I'd like to make a super-overgeneralization, to which I would like knowledgeable people to disprove.


If you are using reflection, your program suffers a fundemental flaw in its design.
 
Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think flaw is too strong. It might be a bit of a compromise and something to consider carefully. I'm tickled with a couple factories that load abstract ids and classnames from configuration. When somebody asks for a handler:

strategy = factory.getStrategyFor(id);

the factory uses class.forName... to create a new handler. Absolutely no compile time dependencies on any handlers. But I think that's just one toe in the reflection pool.

I'm less comfortable with finding methods and variables on other classes. We have a generic method that copies all non-null attributes from one instance of any bean to another bean with identical attribute names. But I could be convinced that falls into the design flaw area

And I get real squirmy around instanceof.
 
Warren Dew
blacksmith
Ranch Hand
Posts: 1332
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Interesting conjecture, Joseph. My gut reaction is to agree, but then I start thinking of exceptions....

I agree with Stan that use of Class.forName to set up a run time configuration is entirely legitimate. This is basically just a workaround for the fact that configuration files can't contain actual class specifications, just data.

I'll use instanceof even more freely. I'm interested if people see a design flaw in the following code; I suspect if they find one, it won't be fundamental:


I just noticed that this code, too, deals with flat data where a class can't be specified directly; the class of the command is being generated from binary data in the buffer. Perhaps there's a connection here?

Stan James:

We have a generic method that copies all non-null attributes from one instance of any bean to another bean with identical attribute names. But I could be convinced that falls into the design flaw area

That's the kind of thing that makes me feel 'squirmy', as you put it. To me, names are just arbitrary identifiers; the fact that two members share a name doesn't necessarily say anything about whether they share functionality; if it works, it's just because you're getting lucky, not because the bean code was meant to work that way.

Let's look at this from another perspective: what happens if you do a "rename" refactoring from your fancy modern IDE? Things that use instanceof are fine, since the language, and thus the IDE, recognizes the next word as a class name. If you use class.forName, things could get broken if you don't change your configuration file, but there's a pretty good chance you'll remember that change. But if you're extracting random member variable names, I don't think there's a very good chance that when changing an attribute name you'll remember to change all attributes in other classes that happen to have the same name - and worse, if you do that, you might end up breaking things anyway, for example by creating a new name collision.

I'm interested in additional points of view, though.
 
Nick George
Ranch Hand
Posts: 815
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'd like to... drum roll please... Display... My... IGNORANCE!!!

Where does instanceof fit into this discussion?

I could guess that instanceof calls methods from the reflection API, but why guess when you're around a bunch of people who genuinely know what they're talking about?
[ September 06, 2004: Message edited by: Joseph George ]
 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Joseph George:
Where does instanceof fit into this discussion?


It's another way to query for type information at runtime instead of using proper polymorphism...
 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Warren Dew:
I agree with Stan that use of Class.forName to set up a run time configuration is entirely legitimate. This is basically just a workaround for the fact that configuration files can't contain actual class specifications, just data.


It's actually a quite powerfull way to decouple the compile time structure of a system from its runtime structure.

JDBC uses it, so that at compile time you actually don't need to know the type of database you use.

JAXP uses it, so that at compile time you don't need to know what XML parser to use.

Eclipse uses it, so that at compile time they don't need to know which Plugins to use (or even which ones exist!).

Etc. pp.


I'll use instanceof even more freely. I'm interested if people see a design flaw in the following code; I suspect if they find one, it won't be fundamental:




Well, the flaw is that it potentially breaks the Single Choice Principle - especially when there is more than one place where you need to know about the possible types of commands. If you introduce another command, you need to remember to update all those places.

You might want to take a look at the Visitor pattern for an alternative...


We have a generic method that copies all non-null attributes from one instance of any bean to another bean with identical attribute names. But I could be convinced that falls into the design flaw area

That's the kind of thing that makes me feel 'squirmy', as you put it. To me, names are just arbitrary identifiers; the fact that two members share a name doesn't necessarily say anything about whether they share functionality; if it works, it's just because you're getting lucky, not because the bean code was meant to work that way.


Depends on where those beans come from.

We are using exactly this technique for beans created by JAXB.

Imagine an XML-Schema defining a configuration file. Imagine that from that schema, another schema automatically gets generated (basically making all elements optional). Both schemas are then used to automatically generate beans that can get filled automatically with the data from XML files.

Now we need to read data from XML files and merge the data from XML files to the latter schema into data from files to the former schema. That is, we need to copy data from one bean to another bean that we know about that they must be "compatible" according to our rules.

Now imagine that we have a whole bunch of those schemata, and that they are changed frequently.

An algorithm using reflection is a perfect fit, as far as I can see.
 
Warren Dew
blacksmith
Ranch Hand
Posts: 1332
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, among other things, all of these things - java.lang.reflect.*, Class.forName, instanceof - violate the Liskov Substitution Principle, which roughly says that a program that expects and object of a given class (e.g., by declaring a variable to be of that class) should run the same way with an object of a subclass of that class. Here's one of many pages discussing the Liskov Substitution Principle in more detail:

http://javaboutique.internet.com/tutorials/JavaOO/

My code snippet violates this because an object of the Administration subclass of the Command class gets handled differently than a generic Command class.

Of course, every time you do a cast, say when taking an object out of a collection, you violate the Liskov Substitution Principle. So you get into questions about just how badly it's violated - just how badly one is getting into the guts of a class by using these features. For example, java.lang.reflect allows one to examine internal aspects of a class' implementation that the person writing the class probably intended not to be accessible, thus breaking modularity and making it much more difficult to change code safely.

Uh, can I suggest that you repost your original post in this thread in the OO forum? There are lots of people that hang out there who would probably add very useful comments.
 
Warren Dew
blacksmith
Ranch Hand
Posts: 1332
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Er, never mind my suggestion to Joseph to repost, I see Ilya has found this thread!

Ilya Preuss:

Depends on where those beans come from.

We are using exactly this technique for beans created by JAXB.

Imagine an XML-Schema ...


Interesting that this is yet another case, like reading configuration files or my buffer, that involves fundamentally flat data (XML files being flat until they get parsed).
 
Warren Dew
blacksmith
Ranch Hand
Posts: 1332
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ilya Preuss:

Well, the flaw is that it potentially breaks the Single Choice Principle - especially when there is more than one place where you need to know about the possible types of commands. If you introduce another command, you need to remember to update all those places.

Yes.

You might want to take a look at the Visitor pattern for an alternative...

I will be adding more Commands. The problem is, the set of classes the Commands operate on is also unstable and growing, so if I make the Commands Visitors, each new class will require a change to every Visitor. Also, since any given Command operates on only a small subset of these classes, using the Visitor pattern would result in a lot of unsupported operations.

And, actually, this is presently the only place the code needs to know about multiple types of commands. In fact, given the strong correlation between deserialization of data and use of these reflective language features, I suspect it will remain the only place where the code will need to know that; everywhere else, the relevant detail about objects' classes is already known. The only reason the information isn't known here is that the class has to be extracted from the data before the object can be created.

So, I'll propose a modified version of Joseph's postulate:

"Reflection should only be used when extracting type information from serialized data."

Counterexamples?
[ September 07, 2004: Message edited by: Warren Dew ]
 
David Hibbs
Ranch Hand
Posts: 374
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Stan James:

I'm less comfortable with finding methods and variables on other classes. We have a generic method that copies all non-null attributes from one instance of any bean to another bean with identical attribute names. But I could be convinced that falls into the design flaw area

And I get real squirmy around instanceof.


If by 'finding' you refer to searching for a specific method or field in a specific piece of code, yes--that makes me somewhat squimish. However, when it comes to a bulk copy mechanism it's actually much more convenient--especially in frameworks and libraries. Apache uses such a mechanism itself in commons-beanutils (BeanUtils.copyProperties and PropertyUtils.copyProperties).

instanceof can be important, but should be used with interfaces rather than concrete classes. It should also ONLY be used in a couple conditions:
a) where some special behavior needs performed where a truer polymorphic behavior is undesirable such as the previous example of an AdminCommand.
b) to verify the outcome of a factory/strategy construction -- so as to avoid simple ClassCastExceptions and instead return a more helpful error message.
 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Warren Dew:
Er, never mind my suggestion to Joseph to repost, I see Ilya has found this thread!




BTW, the name is Il*j*a
 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Warren Dew:
this is presently the only place the code needs to know about multiple types of commands. In fact, given the strong correlation between deserialization of data and use of these reflective language features, I suspect it will remain the only place where the code will need to know that; everywhere else, the relevant detail about objects' classes is already known. The only reason the information isn't known here is that the class has to be extracted from the data before the object can be created.


Then I guess it doesn't do much harm. I'd probably simply live with it.

So, I'll propose a modified version of Joseph's postulate:

"Reflection should only be used when extracting type information from serialized data."

Counterexamples?


Well, I recently wanted to write a test that executes a command from the context menu of a Borland Gridcontrol. The only way to do this I found is invoking a private method via reflection.

Of course this actually is a bad hack - but it's still better than not having the test.

BTW, if you are thinking about using Borland DataExpress in your product - think again...
[ September 07, 2004: Message edited by: Ilja Preuss ]
 
Julian Kennedy
Ranch Hand
Posts: 823
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I don't understand why it is necessary or even justifiable to use instanceof at all in Warren's example.

What would be the issue with refactoring as shown below? The key modification is emboldened. The rest of the changes have been made as the style of the original was upsetting me deeply!

Jules
 
Warren Dew
blacksmith
Ranch Hand
Posts: 1332
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Julian, I see three problems with your proposal (some of which you may not view as problems).

First, I have multiple subclasses of the Administration class - for example, the Protocol class inherits from Administration. (In fact, Administration is an abstract class and all instantiations of it are subclasses.) Your code would incorrectly queue a Protocol command to the character rather than to the administrative command list where it belongs. Using instanceof works because it returns true if the type of the object is the specified class or a subclass of it.

Second, your proposal duplicates data, resulting in an additional potential point of failure. Objects now have their type stored in two places - where it's used by the virtual machine, and in an additional field that we've added. Each time we create a new command subclass, we get an extra opportunity to break things by forgetting to add a new constant identifying the type of the objects in the class.

Third, your proposal still violates the Liskov Substitution Principle, so it doesn't, in my opinion, actually fix anything. In fact, it's an even worse violation than using instanceof, since not only are administrative commands not treated the same as other commands by the program, but different administrative command subclasses end up causing different program behavior as well.

i guess I just don't see what your proposal fixes. I'm open to counterarguments, though.
 
Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'd try hard to make the commands polymorphic so this routine only does command.execute(). Maybe nested commands - the outer one knows how to queue up the inner one, the inner one does the real work. One outer command might put its payload on the admin list while another puts its payload on the character queue.

BTW: I liked visitor, too. I think commands aren't visitors, they accept visitors. Each command has:

Visitor has a visit method for each command type

One aspect of this is you have to update Visitor for every new command type. Its a very active site of change, but isolated to one class so not too painful.
 
Warren Dew
blacksmith
Ranch Hand
Posts: 1332
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stan James:

I'd try hard to make the commands polymorphic so this routine only does command.execute().

Actually the commands do have a polymorphic execute() method. One of the reason they are being queued separately is that that method needs to be executed at different times for administrative and other commands - in fact, in different threads. (In the future, they might even execute on different machines.)

I thought about creating a separate queueing command and call command.Queue_on(this), then have the command call an appropriate method of "this", say Add_to_administrative_queue or Add_to_character_queue. That's probably the safest way of doing it, but I'm not sure it's worth the extra code, indirection, and coupling. I'm interested in opinions on that.

Regarding the visitor pattern, if I make the commands the visited elements, then all the different things the commands operate on end up being visitors. So I end up having to add methods, many of which will be empty, in a lot of different places whenever I add a command.

In fact, I think Design Patterns specifically cautions against using the visitor pattern when you'll frequently be adding visited element classes.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!