• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TAKETODAY / today-infrastructure / 18154768944

01 Oct 2025 07:26AM UTC coverage: 81.882% (-0.005%) from 81.887%
18154768944

push

github

web-flow
Merge pull request #290 from TAKETODAY/dev/jspecify

jspecify

59788 of 78013 branches covered (76.64%)

Branch coverage included in aggregate %.

141239 of 167496 relevant lines covered (84.32%)

3.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.49
today-context/src/main/java/infra/context/support/AbstractResourceBasedMessageSource.java
1
/*
2
 * Copyright 2017 - 2025 the original author or authors.
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see [https://www.gnu.org/licenses/]
16
 */
17

18
package infra.context.support;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.util.LinkedHashSet;
23
import java.util.Locale;
24
import java.util.Set;
25

26
import infra.lang.Assert;
27
import infra.util.ObjectUtils;
28

29
/**
30
 * Abstract base class for {@code MessageSource} implementations based on
31
 * resource bundle conventions, such as {@link ResourceBundleMessageSource}
32
 * and {@link ReloadableResourceBundleMessageSource}. Provides common
33
 * configuration methods and corresponding semantic definitions.
34
 *
35
 * @author Juergen Hoeller
36
 * @see ResourceBundleMessageSource
37
 * @see ReloadableResourceBundleMessageSource
38
 * @since 4.0
39
 */
