All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.data.convert.SimplePropertyValueConversions Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2022-2024 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.data.convert;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.convert.PropertyValueConverterFactories.ChainedPropertyValueConverterFactory;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
 * {@link PropertyValueConversions} implementation allowing a {@link PropertyValueConverterFactory} creating
 * {@link PropertyValueConverter converters} to be chosen. Activating {@link #setConverterCacheEnabled(boolean) caching}
 * allows converters to be reused.
 * 

* Providing a {@link SimplePropertyValueConverterRegistry} adds path configured converter instances. *

* This class should be {@link #afterPropertiesSet() initialized}. If not, {@link #init()} will be called on the first * attempt of {@link PropertyValueConverter converter} retrieval. * * @author Christoph Strobl * @author Mark Paluch * @see PropertyValueConversions * @see InitializingBean * @since 2.7 */ public class SimplePropertyValueConversions implements PropertyValueConversions, InitializingBean { private static final String NO_CONVERTER_FACTORY_ERROR_MESSAGE = "PropertyValueConverterFactory is not set; Make sure to either set the converter factory or call afterPropertiesSet() to initialize the object"; private boolean converterCacheEnabled = true; private @Nullable PropertyValueConverterFactory converterFactory; private @Nullable ValueConverterRegistry valueConverterRegistry; private volatile Map, PropertyValueConverter> converterCache = new HashMap<>(); @SuppressWarnings("rawtypes") enum NoOpConverter implements PropertyValueConverter { INSTANCE; @Override public Object read(Object value, ValueConversionContext context) { return null; } @Override public Object write(Object value, ValueConversionContext context) { return null; } } /** * Set the {@link PropertyValueConverterFactory} responsible for creating the actual {@link PropertyValueConverter}. * * @param converterFactory {@link PropertyValueConverterFactory} used to create the actual * {@link PropertyValueConverter}. * @see PropertyValueConverterFactory */ public void setConverterFactory(@Nullable PropertyValueConverterFactory converterFactory) { this.converterFactory = converterFactory; } /** * Returns the configured {@link PropertyValueConverterFactory} responsible for creating the actual * {@link PropertyValueConverter}. * * @return the configured {@link PropertyValueConverterFactory}; can be {@literal null}. * @see PropertyValueConverterFactory */ @Nullable public PropertyValueConverterFactory getConverterFactory() { return converterFactory; } private PropertyValueConverterFactory requireConverterFactory() { PropertyValueConverterFactory factory = getConverterFactory(); Assert.state(factory != null, NO_CONVERTER_FACTORY_ERROR_MESSAGE); return factory; } /** * Set the {@link ValueConverterRegistry converter registry} used for path configured converters. *

* This is short for adding a * {@link org.springframework.data.convert.PropertyValueConverterFactories.ConfiguredInstanceServingValueConverterFactory} * at the end of a {@link ChainedPropertyValueConverterFactory}. * * @param valueConverterRegistry registry of {@link PropertyValueConverter PropertyValueConverters}. * @see ValueConverterRegistry */ public void setValueConverterRegistry(@Nullable ValueConverterRegistry valueConverterRegistry) { this.valueConverterRegistry = valueConverterRegistry; } /** * Get the {@link ValueConverterRegistry} used for path configured converters. * * @return the configured {@link ValueConverterRegistry}; can be {@literal null}. * @see ValueConverterRegistry */ @Nullable public ValueConverterRegistry getValueConverterRegistry() { return valueConverterRegistry; } /** * Configure whether to use converter the cache. Enabled by default. * * @param converterCacheEnabled set to {@literal true} to enable caching of {@link PropertyValueConverter converter} * instances. */ public void setConverterCacheEnabled(boolean converterCacheEnabled) { this.converterCacheEnabled = converterCacheEnabled; } /** * Determines whether a {@link PropertyValueConverter} has been registered for the given {@link PersistentProperty * property}. * * @param property {@link PersistentProperty} to evaluate. * @return {@literal true} if a {@link PropertyValueConverter} has been registered for the given * {@link PersistentProperty property}. * @see PersistentProperty */ @Override public boolean hasValueConverter(PersistentProperty property) { return doGetConverter(property) != null; } @Override public , D extends ValueConversionContext

> PropertyValueConverter getValueConverter( P property) { PropertyValueConverter converter = doGetConverter(property); Assert.notNull(converter, String.format("No PropertyValueConverter registered for %s", property)); return converter; } @SuppressWarnings("unchecked") @Nullable private , D extends ValueConversionContext

> PropertyValueConverter doGetConverter( PersistentProperty property) { PropertyValueConverter converter = converterCache.get(property); if (converter == null) { synchronized (this) { PropertyValueConverter fromCache = converterCache.get(property); if (fromCache != null) { converter = fromCache; } else { converter = requireConverterFactory().getConverter(property); Map, PropertyValueConverter> converterCache = new HashMap<>( this.converterCache); converterCache.put(property, converter != null ? converter : NoOpConverter.INSTANCE); this.converterCache = converterCache; } } } if (converter == NoOpConverter.INSTANCE) { return null; } return (PropertyValueConverter) converter; } /** * May be called just once to initialize the underlying factory with its values. */ public void init() { List factoryList = new ArrayList<>(3); factoryList.add(resolveConverterFactory()); resolveConverterRegistryAsConverterFactory().ifPresent(factoryList::add); PropertyValueConverterFactory targetFactory = factoryList.size() > 1 ? PropertyValueConverterFactory.chained(factoryList) : factoryList.iterator().next(); this.converterFactory = converterCacheEnabled ? PropertyValueConverterFactory.caching(targetFactory) : targetFactory; } private PropertyValueConverterFactory resolveConverterFactory() { PropertyValueConverterFactory converterFactory = getConverterFactory(); return converterFactory != null ? converterFactory : PropertyValueConverterFactory.simple(); } private Optional resolveConverterRegistryAsConverterFactory() { return Optional.ofNullable(getValueConverterRegistry()).filter(it -> !it.isEmpty()) .map(PropertyValueConverterFactory::configuredInstance); } /** * Initializes this {@link SimplePropertyValueConversions} instance. * * @see #init() */ @Override public void afterPropertiesSet() { init(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy