How do you get the name of the object from within the object?

keithedward
keithedward used Ask the Experts™
on
Hello,

I am not sure if I am asking this the right way... but I have java bean for a jsp page. This java bean in turn uses a logger class to log to a file... the logger class can be used in any number of beans...

I want the logger class to determine the name of the bean class that it is being class from so that it can write this to the log file ....

So if the employee bean has a logger object, then when the logger object go to write to the log, it will somehow know that it is being called from the employee class

And yes, I know jdk1.4 has a logging utility...

Thanks
Keith
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
A simple, not so elegant solution, will be:

class Logger {
  public static void log(String message, Class caller);
  public static void log(String message, Throwable th, Class caller);
}

class MyBean {
  public void doSomething() {
    File file = new File("....");
    Logger.log("Create file object", getClass());
  }
}

I'll post other solution later. But much better.
Wolfmark
Commented:
Ok, here's the better solution.

The only way I know to get the current stack trace (and so you can see who is the caller) is to use exceptions. A simple code like:
    new Throwable().printStackTrace()
will output to screen the entire stack trace. You can capture the output, using "printStackTrace(PrintWriter w)" or "printStackTrace(PrintStream s)" methods (see javadoc for more info) and parse the result.

So ... all I've done was to get the class org.apache.log4j.spi.LocationInfo from log4j-1.2.2) sources (http://jakarta.apache.org/log4j/docs/index.html) and modify it a bit to work with a my simple application.

I'll post here the source of my test application, and in my next comment the modified source of the LocationInfo class.

class Logger {
     public static void log(String message) {
         
          LocationInfo location = new LocationInfo(new Throwable(), "Logger");
          System.out.print(location.getClassName());
          System.out.println(": " + message);
     }
}

class MyClassA {
     public static void doSomething() {
          Logger.log("doSomething of class A");
     }
}

class MyClassB {
     public static void doSomething() {
          Logger.log("doSomething of class B");
     }
}

public class Test {
     public static void main(String[] args) {
          MyClassA.doSomething();
          MyClassB.doSomething();
     }
}

Commented:
And here's the modified LocationInfo class:

/*
 * Copyright (C) The Apache Software Foundation. All rights reserved.
 *
 * This software is published under the terms of the Apache Software
 * License version 1.1, a copy of which has been included with this
 * distribution in the LICENSE.txt file.  */

// Contributors: Mathias Rupprecht <mmathias.rupprecht@fja.com>

/**
   The internal representation of caller location information.

   @since 0.8.3
*/
class LocationInfo implements java.io.Serializable {
      public final static String LINE_SEP = System.getProperty("line.separator");
      public final static int LINE_SEP_LEN = LINE_SEP.length();

      /**
         Caller's line number.
      */
      transient String lineNumber;
      /**
         Caller's file name.
      */
      transient String fileName;
      /**
         Caller's fully qualified class name.
      */
      transient String className;
      /**
         Caller's method name.
      */
      transient String methodName;
      /**
         All available caller information, in the format
         <code>fully.qualified.classname.of.caller.methodName(Filename.java:line)</code>
        */
      public String fullInfo;

      private static StringWriter sw = new StringWriter();
      private static PrintWriter pw = new PrintWriter(sw);

      /**
         When location information is not available the constant
         <code>NA</code> is returned. Current value of this string
         constant is <b>?</b>.  */
      public final static String NA = "?";

      static final long serialVersionUID = -1325822038990805636L;

      // Check if we are running in IBM's visual age.
      static boolean inVisualAge = false;
      static {
            try {
                  Class dummy = Class.forName("com.ibm.uvm.tools.DebugSupport");
                  inVisualAge = true;
                  System.out.println("Detected IBM VisualAge environment.");
            } catch (Throwable e) {
                  // nothing to do
            }
      }

      /**
         Instantiate location information based on a Throwable. We
         expect the Throwable <code>t</code>, to be in the format
      
           <pre>
            java.lang.Throwable
            ...
              at org.apache.log4j.PatternLayout.format(PatternLayout.java:413)
              at org.apache.log4j.FileAppender.doAppend(FileAppender.java:183)
            at org.apache.log4j.Category.callAppenders(Category.java:131)
            at org.apache.log4j.Category.log(Category.java:512)
            at callers.fully.qualified.className.methodName(FileName.java:74)
            ...
           </pre>
      
           <p>However, we can also deal with JIT compilers that "lose" the
           location information, especially between the parentheses.
      
        */
      public LocationInfo(Throwable t, String fqnOfCallingClass) {
            if (t == null)
                  return;

            String s;
            // Protect against multiple access to sw.
            synchronized (sw) {
                  t.printStackTrace(pw);
                  s = sw.toString();
                  sw.getBuffer().setLength(0);
            }
            //System.out.println("s is ["+s+"].");
            int ibegin, iend;

            // Given the current structure of the package, the line
            // containing "org.apache.log4j.Category." should be printed just
            // before the caller.

            // This method of searching may not be fastest but it's safer
            // than counting the stack depth which is not guaranteed to be
            // constant across JVM implementations.
            ibegin = s.lastIndexOf(fqnOfCallingClass);
            if (ibegin == -1)
                  return;

            ibegin = s.indexOf(LINE_SEP, ibegin);
            if (ibegin == -1)
                  return;
            ibegin += LINE_SEP_LEN;

            // determine end of line
            iend = s.indexOf(LINE_SEP, ibegin);
            if (iend == -1)
                  return;

            // VA has a different stack trace format which doesn't
            // need to skip the inital 'at'
            if (!inVisualAge) {
                  // back up to first blank character
                  ibegin = s.lastIndexOf("at ", iend);
                  if (ibegin == -1)
                        return;
                  // Add 3 to skip "at ";
                  ibegin += 3;
            }
            // everything between is the requested stack item
            this.fullInfo = s.substring(ibegin, iend);
      }

      /**
         Return the fully qualified class name of the caller making the
         logging request.
      */
      public String getClassName() {
            if (fullInfo == null)
                  return NA;
            if (className == null) {
                  // Starting the search from '(' is safer because there is
                  // potentially a dot between the parentheses.
                  int iend = fullInfo.lastIndexOf('(');
                  if (iend == -1)
                        className = NA;
                  else {
                        iend = fullInfo.lastIndexOf('.', iend);

                        // This is because a stack trace in VisualAge looks like:

                        //java.lang.RuntimeException
                        //  java.lang.Throwable()
                        //  java.lang.Exception()
                        //  java.lang.RuntimeException()
                        //  void test.test.B.print()
                        //  void test.test.A.printIndirect()
                        //  void test.test.Run.main(java.lang.String [])
                        int ibegin = 0;
                        if (inVisualAge) {
                              ibegin = fullInfo.lastIndexOf(' ', iend) + 1;
                        }

                        if (iend == -1)
                              className = NA;
                        else
                              className = this.fullInfo.substring(ibegin, iend);
                  }
            }
            return className;
      }

      /**
         Return the file name of the caller.
      
         <p>This information is not always available.
      */
      public String getFileName() {
            if (fullInfo == null)
                  return NA;

            if (fileName == null) {
                  int iend = fullInfo.lastIndexOf(':');
                  if (iend == -1)
                        fileName = NA;
                  else {
                        int ibegin = fullInfo.lastIndexOf('(', iend - 1);
                        fileName = this.fullInfo.substring(ibegin + 1, iend);
                  }
            }
            return fileName;
      }

      /**
         Returns the line number of the caller.
      
         <p>This information is not always available.
      */
      public String getLineNumber() {
            if (fullInfo == null)
                  return NA;

            if (lineNumber == null) {
                  int iend = fullInfo.lastIndexOf(')');
                  int ibegin = fullInfo.lastIndexOf(':', iend - 1);
                  if (ibegin == -1)
                        lineNumber = NA;
                  else
                        lineNumber = this.fullInfo.substring(ibegin + 1, iend);
            }
            return lineNumber;
      }

      /**
         Returns the method name of the caller.
      */
      public String getMethodName() {
            if (fullInfo == null)
                  return NA;
            if (methodName == null) {
                  int iend = fullInfo.lastIndexOf('(');
                  int ibegin = fullInfo.lastIndexOf('.', iend);
                  if (ibegin == -1)
                        methodName = NA;
                  else
                        methodName = this.fullInfo.substring(ibegin + 1, iend);
            }
            return methodName;
      }
}
Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

Commented:
use aLogger.log(Level.INFO, getClass().getName() + ": My error msg");

Commented:
As I saw, you can get other many informations, like method's name, line's number, file's name.

>> And yes, I know jdk1.4 has a logging utility...

But why do you complicate your life and don't use a standard logging utility. Log4j is cool, Jdk1.4 has a framework for logging ... and if you search the net a little bit you'll find many more!

Commented:
Thanx for points! :)

Other thing: if you're using Java 1.4, there is a new method named "getStackTrace" for Throwable class, which returns an array of "StackTraceElement" items. It's better than parsing the output of "printStackTrace" method. And safer!

Cheers

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial