6 changed files with 214 additions and 56 deletions
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
/* |
||||
* Copyright 2012-2019 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.convert; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.EnumSet; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.core.convert.converter.Converter; |
||||
import org.springframework.core.convert.converter.ConverterFactory; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.LinkedMultiValueMap; |
||||
import org.springframework.util.MultiValueMap; |
||||
|
||||
/** |
||||
* Abstract base class for converting from a type to a {@link java.lang.Enum}. |
||||
* |
||||
* @param <T> the source type |
||||
* @author Phillip Webb |
||||
* @author Madhura Bhave |
||||
*/ |
||||
abstract class AbstractTypeToEnumConverterFactory<T> implements ConverterFactory<T, Enum> { |
||||
|
||||
private static Map<String, List<String>> ALIASES; |
||||
|
||||
static { |
||||
MultiValueMap<String, String> aliases = new LinkedMultiValueMap<>(); |
||||
aliases.add("true", "on"); |
||||
aliases.add("false", "off"); |
||||
ALIASES = Collections.unmodifiableMap(aliases); |
||||
} |
||||
|
||||
@Override |
||||
public <E extends Enum> Converter<T, E> getConverter(Class<E> targetType) { |
||||
Class<?> enumType = targetType; |
||||
while (enumType != null && !enumType.isEnum()) { |
||||
enumType = enumType.getSuperclass(); |
||||
} |
||||
Assert.notNull(enumType, () -> "The target type " + targetType.getName() + " does not refer to an enum"); |
||||
return getTypeToEnumConverter(targetType); |
||||
} |
||||
|
||||
abstract <E extends Enum> Converter<T, E> getTypeToEnumConverter(Class<E> targetType); |
||||
|
||||
<E extends Enum> E findEnum(String source, Class<E> enumType) { |
||||
Map<String, E> candidates = new LinkedHashMap<>(); |
||||
for (E candidate : (Set<E>) EnumSet.allOf(enumType)) { |
||||
candidates.put(getCanonicalName(candidate.name()), candidate); |
||||
} |
||||
String name = getCanonicalName(source); |
||||
E result = candidates.get(name); |
||||
if (result != null) { |
||||
return result; |
||||
} |
||||
for (String alias : ALIASES.getOrDefault(name, Collections.emptyList())) { |
||||
result = candidates.get(alias); |
||||
if (result != null) { |
||||
return result; |
||||
} |
||||
} |
||||
throw new IllegalArgumentException("No enum constant " + enumType.getCanonicalName() + "." + source); |
||||
|
||||
} |
||||
|
||||
private String getCanonicalName(String name) { |
||||
StringBuilder canonicalName = new StringBuilder(name.length()); |
||||
name.chars().filter(Character::isLetterOrDigit).map(Character::toLowerCase) |
||||
.forEach((c) -> canonicalName.append((char) c)); |
||||
return canonicalName.toString(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* Copyright 2012-2019 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.convert; |
||||
|
||||
import org.springframework.core.convert.converter.Converter; |
||||
|
||||
/** |
||||
* Converter to support mapping of YAML style {@code "false"} and {@code "true"} to enums |
||||
* {@code ON} and {@code OFF}. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
@SuppressWarnings({ "unchecked", "rawtypes" }) |
||||
final class BooleanToEnumConverterFactory extends AbstractTypeToEnumConverterFactory<Boolean> { |
||||
|
||||
@Override |
||||
<E extends Enum> Converter<Boolean, E> getTypeToEnumConverter(Class<E> targetType) { |
||||
return new BooleanToEnum<>(targetType); |
||||
} |
||||
|
||||
private class BooleanToEnum<T extends Enum> implements Converter<Boolean, T> { |
||||
|
||||
private final Class<T> enumType; |
||||
|
||||
BooleanToEnum(Class<T> enumType) { |
||||
this.enumType = enumType; |
||||
} |
||||
|
||||
@Override |
||||
public T convert(Boolean source) { |
||||
return findEnum(Boolean.toString(source), this.enumType); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
/* |
||||
* Copyright 2012-2019 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.boot.convert; |
||||
|
||||
import java.util.stream.Stream; |
||||
|
||||
import org.junit.jupiter.params.provider.Arguments; |
||||
|
||||
import org.springframework.core.convert.ConversionService; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link BooleanToEnumConverterFactory}. |
||||
* |
||||
* @author Madhura Bhave |
||||
*/ |
||||
class BooleanToEnumConverterFactoryTests { |
||||
|
||||
@ConversionServiceTest |
||||
void convertFromBooleanToEnumWhenShouldConvertValue(ConversionService conversionService) { |
||||
assertThat(conversionService.convert(true, TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.ON); |
||||
assertThat(conversionService.convert(false, TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.OFF); |
||||
assertThat(conversionService.convert(true, TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.TRUE); |
||||
assertThat(conversionService.convert(false, TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.FALSE); |
||||
} |
||||
|
||||
static Stream<? extends Arguments> conversionServices() { |
||||
return ConversionServiceArguments |
||||
.with((service) -> service.addConverterFactory(new BooleanToEnumConverterFactory())); |
||||
} |
||||
|
||||
enum TestOnOffEnum { |
||||
|
||||
ON, OFF |
||||
|
||||
} |
||||
|
||||
enum TestTrueFalseEnum { |
||||
|
||||
ONE, TWO, TRUE, FALSE, ON, OFF |
||||
|
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue