• 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

97.73
today-context/src/main/java/infra/format/support/FormattingConversionServiceFactoryBean.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.format.support;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.util.Set;
23

24
import infra.beans.factory.FactoryBean;
25
import infra.beans.factory.InitializingBean;
26
import infra.context.annotation.Bean;
27
import infra.context.annotation.Configuration;
28
import infra.context.expression.EmbeddedValueResolverAware;
29
import infra.core.StringValueResolver;
30
import infra.core.conversion.Converter;
31
import infra.core.conversion.ConverterFactory;
32
import infra.core.conversion.ConverterRegistry;
33
import infra.core.conversion.GenericConverter;
34
import infra.format.AnnotationFormatterFactory;
35
import infra.format.Formatter;
36
import infra.format.FormatterRegistrar;
37
import infra.format.FormatterRegistry;
38
import infra.format.Parser;
39
import infra.format.Printer;
40

41
/**
42
 * A factory providing convenient access to a {@link FormattingConversionService}
43
 * configured with converters and formatters for common types such as numbers, dates,
44
 * and times.
45
 *
46
 * <p>Additional converters and formatters can be registered declaratively through
47
 * {@link #setConverters(Set)} and {@link #setFormatters(Set)}. Another option
48
 * is to register converters and formatters in code by implementing the
49
 * {@link FormatterRegistrar} interface. You can then provide the set of registrars
50
 * to use through {@link #setFormatterRegistrars(Set)}.
51
 *
52
 * <p>Like all {@code FactoryBean} implementations, this class is suitable for
53
 * use when configuring a Framework application context using Framework {@code <beans>}
54
 * XML configuration files. When configuring the container with
55
 * {@link Configuration @Configuration}
56
 * classes, simply instantiate, configure and return the appropriate
57
 * {@code FormattingConversionService} object from a
58
 * {@link Bean @Bean} method.
59
 *
60
 * @author Keith Donald
61
 * @author Juergen Hoeller
62
 * @author Rossen Stoyanchev
63
 * @author Chris Beams
64
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
65
 * @since 4.0
66
 */
67
public class FormattingConversionServiceFactoryBean
2✔
68
        implements FactoryBean<FormattingConversionService>, EmbeddedValueResolverAware, InitializingBean {
69

70
  @Nullable
71
  private Set<?> converters;
72

73
  @Nullable
74
  private Set<?> formatters;
75

76
  @Nullable
77
  private Set<FormatterRegistrar> formatterRegistrars;
78

79
  private boolean registerDefaultFormatters = true;
4✔
80

81
  @Nullable
82
  private StringValueResolver embeddedValueResolver;
83

84
  @Nullable
85
  private FormattingConversionService conversionService;
86

87
  /**
88
   * Configure the set of custom converter objects that should be added.
89
   *
90
   * @param converters instances of any of the following:
91
   * {@link Converter},
92
   * {@link ConverterFactory},
93
   * {@link GenericConverter}
94
   */
95
  public void setConverters(Set<?> converters) {
96
    this.converters = converters;
3✔
97
  }
1✔
98

99
  /**
100
   * Configure the set of custom formatter objects that should be added.
101
   *
102
   * @param formatters instances of {@link Formatter} or {@link AnnotationFormatterFactory}
103
   */
104
  public void setFormatters(Set<?> formatters) {
105
    this.formatters = formatters;
3✔
106
  }
1✔
107

108
  /**
109
   * <p>Configure the set of FormatterRegistrars to invoke to register
110
   * Converters and Formatters in addition to those added declaratively
111
   * via {@link #setConverters(Set)} and {@link #setFormatters(Set)}.
112
   * <p>FormatterRegistrars are useful when registering multiple related
113
   * converters and formatters for a formatting category, such as Date
114
   * formatting. All types related needed to support the formatting
115
   * category can be registered from one place.
116
   * <p>FormatterRegistrars can also be used to register Formatters
117
   * indexed under a specific field type different from its own &lt;T&gt;,
118
   * or when registering a Formatter from a Printer/Parser pair.
119
   *
120
   * @see FormatterRegistry#addFormatterForFieldType(Class, Formatter)
121
   * @see FormatterRegistry#addFormatterForFieldType(Class, Printer, Parser)
122
   */
123
  public void setFormatterRegistrars(Set<FormatterRegistrar> formatterRegistrars) {
124
    this.formatterRegistrars = formatterRegistrars;
3✔
125
  }
1✔
126

127
  /**
128
   * Indicate whether default formatters should be registered or not.
129
   * <p>By default, built-in formatters are registered. This flag can be used
130
   * to turn that off and rely on explicitly registered formatters only.
131
   *
132
   * @see #setFormatters(Set)
133
   * @see #setFormatterRegistrars(Set)
134
   */
135
  public void setRegisterDefaultFormatters(boolean registerDefaultFormatters) {
136
    this.registerDefaultFormatters = registerDefaultFormatters;
3✔
137
  }
1✔
138

139
  @Override
140
  public void setEmbeddedValueResolver(StringValueResolver embeddedValueResolver) {
141
    this.embeddedValueResolver = embeddedValueResolver;
3✔
142
  }
1✔
143

144
  @Override
145
  public void afterPropertiesSet() {
146
    this.conversionService = new DefaultFormattingConversionService(embeddedValueResolver, registerDefaultFormatters);
9✔
147
    ConverterRegistry.registerConverters(converters, conversionService);
5✔
148
    registerFormatters(conversionService);
4✔
149
  }
1✔
150

151
  private void registerFormatters(FormattingConversionService conversionService) {
152
    if (this.formatters != null) {
3✔
153
      for (Object formatter : this.formatters) {
10✔
154
        if (formatter instanceof Formatter<?>) {
3✔
155
          conversionService.addFormatter((Formatter<?>) formatter);
5✔
156
        }
157
        else if (formatter instanceof AnnotationFormatterFactory<?>) {
3✔
158
          conversionService.addFormatterForFieldAnnotation((AnnotationFormatterFactory<?>) formatter);
5✔
159
        }
160
        else {
161
          throw new IllegalArgumentException(
5✔
162
                  "Custom formatters must be implementations of Formatter or AnnotationFormatterFactory");
163
        }
164
      }
1✔
165
    }
166
    if (this.formatterRegistrars != null) {
3✔
167
      for (FormatterRegistrar registrar : this.formatterRegistrars) {
11✔
168
        registrar.registerFormatters(conversionService);
3✔
169
      }
1✔
170
    }
171
  }
1✔
172

173
  @Override
174
  @Nullable
175
  public FormattingConversionService getObject() {
176
    return this.conversionService;
3✔
177
  }
178

179
  @Override
180
  public Class<? extends FormattingConversionService> getObjectType() {
181
    return FormattingConversionService.class;
×
182
  }
183

184
  @Override
185
  public boolean isSingleton() {
186
    return true;
2✔
187
  }
188

189
}
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