You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2022/03/29 14:05:33 UTC

[logging-log4j2] 13/25: Log4j 1.2 bridge missing some LocationInfo constructors.

This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit c4ce19f4f6134ce36551ace8c9c7d65b70ea4d4f
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sat Feb 5 15:53:20 2022 -0500

    Log4j 1.2 bridge missing some LocationInfo constructors.
    
    Conflicts:
    	log4j-1.2-api/src/main/java/org/apache/log4j/spi/LocationInfo.java
---
 .../java/org/apache/log4j/spi/LocationInfo.java    | 96 +++++++++++++++++-----
 .../org/apache/log4j/spi/LocationInfoTest.java     | 82 ++++++++++++++++++
 src/changes/changes.xml                            |  3 +
 3 files changed, 162 insertions(+), 19 deletions(-)

diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LocationInfo.java b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LocationInfo.java
index c5e5b5e..a3f2fd1 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LocationInfo.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/LocationInfo.java
@@ -16,62 +16,120 @@
  */
 package org.apache.log4j.spi;
 
+import java.io.Serializable;
+import java.util.Objects;
+
 /**
  * The internal representation of caller location information.
- * 
+ *
  * @since 0.8.3
  */
-public class LocationInfo implements java.io.Serializable {
+public class LocationInfo implements Serializable {
+
+    /**
+     * 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;
 
-    private final StackTraceElement element;
+    private final StackTraceElement stackTraceElement;
 
     public String fullInfo;
 
     /**
-     * Constructor for LocationInfo.
-     * @param element The StackTraceElement representing the caller.
+     * Constructs a new instance.
      */
-    public LocationInfo(StackTraceElement element) {
-        this.element = element;
+    public LocationInfo(final StackTraceElement stackTraceElement) {
+        this.stackTraceElement = Objects.requireNonNull(stackTraceElement, "stackTraceElement");
+        this.fullInfo = stackTraceElement.toString();
     }
 
     /**
-     * When location information is not available the constant <code>NA</code> is returned. Current value of this string
-     * constant is <b>?</b>.
+     * Constructs a new instance.
+     *
+     * @param file source file name
+     * @param declaringClass class name
+     * @param methodName method
+     * @param line source line number
+     *
+     * @since 1.2.15
      */
-    public final static String NA = "?";
+    public LocationInfo(final String file, final String declaringClass, final String methodName, final String line) {
+        this(new StackTraceElement(declaringClass, methodName, file, Integer.parseInt(line)));
+    }
 
-    static final long serialVersionUID = -1325822038990805636L;
+    /**
+     * Constructs a new instance.
+     */
+    public LocationInfo(final Throwable throwable, final String fqnOfCallingClass) {
+        String declaringClass = null, methodName = null, file = null, line = null;
+        if (throwable != null && fqnOfCallingClass != null) {
+            final StackTraceElement[] elements = throwable.getStackTrace();
+            String prevClass = NA;
+            for (int i = elements.length - 1; i >= 0; i--) {
+                final String thisClass = elements[i].getClassName();
+                if (fqnOfCallingClass.equals(thisClass)) {
+                    final int caller = i + 1;
+                    if (caller < elements.length) {
+                        declaringClass = prevClass;
+                        methodName = elements[caller].getMethodName();
+                        file = elements[caller].getFileName();
+                        if (file == null) {
+                            file = NA;
+                        }
+                        final int lineNo = elements[caller].getLineNumber();
+                        if (lineNo < 0) {
+                            line = NA;
+                        } else {
+                            line = String.valueOf(lineNo);
+                        }
+                        final StringBuilder builder = new StringBuilder();
+                        builder.append(declaringClass);
+                        builder.append(".");
+                        builder.append(methodName);
+                        builder.append("(");
+                        builder.append(file);
+                        builder.append(":");
+                        builder.append(line);
+                        builder.append(")");
+                        this.fullInfo = builder.toString();
+                    }
+                    break;
+                }
+                prevClass = thisClass;
+            }
+        }
+        this.stackTraceElement = new StackTraceElement(declaringClass, methodName, file, Integer.parseInt(line));
+        this.fullInfo = stackTraceElement.toString();
+    }
 
     /**
      * Return the fully qualified class name of the caller making the logging request.
-     @return The class name.
      */
     public String getClassName() {
-        return element.getClassName();
+        return stackTraceElement.getClassName();
     }
 
     /**
      * Return the file name of the caller.
-     @return the file name.
      */
     public String getFileName() {
-        return element.getFileName();
+        return stackTraceElement.getFileName();
     }
 
     /**
      * Returns the line number of the caller.
-     @return The line number.
      */
     public String getLineNumber() {
-        return Integer.toString(element.getLineNumber());
+        return Integer.toString(stackTraceElement.getLineNumber());
     }
 
     /**
      * Returns the method name of the caller.
-     @return The method name.
      */
     public String getMethodName() {
-        return element.getMethodName();
+        return stackTraceElement.getMethodName();
     }
 }
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/spi/LocationInfoTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/spi/LocationInfoTest.java
new file mode 100644
index 0000000..a6daefc
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/spi/LocationInfoTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.spi;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for LocationInfo.
+ */
+public class LocationInfoTest extends TestCase {
+
+    /**
+     * Tests four parameter constructor.
+     */
+    public void testFourParamConstructor() {
+        final String className = LocationInfoTest.class.getName();
+        final String methodName = "testFourParamConstructor";
+        final String fileName = "LocationInfoTest.java";
+        final String lineNumber = "41";
+        LocationInfo li = new LocationInfo(fileName, className, methodName, lineNumber);
+        assertEquals(className, li.getClassName());
+        assertEquals(methodName, li.getMethodName());
+        assertEquals(fileName, li.getFileName());
+        assertEquals(lineNumber, li.getLineNumber());
+        assertEquals(className + "." + methodName + "(" + fileName + ":" + lineNumber + ")", li.fullInfo);
+    }
+
+    /**
+     * Class with name that is a substring of its caller.
+     */
+    private static class NameSubstring {
+        /**
+         * Construct a LocationInfo. Location should be immediate caller of this method.
+         * 
+         * @return location info.
+         */
+        public static LocationInfo getInfo() {
+            return new LocationInfo(new Throwable(), NameSubstring.class.getName());
+
+        }
+    }
+
+    /**
+     * Class whose name is contains the name of the class that obtains the LocationInfo.
+     */
+    private static class NameSubstringCaller {
+        /**
+         * Construct a locationInfo. Location should be this location.
+         * 
+         * @return location info.
+         */
+        public static LocationInfo getInfo() {
+            return NameSubstring.getInfo();
+        }
+
+    }
+
+    /**
+     * Tests creation of location info when the logger class name is a substring of one of the other classes in the stack
+     * trace. See bug 44888.
+     */
+    public void testLocationInfo() {
+        LocationInfo li = NameSubstringCaller.getInfo();
+        assertEquals(NameSubstringCaller.class.getName(), li.getClassName());
+        assertEquals("getInfo", li.getMethodName());
+    }
+
+}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 7d288e7..0226b41 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -331,6 +331,9 @@
       <action dev="ggregory" type="fix" due-to="Gary Gregory">
         Log4j 1.2 bridge missing some ThrowableInformation constructors.
       </action>
+      <action dev="ggregory" type="fix" due-to="Gary Gregory">
+        Log4j 1.2 bridge missing some LocationInfo constructors.
+      </action>
       <action dev="ggregory" type="fix">
         JndiManager reverts to 2.17.0 behavior: Read the system property for each call.
       </action>