40
public abstract class AbstractResourceBasedMessageSource extends AbstractMessageSource {
2✔
41

42
  private final Set<String> basenameSet = new LinkedHashSet<>(4);
6✔
43

44
  @Nullable
45
  private String defaultEncoding;
46

47
  private boolean fallbackToSystemLocale = true;
3✔
48

49
  @Nullable
50
  private Locale defaultLocale;
51

52
  private long cacheMillis = -1;
4✔
53

54
  /**
55
   * Set a single basename, following the basic ResourceBundle convention
56
   * of not specifying file extension or language codes. The resource location
57
   * format is up to the specific {@code MessageSource} implementation.
58
   * <p>Regular and XMl properties files are supported: e.g. "messages" will find
59
   * a "messages.properties", "messages_en.properties" etc arrangement as well
60
   * as "messages.xml", "messages_en.xml" etc.
61
   *
62
   * @param basename the single basename
63
   * @see #setBasenames
64
   * @see java.util.ResourceBundle
65
   */
66
  public void setBasename(String basename) {
67
    setBasenames(basename);
8✔
68
  }
1✔
69

70
  /**
71
   * Set an array of basenames, each following the basic ResourceBundle convention
72
   * of not specifying file extension or language codes. The resource location
73
   * format is up to the specific {@code MessageSource} implementation.
74
   * <p>Regular and XMl properties files are supported: e.g. "messages" will find
75
   * a "messages.properties", "messages_en.properties" etc arrangement as well
76
   * as "messages.xml", "messages_en.xml" etc.
77
   * <p>The associated resource bundles will be checked sequentially when resolving
78
   * a message code. Note that message definitions in a <i>previous</i> resource
79
   * bundle will override ones in a later bundle, due to the sequential lookup.
80
   * <p>Note: In contrast to {@link #addBasenames}, this replaces existing entries
81
   * with the given names and can therefore also be used to reset the configuration.
82
   *
83
   * @param basenames an array of basenames
84
   * @see #setBasename
85
   * @see java.util.ResourceBundle
86
   */
87
  public void setBasenames(String... basenames) {
88
    this.basenameSet.clear();
3✔
89
    addBasenames(basenames);
3✔
90
  }
1✔
91

92
  /**
93
   * Add the specified basenames to the existing basename configuration.
94
   * <p>Note: If a given basename already exists, the position of its entry
95
   * will remain as in the original set. New entries will be added at the
96
   * end of the list, to be searched after existing basenames.
97
   *
98
   * @see #setBasenames
99
   * @see java.util.ResourceBundle
100
   */
101
  public void addBasenames(String... basenames) {
102
    if (ObjectUtils.isNotEmpty(basenames)) {
3!
103
      for (String basename : basenames) {
16✔
104
        Assert.hasText(basename, "Basename must not be empty");
3✔
105
        this.basenameSet.add(basename.trim());
6✔
106
      }
107
    }
108
  }
1✔
109

110
  /**
111
   * Return this {@code MessageSource}'s basename set, containing entries
112
   * in the order of registration.
113
   * <p>Calling code may introspect this set as well as add or remove entries.
114
   *
115
   * @see #addBasenames
116
   */
117
  public Set<String> getBasenameSet() {
118
    return this.basenameSet;
3✔
119
  }
120

121
  /**
122
   * Set the default charset to use for parsing properties files.
123
   * Used if no file-specific charset is specified for a file.
124
   * <p>The effective default is the {@code java.util.Properties}
125
   * default encoding: ISO-8859-1. A {@code null} value indicates
126
   * the platform default encoding.
127
   * <p>Only applies to classic properties files, not to XML files.
128
   *
129
   * @param defaultEncoding the default charset
130
   */
131
  public void setDefaultEncoding(@Nullable String defaultEncoding) {
132
    this.defaultEncoding = defaultEncoding;
3✔
133
  }
1✔
134

135
  /**
136
   * Return the default charset to use for parsing properties files, if any.
137
   */
138
  @Nullable
139
  protected String getDefaultEncoding() {
140
    return this.defaultEncoding;
3✔
141
  }
142

143
  /**
144
   * Set whether to fall back to the system Locale if no files for a specific
145
   * Locale have been found. Default is "true"; if this is turned off, the only
146
   * fallback will be the default file (e.g. "messages.properties" for
147
   * basename "messages").
148
   * <p>Falling back to the system Locale is the default behavior of
149
   * {@code java.util.ResourceBundle}. However, this is often not desirable
150
   * in an application server environment, where the system Locale is not relevant
151
   * to the application at all: set this flag to "false" in such a scenario.
152
   *
153
   * @see #setDefaultLocale
154
   */
155
  public void setFallbackToSystemLocale(boolean fallbackToSystemLocale) {
156
    this.fallbackToSystemLocale = fallbackToSystemLocale;
3✔
157
  }
1✔
158

159
  /**
160
   * Return whether to fall back to the system Locale if no files for a specific
161
   * Locale have been found.
162
   */
163
  protected boolean isFallbackToSystemLocale() {
164
    return this.fallbackToSystemLocale;
×
165
  }
166

167
  /**
168
   * Specify a default Locale to fall back to, as an alternative to falling back
169
   * to the system Locale.
170
   * <p>Default is to fall back to the system Locale. You may override this with
171
   * a locally specified default Locale here, or enforce no fallback locale at all
172
   * through disabling {@link #setFallbackToSystemLocale "fallbackToSystemLocale"}.
173
   *
174
   * @see #setFallbackToSystemLocale
175
   * @see #getDefaultLocale()
176
   */
177
  public void setDefaultLocale(@Nullable Locale defaultLocale) {
178
    this.defaultLocale = defaultLocale;
×
179
  }
×
180

181
  /**
182
   * Determine a default Locale to fall back to: either a locally specified default
183
   * Locale or the system Locale, or {@code null} for no fallback locale at all.
184
   *
185
   * @see #setDefaultLocale
186
   * @see #setFallbackToSystemLocale
187
   * @see Locale#getDefault()
188
   */
189
  @Nullable
190
  protected Locale getDefaultLocale() {
191
    if (this.defaultLocale != null) {
3!
192
      return this.defaultLocale;
×
193
    }
194
    if (this.fallbackToSystemLocale) {
3✔
195
      return Locale.getDefault();
2✔
196
    }
197
    return null;
2✔
198
  }
199

200
  /**
201
   * Set the number of seconds to cache loaded properties files.
202
   * <ul>
203
   * <li>Default is "-1", indicating to cache forever (matching the default behavior
204
   * of {@code java.util.ResourceBundle}). Note that this constant follows Framework
205
   * conventions, not {@link java.util.ResourceBundle.Control#getTimeToLive}.
206
   * <li>A positive number will cache loaded properties files for the given
207
   * number of seconds. This is essentially the interval between refresh checks.
208
   * Note that a refresh attempt will first check the last-modified timestamp
209
   * of the file before actually reloading it; so if files don't change, this
210
   * interval can be set rather low, as refresh attempts will not actually reload.
211
   * <li>A value of "0" will check the last-modified timestamp of the file on
212
   * every message access. <b>Do not use this in a production environment!</b>
213
   * </ul>
214
   * <p><b>Note that depending on your ClassLoader, expiration might not work reliably
215
   * since the ClassLoader may hold on to a cached version of the bundle file.</b>
216
   * Prefer {@link ReloadableResourceBundleMessageSource} over
217
   * {@link ResourceBundleMessageSource} in such a scenario, in combination with
218
   * a non-classpath location.
219
   */
220
  public void setCacheSeconds(int cacheSeconds) {
221
    this.cacheMillis = cacheSeconds * 1000L;
×
222
  }
×
223

224
  /**
225
   * Set the number of milliseconds to cache loaded properties files.
226
   * Note that it is common to set seconds instead: {@link #setCacheSeconds}.
227
   * <ul>
228
   * <li>Default is "-1", indicating to cache forever (matching the default behavior
229
   * of {@code java.util.ResourceBundle}). Note that this constant follows Framework
230
   * conventions, not {@link java.util.ResourceBundle.Control#getTimeToLive}.
231
   * <li>A positive number will cache loaded properties files for the given
232
   * number of milliseconds. This is essentially the interval between refresh checks.
233
   * Note that a refresh attempt will first check the last-modified timestamp
234
   * of the file before actually reloading it; so if files don't change, this
235
   * interval can be set rather low, as refresh attempts will not actually reload.
236
   * <li>A value of "0" will check the last-modified timestamp of the file on
237
   * every message access. <b>Do not use this in a production environment!</b>
238
   * </ul>
239
   *
240
   * @see #setCacheSeconds
241
   */
242
  public void setCacheMillis(long cacheMillis) {
243
    this.cacheMillis = cacheMillis;
3✔
244
  }
1✔
245

246
  /**
247
   * Return the number of milliseconds to cache loaded properties files.
248
   */
249
  protected long getCacheMillis() {
250
    return this.cacheMillis;
3✔
251
  }
252

253
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc