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}