001/*
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v2.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.classic.spi;
015
016import ch.qos.logback.classic.ClassicConstants;
017import ch.qos.logback.core.CoreConstants;
018
019import java.io.Serializable;
020import java.util.Objects;
021
022import static ch.qos.logback.classic.ClassicConstants.DECLARING_CLASS_NA;
023import static ch.qos.logback.classic.ClassicConstants.FILENAME_NA;
024import static ch.qos.logback.classic.ClassicConstants.LINE_NUMBER_NA;
025import static ch.qos.logback.classic.ClassicConstants.METHOD_NAME_NA;
026
027public class StackTraceElementProxy implements Serializable {
028
029    private static final long serialVersionUID = -2374374378980555982L;
030
031    final StackTraceElement ste;
032    // save a byte or two during serialization, as we can
033    // reconstruct this field from 'ste'
034    transient private String steAsString;
035
036    @Deprecated
037    ClassPackagingData classPackagingData;
038
039    // See https://github.com/qos-ch/logback/issues/1040
040    static final StackTraceElement NA_SUBSTITUTE = new StackTraceElement(DECLARING_CLASS_NA, METHOD_NAME_NA,
041                                                                        FILENAME_NA, LINE_NUMBER_NA);
042
043    public StackTraceElementProxy(StackTraceElement ste) {
044        // while null StackTraceElement is not expected, we defensively replace it with NA_SUBSTITUTE.
045        this.ste = Objects.requireNonNullElse(ste, NA_SUBSTITUTE);
046    }
047
048    public String getSTEAsString() {
049        if (steAsString == null) {
050            steAsString = "at " + ste.toString();
051        }
052        return steAsString;
053    }
054
055    public StackTraceElement getStackTraceElement() {
056        return ste;
057    }
058
059    public void setClassPackagingData(ClassPackagingData cpd) {
060        if (this.classPackagingData != null) {
061            throw new IllegalStateException("Packaging data has been already set");
062        }
063        this.classPackagingData = cpd;
064    }
065
066    public ClassPackagingData getClassPackagingData() {
067        return classPackagingData;
068    }
069
070    @Override
071    public int hashCode() {
072        return ste.hashCode();
073    }
074
075    @Override
076    public boolean equals(Object obj) {
077        if (this == obj)
078            return true;
079        if (obj == null)
080            return false;
081        if (getClass() != obj.getClass())
082            return false;
083        final StackTraceElementProxy other = (StackTraceElementProxy) obj;
084
085        if (!ste.equals(other.ste)) {
086            return false;
087        }
088        if (classPackagingData == null) {
089            if (other.classPackagingData != null) {
090                return false;
091            }
092        } else if (!classPackagingData.equals(other.classPackagingData)) {
093            return false;
094        }
095        return true;
096    }
097
098    @Override
099    public String toString() {
100        return getSTEAsString();
101    }
102}