• 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

92.0
today-context/src/main/java/infra/format/support/LenientObjectToEnumConverterFactory.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.Collections;
23
import java.util.EnumSet;
24
import java.util.List;
25
import java.util.Map;
26
import java.util.Set;
27

28
import infra.core.conversion.Converter;
29
import infra.core.conversion.ConverterFactory;
30
import infra.util.MultiValueMap;
31

32
/**
33
 * Abstract base class for converting from a type to a {@link Enum}.
34
 *
35
 * @param <T> the source type
36
 * @author Phillip Webb
37
 * @author Madhura Bhave
38
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
39
 * @since 4.0
40
 */
41
@SuppressWarnings("rawtypes")
42
abstract class LenientObjectToEnumConverterFactory<T> implements ConverterFactory<T, Enum<?>> {
3✔
43

44
  private static final Map<String, List<String>> ALIASES;
45

46
  static {
47
    MultiValueMap<String, String> aliases = MultiValueMap.forLinkedHashMap();
2✔
48
    aliases.add("true", "on");
4✔
49
    aliases.add("false", "off");
4✔
50
    ALIASES = Collections.unmodifiableMap(aliases);
3✔
51
  }
1✔
52

53
  @Override
54
  @SuppressWarnings("unchecked")
55
  public <E extends Enum<?>> Converter<T, E> getConverter(Class<E> targetType) {
56
    Class<?> enumType = targetType;
2✔
57
    while (enumType != null && !enumType.isEnum()) {
5!
58
      enumType = enumType.getSuperclass();
4✔
59
    }
60
    if (enumType == null) {
2!
61
      throw new IllegalArgumentException(
×
62
              "The target type " + targetType.getName() + " does not refer to an enum");
×
63

64
    }
65
    return new LenientToEnumConverter<>((Class<E>) enumType);
6✔
66
  }
67

68
  @SuppressWarnings("unchecked")
69
  private class LenientToEnumConverter<E extends Enum> implements Converter<T, E> {
70

71
    private final Class<E> enumType;
72

73
    LenientToEnumConverter(Class<E> enumType) {
5✔
74
      this.enumType = enumType;
3✔
75
    }
1✔
76

77
    @Nullable
78
    @Override
79
    public E convert(T source) {
80
      String value = source.toString().trim();
4✔
81
      if (value.isEmpty()) {
3✔
82
        return null;
2✔
83
      }
84
      try {
85
        return (E) Enum.valueOf(this.enumType, value);
5✔
86
      }
87
      catch (Exception ex) {
1✔
88
        return findEnum(value);
4✔
89
      }
90
    }
91

92
    private E findEnum(String value) {
93
      String name = getCanonicalName(value);
4✔
94
      List<String> aliases = ALIASES.getOrDefault(name, Collections.emptyList());
6✔
95
      for (E candidate : (Set<E>) EnumSet.allOf(this.enumType)) {
12✔
96
        String candidateName = getCanonicalName(candidate.name());
5✔
97
        if (name.equals(candidateName) || aliases.contains(candidateName)) {
8✔
98
          return candidate;
2✔
99
        }
100
      }
1✔
101
      throw new IllegalArgumentException("No enum constant " + this.enumType.getCanonicalName() + "." + value);
9✔
102
    }
103

104
    private String getCanonicalName(String name) {
105
      StringBuilder canonicalName = new StringBuilder(name.length());
6✔
106
      name.chars()
3✔
107
              .filter(Character::isLetterOrDigit)
2✔
108
              .map(Character::toLowerCase)
3✔
109
              .forEach((c) -> canonicalName.append((char) c));
7✔
110
      return canonicalName.toString();
3✔
111
    }
112

113
  }
114

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