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}