• 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

87.06
today-context/src/main/java/infra/validation/AbstractPropertyBindingResult.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.validation;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.beans.PropertyEditor;
23

24
import infra.beans.BeanUtils;
25
import infra.beans.ConfigurablePropertyAccessor;
26
import infra.beans.PropertyAccessor;
27
import infra.beans.PropertyAccessorUtils;
28
import infra.beans.PropertyEditorRegistry;
29
import infra.core.TypeDescriptor;
30
import infra.core.conversion.ConversionService;
31
import infra.core.conversion.support.ConvertingPropertyEditorAdapter;
32
import infra.lang.Assert;
33

34
/**
35
 * Abstract base class for {@link BindingResult} implementations that work with
36
 * Framework's {@link PropertyAccessor} mechanism.
37
 * Pre-implements field access through delegation to the corresponding
38
 * PropertyAccessor methods.
39
 *
40
 * @author Juergen Hoeller
41
 * @see #getPropertyAccessor()
42
 * @see PropertyAccessor
43
 * @see ConfigurablePropertyAccessor
44
 * @since 4.0
45
 */
46
@SuppressWarnings("serial")
47
public abstract class AbstractPropertyBindingResult extends AbstractBindingResult {
48

49
  @Nullable
50
  private transient ConversionService conversionService;
51

52
  /**
53
   * Create a new AbstractPropertyBindingResult instance.
54
   *
55
   * @param objectName the name of the target object
56
   * @see DefaultMessageCodesResolver
57
   */
58
  protected AbstractPropertyBindingResult(String objectName) {
59
    super(objectName);
3✔
60
  }
1✔
61

62
  public void initConversion(ConversionService conversionService) {
63
    Assert.notNull(conversionService, "ConversionService is required");
3✔
64
    this.conversionService = conversionService;
3✔
65
    if (getTarget() != null) {
3✔
66
      getPropertyAccessor().setConversionService(conversionService);
4✔
67
    }
68
  }
1✔
69

70
  /**
71
   * Returns the underlying PropertyAccessor.
72
   *
73
   * @see #getPropertyAccessor()
74
   */
75
  @Override
76
  @Nullable
77
  public PropertyEditorRegistry getPropertyEditorRegistry() {
78
    return (getTarget() != null ? getPropertyAccessor() : null);
7!
79
  }
80

81
  /**
82
   * Returns the canonical property name.
83
   *
84
   * @see PropertyAccessorUtils#canonicalPropertyName
85
   */
86
  @Override
87
  protected String canonicalFieldName(String field) {
88
    return PropertyAccessorUtils.canonicalPropertyName(field);
3✔
89
  }
90

91
  /**
92
   * Determines the field type from the property type.
93
   *
94
   * @see #getPropertyAccessor()
95
   */
96
  @Override
97
  @Nullable
98
  public Class<?> getFieldType(@Nullable String field) {
99
    return getTarget() != null
4✔
100
            ? getPropertyAccessor().getPropertyType(fixedField(field))
7✔
101
            : super.getFieldType(field);
3✔
102
  }
103

104
  /**
105
   * Fetches the field value from the PropertyAccessor.
106
   *
107
   * @see #getPropertyAccessor()
108
   */
109
  @Override
110
  @Nullable
111
  protected Object getActualFieldValue(String field) {
112
    return getPropertyAccessor().getPropertyValue(field);
5✔
113
  }
114

115
  /**
116
   * Formats the field value based on registered PropertyEditors.
117
   *
118
   * @see #getCustomEditor
119
   */
120
  @Override
121
  @Nullable
122
  protected Object formatFieldValue(String field, @Nullable Object value) {
123
    String fixedField = fixedField(field);
4✔
124
    // Try custom editor...
125
    PropertyEditor customEditor = getCustomEditor(fixedField);
4✔
126
    if (customEditor != null) {
2✔
127
      customEditor.setValue(value);
3✔
128
      String textValue = customEditor.getAsText();
3✔
129
      // If the PropertyEditor returned null, there is no appropriate
130
      // text representation for this value: only use it if non-null.
131
      if (textValue != null) {
2✔
132
        return textValue;
2✔
133
      }
134
    }
135
    if (this.conversionService != null) {
3✔
136
      // Try custom converter...
137
      TypeDescriptor fieldDesc = getPropertyAccessor().getPropertyTypeDescriptor(fixedField);
5✔
138
      TypeDescriptor strDesc = TypeDescriptor.valueOf(String.class);
3✔
139
      if (fieldDesc != null && this.conversionService.canConvert(fieldDesc, strDesc)) {
8!
140
        return this.conversionService.convert(value, fieldDesc, strDesc);
7✔
141
      }
142
    }
143
    return value;
2✔
144
  }
145

146
  /**
147
   * Retrieve the custom PropertyEditor for the given field, if any.
148
   *
149
   * @param fixedField the fully qualified field name
150
   * @return the custom PropertyEditor, or {@code null}
151
   */
152
  @Nullable
153
  protected PropertyEditor getCustomEditor(String fixedField) {
154
    ConfigurablePropertyAccessor propertyAccessor = getPropertyAccessor();
3✔
155
    Class<?> targetType = propertyAccessor.getPropertyType(fixedField);
4✔
156
    PropertyEditor editor = propertyAccessor.findCustomEditor(targetType, fixedField);
5✔
157
    if (editor == null) {
2✔
158
      editor = BeanUtils.findEditorByConvention(targetType);
3✔
159
    }
160
    return editor;
2✔
161
  }
162

163
  /**
164
   * This implementation exposes a PropertyEditor adapter for a Formatter,
165
   * if applicable.
166
   */
167
  @Override
168
  @Nullable
169
  public PropertyEditor findEditor(@Nullable String field, @Nullable Class<?> valueType) {
170
    Class<?> valueTypeForLookup = valueType;
2✔
171
    if (valueTypeForLookup == null) {
2✔
172
      valueTypeForLookup = getFieldType(field);
4✔
173
    }
174
    PropertyEditor editor = super.findEditor(field, valueTypeForLookup);
5✔
175
    if (editor == null && this.conversionService != null) {
5!
176
      TypeDescriptor td = null;
2✔
177
      if (field != null && getTarget() != null) {
5!
178
        TypeDescriptor ptd = getPropertyAccessor().getPropertyTypeDescriptor(fixedField(field));
7✔
179
        if (ptd != null && (valueType == null || valueType.isAssignableFrom(ptd.getType()))) {
9!
180
          td = ptd;
2✔
181
        }
182
      }
183
      if (td == null) {
2!
184
        td = TypeDescriptor.valueOf(valueTypeForLookup);
×
185
      }
186
      if (this.conversionService.canConvert(TypeDescriptor.valueOf(String.class), td)) {
7!
187
        editor = new ConvertingPropertyEditorAdapter(this.conversionService, td);
7✔
188
      }
189
    }
190
    return editor;
2✔
191
  }
192

193
  /**
194
   * Provide the PropertyAccessor to work with, according to the
195
   * concrete strategy of access.
196
   * <p>Note that a PropertyAccessor used by a BindingResult should
197
   * always have its "extractOldValueForEditor" flag set to "true"
198
   * by default, since this is typically possible without side effects
199
   * for model objects that serve as data binding target.
200
   *
201
   * @see ConfigurablePropertyAccessor#setExtractOldValueForEditor
202
   */
203
  public abstract ConfigurablePropertyAccessor getPropertyAccessor();
204

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