File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Java in General and the fly likes Dynamic Casting to subclass Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Dynamic Casting to subclass" Watch "Dynamic Casting to subclass" New topic
Author

Dynamic Casting to subclass

Tom Battaglia
Greenhorn

Joined: Jul 08, 2005
Posts: 8

I have a superclass named Super, and a subclass named Sub, and I instantiate an instance of Sub as sub. Now I am hoping to pass sub to a generic method in a service class that I have that accepts Super.

public abstract class Super {�}

public class Sub extends Super {�.}

Sub sub = new Sub();
sub.setStuffUniquetoSub(x);
doSomething(sub);

//Want this to be a generic method that can determine that s is indeed the type Sub
public doSomething(Super s) {��.}

Now in the method, I need to determine what the actual subclass of s is. I can do this fairly easily with the Class.geName() method. I have been looking at the asSubclass() and cast() methods as well as the forName() methods to be able to cast the s object to what its type really was to begin with: the subclass of Sub.

The reason I am trying to do this is to leverage OO to avoid writing a bunch of methods that all do the same thing: session.save(x) where x is one of the subclasses, and the concrete type of x is important. It�s an ORM mapped object in Hibernate whose type must be correct so that the correct mapping is used.

Is this possible? I�ve tried those things that I already mentioned, but none of them actually return the concrete instance of the original subclass.

Thanks in advance for any input/direction.


---<br />Tom Battaglia<br />:wq
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
One way to find out "the subclass" of an object is using the instanceof operator.

But you might also consider using a "true OO" solution like the Visitor pattern, which is a little bit more robust against changes in the class hierarchy.


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Tom Battaglia
Greenhorn

Joined: Jul 08, 2005
Posts: 8

Hi, I looked into the instanceof operator, but I was really trying to avoid using logic if possible. I am hoping to develop a procedure for using Hibernate that allows any mapped object that extends from some superclass to be inserted or updated using just one method. If I could get it to work, it could potentially handle the majority of our non-specific CRUD operations for all of our applications.

I'll check out the Visitor pattern.

Thanks.
Keith Lynn
Ranch Hand

Joined: Feb 07, 2005
Posts: 2367
I'm not sure if there is a way to accomplish what you want other than to have a set method for each particular subclass in the hierarchy. If you have just one method that accepts the superclass, then the reference type is going to be changed to the superclass even though the runtime type will remain the same. You will need some kind of logic to downcast the reference type back to the original.
Tom Battaglia
Greenhorn

Joined: Jul 08, 2005
Posts: 8

Hi Keith-

I'm with you on this. Is there any way that I can do this in my method that accepts the superclass? It seems like it should be possible being that the getName() method can tell me what the originating class for the object was.

Do you suppose that this is how a debugger can tell you what your object types are?

Thanks,
TB
Reid M. Pinchback
Ranch Hand

Joined: Jan 25, 2002
Posts: 775
Originally posted by Tom Battaglia:
The reason I am trying to do this is to leverage OO to avoid writing a bunch of methods that all do the same thing: session.save(x) where x is one of the subclasses, and the concrete type of x is important. It�s an ORM mapped object in Hibernate whose type must be correct so that the correct mapping is used.


If this were C++ the situation would be different, C++ understands the notion of a most derived class in resolving polymorphism/overloading issues, where Java understands the shallower notion of the compile-time declared type. The distinction doesn't hit people until they try to create something along the lines of a visitor pattern. Visitor in C++ is easy, but Visitor in Java, in the full flavour of how it was originally published, implies an extra (often painfully inconvenient) layer of indirection.

I think you have two broad choices in Java, one of which probably isn't good for the situation you described.

1: Invert the responsibility. Given:

SuperA, SubA, and OtherB.myMethod(SuperA),

you want B to be sensitive to the specific class, SuperA or SubA. In many cases you'd be inclined to suspect that the design out of sync with the correct placement of behaviour responsibility, i.e. that myMethod() was in the wrong place; it should be in SuperA or SubA so that the subclass could provide the appropriate overridden behaviour.

Nice simple answer, except that for cross-cutting functionality like persistence mappings you might not want to sprinkle that responsibility all over the place, or you may be dealing with already-compiled code (libraries) for which this isn't a feasible solution at all.

