org.springframework.data.relational.core.conversion.BasicRelationalConverter Maven / Gradle / Ivy
Show all versions of spring-data-relational Show documentation
/*
* Copyright 2018-2023 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.relational.core.conversion;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.CustomConversions.StoreConversions;
import org.springframework.data.mapping.Parameter;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mapping.model.EntityInstantiators;
import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* {@link RelationalConverter} that uses a {@link MappingContext} to apply basic conversion of relational values to
* property values.
*
* Conversion is configurable by providing a customized {@link CustomConversions}.
*
* @author Mark Paluch
* @author Jens Schauder
* @author Chirag Tailor
* @see MappingContext
* @see SimpleTypeHolder
* @see CustomConversions
*/
public class BasicRelationalConverter implements RelationalConverter {
private final MappingContext, RelationalPersistentProperty> context;
private final ConfigurableConversionService conversionService;
private final EntityInstantiators entityInstantiators;
private final CustomConversions conversions;
/**
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext}.
*
* @param context must not be {@literal null}.
*/
public BasicRelationalConverter(
MappingContext, ? extends RelationalPersistentProperty> context) {
this(context, new CustomConversions(StoreConversions.NONE, Collections.emptyList()), new DefaultConversionService(),
new EntityInstantiators());
}
/**
* Creates a new {@link BasicRelationalConverter} given {@link MappingContext} and {@link CustomConversions}.
*
* @param context must not be {@literal null}.
* @param conversions must not be {@literal null}.
*/
public BasicRelationalConverter(
MappingContext, ? extends RelationalPersistentProperty> context,
CustomConversions conversions) {
this(context, conversions, new DefaultConversionService(), new EntityInstantiators());
}
@SuppressWarnings("unchecked")
private BasicRelationalConverter(
MappingContext, ? extends RelationalPersistentProperty> context,
CustomConversions conversions, ConfigurableConversionService conversionService,
EntityInstantiators entityInstantiators) {
Assert.notNull(context, "MappingContext must not be null!");
Assert.notNull(conversions, "CustomConversions must not be null!");
this.context = (MappingContext) context;
this.conversionService = conversionService;
this.entityInstantiators = entityInstantiators;
this.conversions = conversions;
conversions.registerConvertersIn(this.conversionService);
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.conversion.RelationalConverter#getConversionService()
*/
@Override
public ConversionService getConversionService() {
return conversionService;
}
public CustomConversions getConversions() {
return conversions;
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.conversion.RelationalConverter#getMappingContext()
*/
@Override
public MappingContext, ? extends RelationalPersistentProperty> getMappingContext() {
return context;
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.conversion.RelationalConverter#getPropertyAccessor(org.springframework.data.mapping.PersistentEntity, java.lang.Object)
*/
@Override
public PersistentPropertyAccessor getPropertyAccessor(PersistentEntity persistentEntity, T instance) {
PersistentPropertyAccessor accessor = persistentEntity.getPropertyAccessor(instance);
return new ConvertingPropertyAccessor<>(accessor, conversionService);
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.conversion.RelationalConverter#createInstance(org.springframework.data.mapping.PersistentEntity, java.util.function.Function)
*/
@Override
public T createInstance(PersistentEntity entity,
Function, Object> parameterValueProvider) {
return entityInstantiators.getInstantiatorFor(entity) //
.createInstance(entity, new ConvertingParameterValueProvider<>(parameterValueProvider));
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.conversion.RelationalConverter#readValue(java.lang.Object, org.springframework.data.util.TypeInformation)
*/
@Override
@Nullable
public Object readValue(@Nullable Object value, TypeInformation type) {
if (null == value) {
return null;
}
if (getConversions().hasCustomReadTarget(value.getClass(), type.getType())) {
TypeDescriptor sourceDescriptor = TypeDescriptor.valueOf(value.getClass());
TypeDescriptor targetDescriptor = createTypeDescriptor(type);
return getConversionService().convert(value, sourceDescriptor, targetDescriptor);
}
return getPotentiallyConvertedSimpleRead(value, type);
}
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.conversion.RelationalConverter#writeValue(java.lang.Object, org.springframework.data.util.TypeInformation)
*/
@Override
@Nullable
public Object writeValue(@Nullable Object value, TypeInformation type) {
if (value == null) {
return null;
}
if (getConversions().isSimpleType(value.getClass())) {
if (ClassTypeInformation.OBJECT != type) {
if (conversionService.canConvert(value.getClass(), type.getType())) {
value = conversionService.convert(value, type.getType());
}
}
return getPotentiallyConvertedSimpleWrite(value);
}
// TODO: We should add conversion support for arrays, however,
// these should consider multi-dimensional arrays as well.
if (value.getClass().isArray() && (ClassTypeInformation.OBJECT.equals(type) || type.isCollectionLike())) {
return value;
}
if (value instanceof Collection) {
List