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(Object obj) {
039            if (obj == null) {
040                obj = "null";
041            }
042            this.obj = obj;
043        }
044    
045        /**
046         * Returns the formatted object message.
047         * @return the formatted object message.
048         */
049        @Override
050        public String getFormattedMessage() {
051            // LOG4J2-763: cache formatted string in case obj changes later
052            if (objectString == null) {
053                objectString = String.valueOf(obj);
054            }
055            return objectString;
056        }
057    
058        /**
059         * Returns the object formatted using its toString method.
060         * @return the String representation of the object.
061         */
062        @Override
063        public String getFormat() {
064            return getFormattedMessage();
065        }
066    
067        /**
068         * Returns the object as if it were a parameter.
069         * @return The object.
070         */
071        @Override
072        public Object[] getParameters() {
073            return new Object[] { obj };
074        }
075    
076        @Override
077        public boolean equals(final Object o) {
078            if (this == o) {
079                return true;
080            }
081            if (o == null || getClass() != o.getClass()) {
082                return false;
083            }
084    
085            final ObjectMessage that = (ObjectMessage) o;
086            return obj == null ? that.obj == null : equalObjectsOrStrings(obj, that.obj);
087        }
088        
089        private boolean equalObjectsOrStrings(Object left, Object right) {
090            return left.equals(right) || String.valueOf(left).equals(String.valueOf(right));
091        }
092    
093        @Override
094        public int hashCode() {
095            return obj != null ? obj.hashCode() : 0;
096        }
097    
098        @Override
099        public String toString() {
100            return "ObjectMessage[obj=" + getFormattedMessage() + ']';
101        }
102    
103        private void writeObject(final ObjectOutputStream out) throws IOException {
104            out.defaultWriteObject();
105            if (obj instanceof Serializable) {
106                out.writeObject(obj);
107            } else {
108                out.writeObject(String.valueOf(obj));
109            }
110        }
111    
112        private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
113            in.defaultReadObject();
114            obj = in.readObject();
115        }
116    
117        /**
118         * Gets the message if it is a throwable.
119         *
120         * @return the message if it is a throwable.
121         */
122        @Override
123        public Throwable getThrowable() {
124            return obj instanceof Throwable ? (Throwable) obj : null;
125        }
126    }