2: Create a convention for establishing a correspondence. This was the original approach of JavaBeans for exposing bean info to GUI builders, but you can use the technique in many places. For example, if you have a concrete class names "SuperA" and "SubA", then you could expect to look for "SuperAForOrm" and "SubAForOrm" to contain the mapping info. Now "OtherB" would just use the class name of the argument to derive the class name of the mapping, and use reflection to load and instantiate the mapping object. You don't have to use classes, an XML configuration file corresponding to the original class names would serve the same purpose (which is basically the Hibernate approach, if I recall). The point is just that somehow you establish a correspondence without embedding the specifics in "OtherB"; you only have it contain the algorithm for the correspondence. If you like to think in terms of a Visitor by way of an analogy, you can think of this correspondence algorithm as the traversal mechanism with respect to the hierarchy of class inheritence relationships.

There are many other twists and turns you can add to this (using aspects, using annotations, using dependency injection) to make the situation more convenient, but at the end of the day I think you'll always find some element of #1 or #2 buried somewhere in the final solution given that we are talking about using Java, not C++.
[ March 16, 2006: Message edited by: Reid M. Pinchback ]

Reid - SCJP2 (April 2002)
ak pillai
author
Ranch Hand

Joined: Feb 11, 2006
Posts: 288
I would prefer a visitor deign pattern. The "instnaceof" operator can adversely affect performance, if your method with insatnceof operator is frequently accessed or in a loop.


java j2ee job interview questions with answers | Learn the core concepts and the key areas
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Tom Battaglia:
Hi, I looked into the instanceof operator, but I was really trying to avoid using logic if possible. I am hoping to develop a procedure for using Hibernate that allows any mapped object that extends from some superclass to be inserted or updated using just one method. If I could get it to work, it could potentially handle the majority of our non-specific CRUD operations for all of our applications.


What do you have to do differently for the different subtypes? What would the code look like if you'd use instanceof?
Reid M. Pinchback
Ranch Hand

Joined: Jan 25, 2002
Posts: 775
Code containing instanceof needs to be altered every time you add to the class hierarchy. Leads to bugs when people are working in the hierarchy but don't know the magical places to update with knowledge about the hierarchy. Not sure if you can completely eliminate that issue, but it sounds like maybe that is the situation Tom wants to avoid.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Reid M. Pinchback:
Code containing instanceof needs to be altered every time you add to the class hierarchy.


Typically, yes, but not always - for example when you are using tag interfaces prior to Java 5. And when it won't need to be altered everytime a new subclass is added, it's quite comfortable to use it.
M Anderson
Greenhorn

Joined: Mar 17, 2006
Posts: 25
Why not just overload the method that takes the Super type into several methods that take the various sub types. This counts as OO.

So, you'd have some doSometing(SubA) and doSomething(SubB) methods. If there's a chance for duplicate code, could you write a generic method to handle that common logic that these 'doSomething' methods could call?


Mike -- SCJP, SCWCD
Reid M. Pinchback
Ranch Hand

Joined: Jan 25, 2002
Posts: 775
That approach only works if the compile-time type reference is the correct type. Easy if SubA and SubB don't have a common ancestor that you'll use in a method signature, but as I understand it Tom's original question was for exactly that - how to have the method signature for the common ancestor but get the concrete type-specific behaviour. This wouldn't be an issue in C++ which resolves dynamically to the most resolved type, but not in Java.

Maybe an example will make this clearer than the $20 OO buzzwords.



Because in Java the type of the "myRef" reference is "SuperA", you'll hit the first version of the "OtherClass.doSomething()" method. This would not be true in C++; in C++ you'd hit the second one.

So the issue isn't with creating duplicate methods; you are correct, that is perfectly reasonable to do. The problem is that with inverted responsibilities you get the wrong compile-time resolution of the method signatures if the object references are typed as an ancestor.

Sounds wierd. Never really thought about it until creating bizillion of these goofy little cases when studying for the java cert exam. :roll:
Tom Battaglia
Greenhorn

Joined: Jul 08, 2005
Posts: 8

Well...I gotta say that I'm really impressed with the responses, and Reid has truly gotten the problem that I'm trying to solve. The reason that I didn't want to overload the method that accepts the superclass..

doSomething(Super super){}

is simply to try to develop a one-method solution that could operate with any Hibernate mapped object so long as it extended from the Super. If I could do this, then one would never have to write an insertRecord(Record r) or updateRecord(Record r) again. The method could self discover the object type and then Hibernate could either INSERT or UPDATE it accordingly so long as it was mapped.

I have spent some time today messing with a ReflectiveVisitor, and I think that I am close.

