    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements. See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache license, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License. You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the license for the specific language governing permissions and
    015     * limitations under the license.
    016     */
    017    package org.apache.logging.log4j.message;
    018
    019    import java.io.IOException;
    020    import java.io.ObjectInputStream;
    021    import java.io.ObjectOutputStream;
    022    import java.io.Serializable;
    023
    024    /**
    025     * Handles messages that contain an Object.
    026     */
    027    public class ObjectMessage implements Message {
    028
    029        private static final long serialVersionUID = -5903272448334166185L;
    030
    031        private transient Object obj;
    032        private transient String objectString;
    033
    034        /**
    035         * Create the ObjectMessage.
    036         * @param obj The Object to format.
    037         */
    038        public ObjectMessage(final Object obj) {
    039            this.obj = obj == null ? "null" : obj;
    040        }
    041
    042        /**
    043         * Returns the formatted object message.
    044         * @return the formatted object message.
    045         */
    046        @Override
    047        public String getFormattedMessage() {
    048            // LOG4J2-763: cache formatted string in case obj changes later
    049            if (objectString == null) {
    050                objectString = String.valueOf(obj);
    051            }
    052            return objectString;
    053        }
    054
    055        /**
    056         * Returns the object formatted using its toString method.
    057         * @return the String representation of the object.
    058         */
    059        @Override
    060        public String getFormat() {
    061            return getFormattedMessage();
    062        }
    063
    064        /**
    065         * Returns the object as if it were a parameter.
    066         * @return The object.
    067         */
    068        @Override
    069        public Object[] getParameters() {
    070            return new Object[] { obj };
    071        }
    072
    073        @Override
    074        public boolean equals(final Object o) {
    075            if (this == o) {
    076                return true;
    077            }
    078            if (o == null || getClass() != o.getClass()) {
    079                return false;
    080            }
    081
    082            final ObjectMessage that = (ObjectMessage) o;
    083            return obj == null ? that.obj == null : equalObjectsOrStrings(obj, that.obj);
    084        }
    085
    086        private boolean equalObjectsOrStrings(final Object left, final Object right) {
    087            return left.equals(right) || String.valueOf(left).equals(String.valueOf(right));
    088        }
    089
    090        @Override
    091        public int hashCode() {
    092            return obj != null ? obj.hashCode() : 0;
    093        }
    094
    095        @Override
    096        public String toString() {
    097            return "ObjectMessage[obj=" + getFormattedMessage() + ']';
    098        }
    099
    100        private void writeObject(final ObjectOutputStream out) throws IOException {
    101            out.defaultWriteObject();
    102            if (obj instanceof Serializable) {
    103                out.writeObject(obj);
    104            } else {
    105                out.writeObject(String.valueOf(obj));
    106            }
    107        }
    108
    109        private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
    110            in.defaultReadObject();
    111            obj = in.readObject();
    112        }
    113
    114        /**
    115         * Gets the message if it is a throwable.
    116         *
    117         * @return the message if it is a throwable.
    118         */
    119        @Override
    120        public Throwable getThrowable() {
    121            return obj instanceof Throwable ? (Throwable) obj : null;
    122        }
    123    }