4

Let's say I have a class with a method like below

public class Parent {

    public boolean isValidURL() {
        System.out.println("print the name of the caller method and the method's arguements here");
        //pls ignore the return true below. just an eg.
        return true;
    }
}

I then have another method that calls the isValidURL in the parent class

public class Child {
    Parent parent = new Parent();

    public void verifyURL(String url) {
        parent.isValidURL();
    }
}

Now in the Parent class the method isValidURL() should print the caller method which is verifyURL() and its arguments.

Is that possible without reflection? Are there any design pattern that needs to be followed?

EDIT: I want to do this because I want to implement the idea on a logger. Basically, there are many other methods like verifyURL() method accepting different parameters. I'd like to have a common logger to print the it on the console when any methods in the `Child' class is called

Damien-Amen
  • 7,232
  • 12
  • 46
  • 75
  • 7
    Why do you want to do this? – Sotirios Delimanolis Jun 09 '15 at 15:28
  • 1
    You may use the current stacktrace to obtain the info of the caller and the line of code of the class where this is executed and you may log the value of the arguments. Another alternative would be using aspects to achieve this in a cleaner way. Still, what's your specific concern? – Luiggi Mendoza Jun 09 '15 at 15:30
  • 1
    You could always pass `this` as an argument to the method, for the recipient instance to know its caller. However, it seems to underline a more general issue with your design. – Mena Jun 09 '15 at 15:30
  • 2
    I would also argue for the "don't do that" design pattern; basically coming up with the same question that was asked before: what is the problem that you want to solve? – GhostCat Jun 09 '15 at 15:33
  • Parts of that are possible, see [*Get current stack trace in Java*](http://stackoverflow.com/q/1069066/2991525) – fabian Jun 09 '15 at 15:38
  • @SotiriosDelimanolis : I've edited the OP – Damien-Amen Jun 09 '15 at 15:42

4 Answers4

7

Is that possible without reflection?

No. (I don't even think it's possible with reflection.)

Are there any design pattern that needs to be followed?

The pattern here would be to pass the relevant information as argument to the method. :-)

You could also pass the instance of the Child to the constructor of the Parent, and store the URL as a field in Child.

Parent parent = new Parent(this);  // ...then look up URL through field in Child

Or, you could do use a setter prior to the call to isValidURL:

public void verifyURL(String url) {
    parent.setUrl(url);
    parent.isValidURL();
}

Regarding your edit:

EDIT: I want to do this because I want to implement the idea on a logger. Basically, there are many other methods like verifyURL() method accepting different parameters. I'd like to have a common logger to print the it on the console when any methods in the `Child' class is called

That clears things up quite a bit.

For this I recommend looking at the current stack trace. I posted a similar solution over here:

What's important to keep in mind for robustness is that you loop through the stack trace until you find the element you're looking for. Even though Parent may internally delegate the call or use isValidUrl as a helper method, it is most likely the calling class (in this case Child) that is of interest. Here's an example that discards the stack elements that are "internal" and prints the name of the calling class/method:

public boolean isValidURL() {
    for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
        if (ste.getClassName().equals(Thread.class.getName())
                || ste.getClassName().equals(getClass().getName()))
            continue;
        System.out.println(ste.getClassName() + "." + ste.getMethodName());
        break;
    }
    return true;
}
Community
  • 1
  • 1
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • Thanks for your comment. I understand that using `Parent(this)` will let me know get the argument. However the there may be a lot of different methods like `verifyURL` which might have various other arguments. How do I handle that? – Damien-Amen Jun 09 '15 at 15:40
  • If you pass `this` to the `Parent` constructor (and store the `Child` reference in a field in `Parent`), then you can fetch URLs and all other "parameters" through the child reference in `Parent`. – aioobe Jun 09 '15 at 15:50
  • Okay. Got it. But what about the caller method name? – Damien-Amen Jun 09 '15 at 15:51
  • Aha, well, there's no way to pick that up inside the isValidURL method. You *could* extract that through the stack trace (see for instance [this](http://stackoverflow.com/questions/421280/how-do-i-find-the-caller-of-a-method-using-stacktrace-or-reflection) question) but it would be pretty ugly in my opinion. – aioobe Jun 09 '15 at 15:55
  • Exactly. I tried that before and it works. But It is ugly like you mentioned :( – Damien-Amen Jun 09 '15 at 15:56
  • If this is for a logging purposes, I would say that looking at the stack trace could actually make sense. I can't imagine any other use for stack trace information other than debugging / logging. (When writing my answer, I was under the impression that you wanted to base your URL validation logic on which method that called isValidURL.) – aioobe Jun 11 '15 at 20:33
  • In fact I've used a similar solution here: http://stackoverflow.com/questions/30437019/include-filename-line-number-corresponding-to-system-out-print-statements-in-ecl – aioobe Jun 11 '15 at 20:34
3

This answer is basically just an example of how to achieve @LuiggiMendoza's comment.

(See this SO answer: https://stackoverflow.com/a/421338/837703.)

You can use new Throwable().getStackTrace(), which is more or less equivalent to the kind of stack trace you get when an exception is thrown. The most recently called method will be at index 0, and the caller method will be located (usually) at index 1.

So, for example, you could make your isValidURL() method look like this:

public boolean isValidURL() {
    StackTraceElement caller = new Throwable().getStackTrace()[1];
    System.out.println(caller.getClassName() + "." + caller.getMethodName());
    //pls ignore the return true below. just an eg.
    return true;
}

... which would print out the calling method's name and the fully qualified name of its class (in most cases). As for the method arguments, you could try and use logging, but that would probably require the Child class to log it's arguments, and require isValidURL() to pick them up.

Community
  • 1
  • 1
  • When I googled. First SO page I landed was the one in your post. It was very helpful. But I'm trying to see if there are any design pattern that needs to be followed etc. Thanks a lot for your answer. – Damien-Amen Jun 09 '15 at 15:55
0

It seems you try to reinvent trace logging. It is better to use Log4J for this purpose. Then log info message in verifyURL method just before isValidURL is called.

    public class Child {
        private static final Logger log = LoggerFactory.getLogger(Child.class);
        Parent parent = new Parent();

        public void verifyURL(String url) {
            log.info("verifyURL called");
            parent.isValidURL();
        }
    }

EDIT: Now i read your edit of question. You should use AspectJ for this purpose.

Look for something like: http://www.yegor256.com/2014/06/01/aop-aspectj-java-method-logging.html

mefi
  • 1,203
  • 1
  • 12
  • 16
  • Yes, I'm going to do logging. But I don't want to do `log.info("verifyURL called");` in every method in the `Child` class – Damien-Amen Jun 09 '15 at 15:43
-1

There is no way to do that.

That you are even trying to do that indicates something is wrong with your design.

One approach could be to use a template pattern.

public class Parent {

   public boolean isValidURL() {
      isValidURL( url );
      // do any other stuff necessary
   }

  public abstract isValidURL( String sURL );
}

When the child classes implement the isValidURL method, they print out whatever is necessary.

Tyler Durden
  • 11,156
  • 9
  • 64
  • 126