001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.convert.support; 018 019import java.nio.charset.Charset; 020import java.util.Currency; 021import java.util.Locale; 022import java.util.UUID; 023 024import org.springframework.core.convert.ConversionService; 025import org.springframework.core.convert.converter.ConverterRegistry; 026import org.springframework.lang.Nullable; 027 028/** 029 * A specialization of {@link GenericConversionService} configured by default 030 * with converters appropriate for most environments. 031 * 032 * <p>Designed for direct instantiation but also exposes the static 033 * {@link #addDefaultConverters(ConverterRegistry)} utility method for ad-hoc 034 * use against any {@code ConverterRegistry} instance. 035 * 036 * @author Chris Beams 037 * @author Juergen Hoeller 038 * @author Stephane Nicoll 039 * @since 3.1 040 */ 041public class DefaultConversionService extends GenericConversionService { 042 043 @Nullable 044 private static volatile DefaultConversionService sharedInstance; 045 046 047 /** 048 * Create a new {@code DefaultConversionService} with the set of 049 * {@linkplain DefaultConversionService#addDefaultConverters(ConverterRegistry) default converters}. 050 */ 051 public DefaultConversionService() { 052 addDefaultConverters(this); 053 } 054 055 056 /** 057 * Return a shared default {@code ConversionService} instance, 058 * lazily building it once needed. 059 * <p><b>NOTE:</b> We highly recommend constructing individual 060 * {@code ConversionService} instances for customization purposes. 061 * This accessor is only meant as a fallback for code paths which 062 * need simple type coercion but cannot access a longer-lived 063 * {@code ConversionService} instance any other way. 064 * @return the shared {@code ConversionService} instance (never {@code null}) 065 * @since 4.3.5 066 */ 067 public static ConversionService getSharedInstance() { 068 DefaultConversionService cs = sharedInstance; 069 if (cs == null) { 070 synchronized (DefaultConversionService.class) { 071 cs = sharedInstance; 072 if (cs == null) { 073 cs = new DefaultConversionService(); 074 sharedInstance = cs; 075 } 076 } 077 } 078 return cs; 079 } 080 081 /** 082 * Add converters appropriate for most environments. 083 * @param converterRegistry the registry of converters to add to 084 * (must also be castable to ConversionService, e.g. being a {@link ConfigurableConversionService}) 085 * @throws ClassCastException if the given ConverterRegistry could not be cast to a ConversionService 086 */ 087 public static void addDefaultConverters(ConverterRegistry converterRegistry) { 088 addScalarConverters(converterRegistry); 089 addCollectionConverters(converterRegistry); 090 091 converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry)); 092 converterRegistry.addConverter(new StringToTimeZoneConverter()); 093 converterRegistry.addConverter(new ZoneIdToTimeZoneConverter()); 094 converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter()); 095 096 converterRegistry.addConverter(new ObjectToObjectConverter()); 097 converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry)); 098 converterRegistry.addConverter(new FallbackObjectToStringConverter()); 099 converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry)); 100 } 101 102 /** 103 * Add common collection converters. 104 * @param converterRegistry the registry of converters to add to 105 * (must also be castable to ConversionService, e.g. being a {@link ConfigurableConversionService}) 106 * @throws ClassCastException if the given ConverterRegistry could not be cast to a ConversionService 107 * @since 4.2.3 108 */ 109 public static void addCollectionConverters(ConverterRegistry converterRegistry) { 110 ConversionService conversionService = (ConversionService) converterRegistry; 111 112 converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService)); 113 converterRegistry.addConverter(new CollectionToArrayConverter(conversionService)); 114 115 converterRegistry.addConverter(new ArrayToArrayConverter(conversionService)); 116 converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService)); 117 converterRegistry.addConverter(new MapToMapConverter(conversionService)); 118 119 converterRegistry.addConverter(new ArrayToStringConverter(conversionService)); 120 converterRegistry.addConverter(new StringToArrayConverter(conversionService)); 121 122 converterRegistry.addConverter(new ArrayToObjectConverter(conversionService)); 123 converterRegistry.addConverter(new ObjectToArrayConverter(conversionService)); 124 125 converterRegistry.addConverter(new CollectionToStringConverter(conversionService)); 126 converterRegistry.addConverter(new StringToCollectionConverter(conversionService)); 127 128 converterRegistry.addConverter(new CollectionToObjectConverter(conversionService)); 129 converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService)); 130 131 converterRegistry.addConverter(new StreamConverter(conversionService)); 132 } 133 134 private static void addScalarConverters(ConverterRegistry converterRegistry) { 135 converterRegistry.addConverterFactory(new NumberToNumberConverterFactory()); 136 137 converterRegistry.addConverterFactory(new StringToNumberConverterFactory()); 138 converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter()); 139 140 converterRegistry.addConverter(new StringToCharacterConverter()); 141 converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter()); 142 143 converterRegistry.addConverter(new NumberToCharacterConverter()); 144 converterRegistry.addConverterFactory(new CharacterToNumberFactory()); 145 146 converterRegistry.addConverter(new StringToBooleanConverter()); 147 converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter()); 148 149 converterRegistry.addConverterFactory(new StringToEnumConverterFactory()); 150 converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry)); 151 152 converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory()); 153 converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry)); 154 155 converterRegistry.addConverter(new StringToLocaleConverter()); 156 converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter()); 157 158 converterRegistry.addConverter(new StringToCharsetConverter()); 159 converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter()); 160 161 converterRegistry.addConverter(new StringToCurrencyConverter()); 162 converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter()); 163 164 converterRegistry.addConverter(new StringToPropertiesConverter()); 165 converterRegistry.addConverter(new PropertiesToStringConverter()); 166 167 converterRegistry.addConverter(new StringToUUIDConverter()); 168 converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter()); 169 } 170 171}