How does this sound? If I have methods in my visitor named visitSubA(), visitSubB(), etc... using reflection I can determine which method to call when I visit something like this:

public void visit(Object o) {
String methodName = o.getClass().getName();
methodName = "visit" + methodName.substring(methodName.lastIndexOf('.') + 1);

try {
Method m = getClass().getMethod(methodName, new Class[]{o.getClass()});
m.invoke(this, new Object[] {o});
} catch (NoSuchMethodException e) {
doDefault(o);
} catch (InvocationTargetException e) {
System.out.println(e.getMessage());
} catch (IllegalAccessException e) {
System.out.println(e.getMessage());
}
}

The problem now is that which the Visitor pattern seems to have as an inherent problem..I have to put my concrete code for each new subclass into the Visitor instead of into a HibernateService.

Thoughts, ideas?
Reid M. Pinchback
Ranch Hand

Joined: Jan 25, 2002
Posts: 775
Yup, this will work, your reflective visitor embodies the second option I outlined, essentially an instanceof correspondence handler without having the downside of having to maintain the cascading if tests (nice solution).

Yup, Visitor does have an inherent problem, but just in Java or languages with similar type resolution issues. The double indirection that works in C++ doesn't work in Java. You need triple indirection to make the shift from an Iterator with a single common visitation behaviour to a Visitor with type-specific visitation behaviour, which is what your reflective visitor is effectively dealing with.
[ March 17, 2006: Message edited by: Reid M. Pinchback ]
Tom Battaglia
Greenhorn

Joined: Jul 08, 2005
Posts: 8

So Reid.....

Do you think that it would be possible to create my visitSubA()...visitSubX() methods dynamically at runtime? They are all basically the same, and the names of the classes that would be used as method names are already defined in Hibernate's config file. If so, then my visitor could potentially fulfill my goal. What do you think?

Thanks for all the input.
Reid M. Pinchback
Ranch Hand

Joined: Jan 25, 2002
Posts: 775
Depending on the specifics, it sounds like you might use reflection, annotation, aspects (e.g. for introductions), or some combination of the three to create some kind of class-specific automation at runtime.
[ March 17, 2006: Message edited by: Reid M. Pinchback ]
Tom Battaglia
Greenhorn

Joined: Jul 08, 2005
Posts: 8

Keeping the only references to the set of subclass objects that we would be using in one location such as the implementation of a ReflectiveVisitor might solve the problem well enough for now. It's still better that having to write specific methods that accept each and every type of subclass that might come into play. I just wonder if it will be too much brain strain for everyone here to have to implement the ReflectiveVisitor in their projects.

Thanks for all the insight.
Saso Jordanoski
Greenhorn

Joined: Jan 04, 2005
Posts: 4
Originally posted by Tom Battaglia:
I have a superclass named Super, and a subclass named Sub, and I instantiate an instance of Sub as sub. Now I am hoping to pass sub to a generic method in a service class that I have that accepts Super.

public abstract class Super {�}

public class Sub extends Super {�.}

Sub sub = new Sub();
sub.setStuffUniquetoSub(x);
doSomething(sub);

//Want this to be a generic method that can determine that s is indeed the type Sub
public doSomething(Super s) {��.}

Now in the method, I need to determine what the actual subclass of s is. I can do this fairly easily with the Class.geName() method. I have been looking at the asSubclass() and cast() methods as well as the forName() methods to be able to cast the s object to what its type really was to begin with: the subclass of Sub.

The reason I am trying to do this is to leverage OO to avoid writing a bunch of methods that all do the same thing: session.save(x) where x is one of the subclasses, and the concrete type of x is important. It�s an ORM mapped object in Hibernate whose type must be correct so that the correct mapping is used.

Is this possible? I�ve tried those things that I already mentioned, but none of them actually return the concrete instance of the original subclass.

Thanks in advance for any input/direction.


My answer come a little late, but I hope that it will be usefull.

I would like to point to an error in your assumption with regard to Hibernate:
Originally posted by Tom Battaglia: (cut to the the important part)

The reason I am trying to do this is to leverage OO to avoid writing a bunch of methods that all do the same thing: session.save(x) where x is one of the subclasses, and the concrete type of x is important. It�s an ORM mapped object in Hibernate whose type must be correct so that the correct mapping is used.

The concrete type of x is <b>not</b> important to Hibernate, Hibernate will get the runtime type information. So everything will just work as you expect. Seems you are trying to solve non existing problem here.

Greetings,

Saso
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Dynamic Casting to subclass