下面列出了org.springframework.core.convert.converter.ConverterFactory#org.springframework.core.convert.TypeDescriptor 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Hook method to lookup the converter for a given sourceType/targetType pair.
* First queries this ConversionService's converter cache.
* On a cache miss, then performs an exhaustive search for a matching converter.
* If no converter matches, returns the default converter.
* @param sourceType the source type to convert from
* @param targetType the target type to convert to
* @return the generic converter that will perform the conversion,
* or {@code null} if no suitable converter was found
* @see #getDefaultConverter(TypeDescriptor, TypeDescriptor)
*/
@Nullable
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
GenericConverter converter = this.converterCache.get(key);
if (converter != null) {
return (converter != NO_MATCH ? converter : null);
}
converter = this.converters.find(sourceType, targetType);
if (converter == null) {
converter = getDefaultConverter(sourceType, targetType);
}
if (converter != null) {
this.converterCache.put(key, converter);
return converter;
}
this.converterCache.put(key, NO_MATCH);
return null;
}
private Object convert(String source, TypeDescriptor sourceType,
TypeDescriptor targetType) {
Delimiter delimiter = targetType.getAnnotation(Delimiter.class);
String[] elements = getElements(source,
(delimiter != null) ? delimiter.value() : ",");
TypeDescriptor elementDescriptor = targetType.getElementTypeDescriptor();
Collection<Object> target = createCollection(targetType, elementDescriptor,
elements.length);
Stream<Object> stream = Arrays.stream(elements).map(String::trim);
if (elementDescriptor != null) {
stream = stream.map((element) -> this.conversionService.convert(element,
sourceType, elementDescriptor));
}
stream.forEach(target::add);
return target;
}
@Test
public void collectionMapSourceTarget() throws Exception {
Map<String, List<String>> map = new HashMap<>();
map.put("1", Arrays.asList("9", "12"));
map.put("2", Arrays.asList("37", "23"));
TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("sourceCollectionMapTarget"));
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget"));
assertFalse(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
fail("Should have failed");
}
catch (ConverterNotFoundException ex) {
// expected
}
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
Map<Integer, List<Integer>> result = (Map<Integer, List<Integer>>) conversionService.convert(map, sourceType, targetType);
assertFalse(map.equals(result));
assertEquals(Arrays.asList(9, 12), result.get(1));
assertEquals(Arrays.asList(37, 23), result.get(2));
}
@Override
public TypedValue execute(EvaluationContext context, Object target, Object... arguments)
throws AccessException {
try {
Method m = HasRoleExecutor.class.getMethod("hasRole", String[].class);
Object[] args = arguments;
if (args != null) {
ReflectionHelper.convertAllArguments(tc, args, m);
}
if (m.isVarArgs()) {
args = ReflectionHelper.setupArgumentsForVarargsInvocation(m.getParameterTypes(), args);
}
return new TypedValue(m.invoke(null, args), new TypeDescriptor(new MethodParameter(m,-1)));
}
catch (Exception ex) {
throw new AccessException("Problem invoking hasRole", ex);
}
}
@Nullable
private TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
Class<?> type = (target instanceof Class ? (Class<?>) target : target.getClass());
if (type.isArray() && name.equals("length")) {
return TypeDescriptor.valueOf(Integer.TYPE);
}
PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class);
TypeDescriptor typeDescriptor = this.typeDescriptorCache.get(cacheKey);
if (typeDescriptor == null) {
// Attempt to populate the cache entry
try {
if (canRead(context, target, name) || canWrite(context, target, name)) {
typeDescriptor = this.typeDescriptorCache.get(cacheKey);
}
}
catch (AccessException ex) {
// Continue with null type descriptor
}
}
return typeDescriptor;
}
@Override
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
Class<?> sourceClazz = sourceType.getType();
AccessibleObject accessibleObject = ENUM_CACHE_MAP.computeIfAbsent(sourceClazz, EnumToStringConverter::getAnnotation);
Class<?> targetClazz = targetType.getType();
// 如果为null,走默认的转换
if (accessibleObject == null) {
if (String.class == targetClazz) {
return ((Enum) source).name();
}
int ordinal = ((Enum) source).ordinal();
return ConvertUtil.convert(ordinal, targetClazz);
}
try {
return EnumToStringConverter.invoke(sourceClazz, accessibleObject, source, targetClazz);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
@Test
public void multipleCollectionTypesFromSameSourceType() throws Exception {
conversionService.addConverter(new MyStringToRawCollectionConverter());
conversionService.addConverter(new MyStringToGenericCollectionConverter());
conversionService.addConverter(new MyStringToStringCollectionConverter());
conversionService.addConverter(new MyStringToIntegerCollectionConverter());
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection"))));
assertEquals(Collections.singleton(4),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection"))));
assertEquals(Collections.singleton(4),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection"))));
assertEquals(Collections.singleton(4),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection"))));
assertEquals(Collections.singleton(4),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection"))));
assertEquals(Collections.singleton("testX"),
conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection"))));
}
@Test
public void testCustomFormatter() throws Exception {
FormattingConversionServiceFactoryBean factory = new FormattingConversionServiceFactoryBean();
Set<Object> formatters = new HashSet<>();
formatters.add(new TestBeanFormatter());
formatters.add(new SpecialIntAnnotationFormatterFactory());
factory.setFormatters(formatters);
factory.afterPropertiesSet();
FormattingConversionService fcs = factory.getObject();
TestBean testBean = fcs.convert("5", TestBean.class);
assertEquals(5, testBean.getSpecialInt());
assertEquals("5", fcs.convert(testBean, String.class));
TypeDescriptor descriptor = new TypeDescriptor(TestBean.class.getDeclaredField("specialInt"));
Object value = fcs.convert(":5", TypeDescriptor.valueOf(String.class), descriptor);
assertEquals(5, value);
value = fcs.convert(5, descriptor, TypeDescriptor.valueOf(String.class));
assertEquals(":5", value);
}
@Override
public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException {
try {
if (arguments != null) {
this.argumentConversionOccurred = ReflectionHelper.convertArguments(
context.getTypeConverter(), arguments, this.method, this.varargsPosition);
if (this.method.isVarArgs()) {
arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(
this.method.getParameterTypes(), arguments);
}
}
ReflectionUtils.makeAccessible(this.method);
Object value = this.method.invoke(target, arguments);
return new TypedValue(value, new TypeDescriptor(new MethodParameter(this.method, -1)).narrow(value));
}
catch (Exception ex) {
throw new AccessException("Problem invoking method: " + this.method, ex);
}
}
/**
* Create a model attribute from a String request value (e.g. URI template
* variable, request parameter) using type conversion.
* <p>The default implementation converts only if there a registered
* {@link org.springframework.core.convert.converter.Converter} that can perform the conversion.
*
* @param sourceValue the source value to create the model attribute from
* @param attributeName the name of the attribute, never {@code null}
* @param parameter the method parameter
* @param binderFactory for creating WebDataBinder instance
* @param request the current request
* @return the created model attribute, or {@code null}
* @throws Exception
*/
protected Object createAttributeFromRequestValue(String sourceValue,
String attributeName,
MethodParameter parameter,
WebDataBinderFactory binderFactory,
NativeWebRequest request) throws Exception {
DataBinder binder = binderFactory.createBinder(request, null, attributeName);
ConversionService conversionService = binder.getConversionService();
if (conversionService != null) {
TypeDescriptor source = TypeDescriptor.valueOf(String.class);
TypeDescriptor target = new TypeDescriptor(parameter);
if (conversionService.canConvert(source, target)) {
return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter);
}
}
return null;
}
@Override
public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return Optional.empty();
}
else if (source instanceof Optional) {
return source;
}
else if (targetType.getResolvableType().hasGenerics()) {
Object target = this.conversionService.convert(source, sourceType, new GenericTypeDescriptor(targetType));
if (target == null || (target.getClass().isArray() && Array.getLength(target) == 0) ||
(target instanceof Collection && ((Collection<?>) target).isEmpty())) {
return Optional.empty();
}
return Optional.of(target);
}
else {
return Optional.of(source);
}
}
@Test
public void collectionMap() throws Exception {
Map<String, List<String>> map = new HashMap<>();
map.put("1", Arrays.asList("9", "12"));
map.put("2", Arrays.asList("37", "23"));
TypeDescriptor sourceType = TypeDescriptor.forObject(map);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget"));
assertTrue(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
}
catch (ConversionFailedException ex) {
assertTrue(ex.getCause() instanceof ConverterNotFoundException);
}
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
Map<Integer, List<Integer>> result = (Map<Integer, List<Integer>>) conversionService.convert(map, sourceType, targetType);
assertFalse(map.equals(result));
assertEquals(Arrays.asList(9, 12), result.get(1));
assertEquals(Arrays.asList(37, 23), result.get(2));
}
@Test
@SuppressWarnings("unchecked")
public void stringToCollection() throws Exception {
List<List<String>> list = new ArrayList<>();
list.add(Arrays.asList("9,12"));
list.add(Arrays.asList("37,23"));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
conversionService.addConverter(new StringToCollectionConverter(conversionService));
conversionService.addConverter(new ObjectToCollectionConverter(conversionService));
conversionService.addConverter(new CollectionToObjectConverter(conversionService));
TypeDescriptor sourceType = TypeDescriptor.forObject(list);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("objectToCollection"));
assertTrue(conversionService.canConvert(sourceType, targetType));
List<List<List<Integer>>> result = (List<List<List<Integer>>>) conversionService.convert(list, sourceType, targetType);
assertEquals((Integer) 9, result.get(0).get(0).get(0));
assertEquals((Integer) 12, result.get(0).get(0).get(1));
assertEquals((Integer) 37, result.get(1).get(0).get(0));
assertEquals((Integer) 23, result.get(1).get(0).get(1));
}
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
for (Class<?> interfaceType : ClassUtils.getAllInterfacesForClass(sourceType.getType())) {
if (this.conversionService.canConvert(TypeDescriptor.valueOf(interfaceType), targetType)) {
return false;
}
}
return true;
}
@Override
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
Class<?> paramType = parameter.getParameterType();
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
Object arg = resolveArgumentInternal(parameter, message, namedValueInfo.name);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
arg = resolveDefaultValue(namedValueInfo.defaultValue);
}
else if (namedValueInfo.required && !parameter.getParameterType().getName().equals("java.util.Optional")) {
handleMissingValue(namedValueInfo.name, parameter, message);
}
arg = handleNullValue(namedValueInfo.name, arg, paramType);
}
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveDefaultValue(namedValueInfo.defaultValue);
}
if (!ClassUtils.isAssignableValue(paramType, arg)) {
arg = this.conversionService.convert(
arg, TypeDescriptor.valueOf(arg.getClass()), new TypeDescriptor(parameter));
}
handleResolvedValue(arg, namedValueInfo.name, parameter, message);
return arg;
}
@Override
@Nullable
public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field)
throws TypeMismatchException {
return convertIfNecessary(value, requiredType,
(field != null ? new TypeDescriptor(field) : TypeDescriptor.valueOf(requiredType)));
}
@Test
public void convertFromStreamToArrayNoConverter() throws NoSuchFieldException {
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
TypeDescriptor arrayOfLongs = new TypeDescriptor(Types.class.getField("arrayOfLongs"));
thrown.expect(ConversionFailedException.class);
thrown.expectCause(is(instanceOf(ConverterNotFoundException.class)));
this.conversionService.convert(stream, arrayOfLongs);
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
Collection<?> sourceCollection = (Collection<?>) source;
Object array = Array.newInstance(targetType.getElementTypeDescriptor().getType(), sourceCollection.size());
int i = 0;
for (Object sourceElement : sourceCollection) {
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor());
Array.set(array, i++, targetElement);
}
return array;
}
@Test
public void convertCollectionToObjectAssignableTarget() throws Exception {
Collection<String> source = new ArrayList<String>();
source.add("foo");
Object result = conversionService.convert(source, new TypeDescriptor(getClass().getField("assignableTarget")));
assertEquals(source, result);
}
@Test
public void dateToStringWithGlobalFormat() {
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
registrar.setFormatter(new DateFormatter());
setup(registrar);
Date date = new Date();
Object actual = this.conversionService.convert(date, TypeDescriptor.valueOf(Date.class), TypeDescriptor.valueOf(String.class));
String expected = new DateFormatter().print(date, Locale.US);
assertEquals(expected, actual);
}
@Override
public TypeDescriptor getPropertyTypeDescriptor(String propertyName)
throws BeansException {
if(mapData){
return null;
}else{
return super.getPropertyTypeDescriptor(propertyName);
}
}
@Override
@Nullable
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
Assert.notNull(context, "EvaluationContext is required");
ExpressionState expressionState = new ExpressionState(context, this.configuration);
return this.ast.getValueInternal(expressionState).getTypeDescriptor();
}
@Test
public void emptyListToArray() {
conversionService.addConverter(new CollectionToArrayConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
List<String> list = new ArrayList<>();
TypeDescriptor sourceType = TypeDescriptor.forObject(list);
TypeDescriptor targetType = TypeDescriptor.valueOf(String[].class);
assertTrue(conversionService.canConvert(sourceType, targetType));
assertEquals(0, ((String[]) conversionService.convert(list, sourceType, targetType)).length);
}
@Override
@Nullable
public Class<?> getValueType(EvaluationContext context) throws EvaluationException {
Assert.notNull(context, "EvaluationContext is required");
ExpressionState expressionState = new ExpressionState(context, this.configuration);
TypeDescriptor typeDescriptor = this.ast.getValueInternal(expressionState).getTypeDescriptor();
return (typeDescriptor != null ? typeDescriptor.getType() : null);
}
@Test
public void emptyListToListDifferentTargetType() throws Exception {
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
List<String> list = new ArrayList<>();
TypeDescriptor sourceType = TypeDescriptor.forObject(list);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyListDifferentTarget"));
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
LinkedList<Integer> result = (LinkedList<Integer>) conversionService.convert(list, sourceType, targetType);
assertEquals(LinkedList.class, result.getClass());
assertTrue(result.isEmpty());
}
private void populateReferenceTypeArray(ExpressionState state, Object newArray, TypeConverter typeConverter,
InlineList initializer, Class<?> componentType) {
TypeDescriptor toTypeDescriptor = TypeDescriptor.valueOf(componentType);
Object[] newObjectArray = (Object[]) newArray;
for (int i = 0; i < newObjectArray.length; i++) {
SpelNode elementNode = initializer.getChild(i);
Object arrayEntry = elementNode.getValue(state);
newObjectArray[i] = typeConverter.convertValue(arrayEntry,
TypeDescriptor.forObject(arrayEntry), toTypeDescriptor);
}
}
@Override
public Object convert(Object source, TypeDescriptor sourceType,
TypeDescriptor targetType) {
if (source == null) {
return null;
}
return convert((String) source, sourceType, targetType);
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
if (!(source instanceof Artifact)) {
throw new IllegalStateException("Source must be an Artifact");
}
return ((Artifact) source).getArtifactKey().getKey();
}
@Test(expected = ConversionFailedException.class)
public void nothingInCommon() throws Exception {
List<Object> resources = new ArrayList<>();
resources.add(new ClassPathResource("test"));
resources.add(3);
TypeDescriptor sourceType = TypeDescriptor.forObject(resources);
assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources"))));
}
@Test
public void dateToStringWithFormat() {
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
registrar.setDateTimeFormatter(org.joda.time.format.DateTimeFormat.shortDateTime());
setup(registrar);
Date date = new Date();
Object actual = this.conversionService.convert(date, TypeDescriptor.valueOf(Date.class), TypeDescriptor.valueOf(String.class));
String expected = JodaTimeContextHolder.getFormatter(org.joda.time.format.DateTimeFormat.shortDateTime(), Locale.US).print(new DateTime(date));
assertEquals(expected, actual);
}