2

I have a class:

class Superclass { static List list() { ... } }

and subclasses:

class Subclass extends Superclass { ... }
class Subclass2 extends Superclass { ... }

I want to call the list method like this: Subclass.list() or Subclass2.list(), and do something different based on which subclass it was called with.

Is there a way I can tell which subclass is calling the list method?

Note: I don't want to have to override the list method in each of the subclasses.

UPDATE: Everyone is saying this is bad design, and in most cases I think it would be, but I don't think so in my case. My ORM defines methods that take in a java.lang.Class. I want to provide a shorthand for my ORM's methods so that I can say User.list(...) instead of ORM.list(User.class, ...).

Kyle
  • 21,377
  • 37
  • 113
  • 200
  • 5
    Overriding in the subclasses seems like the right thing to do. Why do you not want to do this? – Oliver Charlesworth Jan 24 '11 at 23:33
  • @Oli - The Superclass.list method is basically either going to call getFromDatabase(Subclass.class) or getFromDatabase(Subclass2.class), etc. I want whatever classes that derive from `Superclass` to be able to get the ability to say `Subclass.list()` to simply get a list of their type from the database. `list` isn't the only method `Superclass` has, so I don't want to have to override 5 different methods in each subclass. – Kyle Jan 24 '11 at 23:39
  • 3
    @Kyle: So rather than some simple boilerplate in each derived class, you're going to need to maintain a bunch of type-checking `if-else` statements in each base-class method. This is lunacy! – Oliver Charlesworth Jan 24 '11 at 23:40
  • @Oli - Nope, no `if-else` type checking. It will just get the class and pass it along to another method. eg. `getFromDatabase(the class of whatever this was called with)`. – Kyle Jan 24 '11 at 23:43
  • 1
    @Oli, agreed! It is reasons exactly like this why method overriding was created. – Chris Wagner Jan 24 '11 at 23:44
  • @Kyle: At some point, something must conditionally execute different code depending on the type. – Oliver Charlesworth Jan 24 '11 at 23:45
  • @Oli Right, but not my code. It's my Object-Relational-Mapper that just takes in the type of the class. I don't have to write any of such `if-else` code. – Kyle Jan 24 '11 at 23:49
  • @hvgotcodes - Objectify for Google App Engine - http://code.google.com/p/objectify-appengine/ – Kyle Jan 25 '11 at 01:41

5 Answers5

1

Sounds like an Interface/Implementation problem.

Create an interface for the list() method and then write two implementations, Subclass uses implementation1, Subclass2 uses implementation2.

UPDATE

Look at my comment, check out this question How do I find the caller of a method using stacktrace or reflection?

Like everyone comments, I think you need to rethink your design and either Override the methods in the subclasses as Oli states or create the Interface and Implementations.

Community
  • 1
  • 1
Chris Wagner
  • 20,773
  • 8
  • 74
  • 95
  • I don't want to have to write any code in the subclasses. The `Superclass.list` method is basically either going to call `getFromDatabase(Subclass.class)` or `getFromDatabase(Subclass2.class)` – Kyle Jan 24 '11 at 23:33
  • Take a look at http://stackoverflow.com/questions/421280/in-java-how-do-i-find-the-caller-of-a-method-using-stacktrace-or-reflection, I don't think this is a good pattern/design in your situation though. – Chris Wagner Jan 24 '11 at 23:40
1

Do you mean the subclass will call the method? Then this should be an instance method (not static), abstract, and the subclass would provide the implementation.

Or do you mean override a static method? That is not possible, at least not in a meaningful way. You can try to hide the superclass static method by defining it in the subclass, but this is not a true inheritance relationship.

  • The method gets a list from the database of the desired type. It doesn't rely on any member variables so I think it should be static. Basically I'm trying to do what the Grails framework does and provide all of my model classes with the ability to say `User.list()` to get a list of users from the database. Or `Post.list()`, etc. – Kyle Jan 24 '11 at 23:47
1

I agree this is not the best possible design. If you have compelling reasons to do this anyway, here is a solution -

The following snippet should print

SuperClass.list() - called by Subclass
or
SuperClass.list() - called by Subclass2

...
    static List list() { 
      System.out.println("SuperClass.list() - called by "+Thread.currentThread().getStackTrace()[3].getClassName());
//[3] because you want to skip these last three calls to get to this information -:)
     }
...
Amol Katdare
  • 6,740
  • 2
  • 33
  • 36
  • I was considering this route, however I'm using Groovy, and the index on the stack trace would probably vary quite a bit due to the dynamic nature of the language. – Kyle Jan 25 '11 at 01:44
  • You can probably build a small wrapper that iterates over Thread.currentThread().getStackTrace() elements and breaks on/returns first occurrence of Superclass's subclass. – Amol Katdare Jan 25 '11 at 04:07
0

You could make the list method take an arg, call the method like

Subclass.list(type)

and then test the type. Its kind of clugy thought. You might want to consider a different design option. It might be better to create

listForSubclass1 

or

listForSubclass2

methods, but even then that doesn't seem right...

hvgotcodes
  • 118,147
  • 33
  • 203
  • 236
  • Yea, I was thinking I could just pass in the type of the class, but that is extra work every time I want to make the call. I mainly want to have it this way as a nice shorthand. – Kyle Jan 24 '11 at 23:42
  • @kyle, it doesnt have to be type. also, what does list do? – hvgotcodes Jan 24 '11 at 23:45
0

As to knowing who called it: this is no different to figuring out calling class in general. Traditionally this has been done by throwing an exception, catching it, and checking out stack trace. But later JDK's have methods to access stack trace without throwing exception as well (Thread.getStackTrace(), available since 1.5).

StaxMan
  • 113,358
  • 34
  • 211
  • 239