001/*
002 * Copyright 2002-2019 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.context.support;
018
019import java.io.Serializable;
020
021import org.springframework.context.MessageSourceResolvable;
022import org.springframework.lang.Nullable;
023import org.springframework.util.ObjectUtils;
024import org.springframework.util.StringUtils;
025
026/**
027 * Spring's default implementation of the {@link MessageSourceResolvable} interface.
028 * Offers an easy way to store all the necessary values needed to resolve
029 * a message via a {@link org.springframework.context.MessageSource}.
030 *
031 * @author Juergen Hoeller
032 * @since 13.02.2004
033 * @see org.springframework.context.MessageSource#getMessage(MessageSourceResolvable, java.util.Locale)
034 */
035@SuppressWarnings("serial")
036public class DefaultMessageSourceResolvable implements MessageSourceResolvable, Serializable {
037
038        @Nullable
039        private final String[] codes;
040
041        @Nullable
042        private final Object[] arguments;
043
044        @Nullable
045        private final String defaultMessage;
046
047
048        /**
049         * Create a new DefaultMessageSourceResolvable.
050         * @param code the code to be used to resolve this message
051         */
052        public DefaultMessageSourceResolvable(String code) {
053                this(new String[] {code}, null, null);
054        }
055
056        /**
057         * Create a new DefaultMessageSourceResolvable.
058         * @param codes the codes to be used to resolve this message
059         */
060        public DefaultMessageSourceResolvable(String[] codes) {
061                this(codes, null, null);
062        }
063
064        /**
065         * Create a new DefaultMessageSourceResolvable.
066         * @param codes the codes to be used to resolve this message
067         * @param defaultMessage the default message to be used to resolve this message
068         */
069        public DefaultMessageSourceResolvable(String[] codes, String defaultMessage) {
070                this(codes, null, defaultMessage);
071        }
072
073        /**
074         * Create a new DefaultMessageSourceResolvable.
075         * @param codes the codes to be used to resolve this message
076         * @param arguments the array of arguments to be used to resolve this message
077         */
078        public DefaultMessageSourceResolvable(String[] codes, Object[] arguments) {
079                this(codes, arguments, null);
080        }
081
082        /**
083         * Create a new DefaultMessageSourceResolvable.
084         * @param codes the codes to be used to resolve this message
085         * @param arguments the array of arguments to be used to resolve this message
086         * @param defaultMessage the default message to be used to resolve this message
087         */
088        public DefaultMessageSourceResolvable(
089                        @Nullable String[] codes, @Nullable Object[] arguments, @Nullable String defaultMessage) {
090
091                this.codes = codes;
092                this.arguments = arguments;
093                this.defaultMessage = defaultMessage;
094        }
095
096        /**
097         * Copy constructor: Create a new instance from another resolvable.
098         * @param resolvable the resolvable to copy from
099         */
100        public DefaultMessageSourceResolvable(MessageSourceResolvable resolvable) {
101                this(resolvable.getCodes(), resolvable.getArguments(), resolvable.getDefaultMessage());
102        }
103
104
105        /**
106         * Return the default code of this resolvable, that is,
107         * the last one in the codes array.
108         */
109        @Nullable
110        public String getCode() {
111                return (this.codes != null && this.codes.length > 0 ? this.codes[this.codes.length - 1] : null);
112        }
113
114        @Override
115        @Nullable
116        public String[] getCodes() {
117                return this.codes;
118        }
119
120        @Override
121        @Nullable
122        public Object[] getArguments() {
123                return this.arguments;
124        }
125
126        @Override
127        @Nullable
128        public String getDefaultMessage() {
129                return this.defaultMessage;
130        }
131
132        /**
133         * Indicate whether the specified default message needs to be rendered for
134         * substituting placeholders and/or {@link java.text.MessageFormat} escaping.
135         * @return {@code true} if the default message may contain argument placeholders;
136         * {@code false} if it definitely does not contain placeholders or custom escaping
137         * and can therefore be simply exposed as-is
138         * @since 5.1.7
139         * @see #getDefaultMessage()
140         * @see #getArguments()
141         * @see AbstractMessageSource#renderDefaultMessage
142         */
143        public boolean shouldRenderDefaultMessage() {
144                return true;
145        }
146
147
148        /**
149         * Build a default String representation for this MessageSourceResolvable:
150         * including codes, arguments, and default message.
151         */
152        protected final String resolvableToString() {
153                StringBuilder result = new StringBuilder(64);
154                result.append("codes [").append(StringUtils.arrayToDelimitedString(this.codes, ","));
155                result.append("]; arguments [").append(StringUtils.arrayToDelimitedString(this.arguments, ","));
156                result.append("]; default message [").append(this.defaultMessage).append(']');
157                return result.toString();
158        }
159
160        /**
161         * The default implementation exposes the attributes of this MessageSourceResolvable.
162         * <p>To be overridden in more specific subclasses, potentially including the
163         * resolvable content through {@code resolvableToString()}.
164         * @see #resolvableToString()
165         */
166        @Override
167        public String toString() {
168                return getClass().getName() + ": " + resolvableToString();
169        }
170
171
172        @Override
173        public boolean equals(@Nullable Object other) {
174                if (this == other) {
175                        return true;
176                }
177                if (!(other instanceof MessageSourceResolvable)) {
178                        return false;
179                }
180                MessageSourceResolvable otherResolvable = (MessageSourceResolvable) other;
181                return (ObjectUtils.nullSafeEquals(getCodes(), otherResolvable.getCodes()) &&
182                                ObjectUtils.nullSafeEquals(getArguments(), otherResolvable.getArguments()) &&
183                                ObjectUtils.nullSafeEquals(getDefaultMessage(), otherResolvable.getDefaultMessage()));
184        }
185
186        @Override
187        public int hashCode() {
188                int hashCode = ObjectUtils.nullSafeHashCode(getCodes());
189                hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(getArguments());
190                hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(getDefaultMessage());
191                return hashCode;
192        }
193
194}