001/*
002 * Copyright 2002-2014 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.messaging.support;
018
019import java.io.Serializable;
020import java.util.Map;
021
022import org.springframework.messaging.Message;
023import org.springframework.messaging.MessageHeaders;
024import org.springframework.util.Assert;
025import org.springframework.util.ObjectUtils;
026
027/**
028 * An implementation of {@link Message} with a generic payload.
029 * Once created, a GenericMessage is immutable.
030 *
031 * @author Mark Fisher
032 * @since 4.0
033 * @see MessageBuilder
034 */
035public class GenericMessage<T> implements Message<T>, Serializable {
036
037        private static final long serialVersionUID = 4268801052358035098L;
038
039
040        private final T payload;
041
042        private final MessageHeaders headers;
043
044
045        /**
046         * Create a new message with the given payload.
047         * @param payload the message payload (never {@code null})
048         */
049        public GenericMessage(T payload) {
050                this(payload, new MessageHeaders(null));
051        }
052
053        /**
054         * Create a new message with the given payload and headers.
055         * The content of the given header map is copied.
056         * @param payload the message payload (never {@code null})
057         * @param headers message headers to use for initialization
058         */
059        public GenericMessage(T payload, Map<String, Object> headers) {
060                this(payload, new MessageHeaders(headers));
061        }
062
063        /**
064         * A constructor with the {@link MessageHeaders} instance to use.
065         * <p><strong>Note:</strong> the given {@code MessageHeaders} instance is used
066         * directly in the new message, i.e. it is not copied.
067         * @param payload the message payload (never {@code null})
068         * @param headers message headers
069         */
070        public GenericMessage(T payload, MessageHeaders headers) {
071                Assert.notNull(payload, "Payload must not be null");
072                Assert.notNull(headers, "MessageHeaders must not be null");
073                this.payload = payload;
074                this.headers = headers;
075        }
076
077
078        public T getPayload() {
079                return this.payload;
080        }
081
082        public MessageHeaders getHeaders() {
083                return this.headers;
084        }
085
086
087        public boolean equals(Object other) {
088                if (this == other) {
089                        return true;
090                }
091                if (!(other instanceof GenericMessage)) {
092                        return false;
093                }
094                GenericMessage<?> otherMsg = (GenericMessage<?>) other;
095                // Using nullSafeEquals for proper array equals comparisons
096                return (ObjectUtils.nullSafeEquals(this.payload, otherMsg.payload) && this.headers.equals(otherMsg.headers));
097        }
098
099        public int hashCode() {
100                // Using nullSafeHashCode for proper array hashCode handling
101                return (ObjectUtils.nullSafeHashCode(this.payload) * 23 + this.headers.hashCode());
102        }
103
104        public String toString() {
105                StringBuilder sb = new StringBuilder(getClass().getSimpleName());
106                sb.append(" [payload=");
107                if (this.payload instanceof byte[]) {
108                        sb.append("byte[").append(((byte[]) this.payload).length).append("]");
109                }
110                else {
111                        sb.append(this.payload);
112                }
113                sb.append(", headers=").append(this.headers).append("]");
114                return sb.toString();
115        }
116
117}