Browse Source
Restructured reading conversion process into: - converting technology base types (JDBC Arrays). - standard and custom conversions. - module specific conversions (AggregateReference). Closes #1828 Original pull request #2062pull/2076/merge
9 changed files with 248 additions and 449 deletions
@ -1,136 +0,0 @@
@@ -1,136 +0,0 @@
|
||||
/* |
||||
* Copyright 2021-2025 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.jdbc.core.convert; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.core.convert.ConversionService; |
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
import org.springframework.core.convert.converter.GenericConverter; |
||||
import org.springframework.data.convert.ReadingConverter; |
||||
import org.springframework.data.convert.WritingConverter; |
||||
import org.springframework.data.jdbc.core.mapping.AggregateReference; |
||||
import org.springframework.lang.Nullable; |
||||
|
||||
/** |
||||
* Converters for aggregate references. They need a {@link ConversionService} in order to delegate the conversion of the |
||||
* content of the {@link AggregateReference}. |
||||
* |
||||
* @author Jens Schauder |
||||
* @author Mark Paluch |
||||
* @since 2.3 |
||||
*/ |
||||
class AggregateReferenceConverters { |
||||
|
||||
/** |
||||
* Returns the converters to be registered. |
||||
* |
||||
* @return a collection of converters. Guaranteed to be not {@literal null}. |
||||
*/ |
||||
public static Collection<GenericConverter> getConvertersToRegister(ConversionService conversionService) { |
||||
|
||||
return Arrays.asList(new AggregateReferenceToSimpleTypeConverter(conversionService), |
||||
new SimpleTypeToAggregateReferenceConverter(conversionService)); |
||||
} |
||||
|
||||
/** |
||||
* Converts from an AggregateReference to its id, leaving the conversion of the id to the ultimate target type to the |
||||
* delegate {@link ConversionService}. |
||||
*/ |
||||
@WritingConverter |
||||
private static class AggregateReferenceToSimpleTypeConverter implements GenericConverter { |
||||
|
||||
private static final Set<ConvertiblePair> CONVERTIBLE_TYPES = Collections |
||||
.singleton(new ConvertiblePair(AggregateReference.class, Object.class)); |
||||
|
||||
private final ConversionService delegate; |
||||
|
||||
AggregateReferenceToSimpleTypeConverter(ConversionService delegate) { |
||||
this.delegate = delegate; |
||||
} |
||||
|
||||
@Override |
||||
public Set<ConvertiblePair> getConvertibleTypes() { |
||||
return CONVERTIBLE_TYPES; |
||||
} |
||||
|
||||
@Override |
||||
public Object convert(@Nullable Object source, TypeDescriptor sourceDescriptor, TypeDescriptor targetDescriptor) { |
||||
|
||||
if (source == null) { |
||||
return null; |
||||
} |
||||
|
||||
// if the target type is an AggregateReference we are going to assume it is of the correct type,
|
||||
// because it was already converted.
|
||||
Class<?> objectType = targetDescriptor.getObjectType(); |
||||
if (objectType.isAssignableFrom(AggregateReference.class)) { |
||||
return source; |
||||
} |
||||
|
||||
Object id = ((AggregateReference<?, ?>) source).getId(); |
||||
|
||||
if (id == null) { |
||||
throw new IllegalStateException( |
||||
String.format("Aggregate references id must not be null when converting to %s from %s to %s", source, |
||||
sourceDescriptor, targetDescriptor)); |
||||
} |
||||
|
||||
return delegate.convert(id, TypeDescriptor.valueOf(id.getClass()), targetDescriptor); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Convert any simple type to an {@link AggregateReference}. If the {@literal targetDescriptor} contains information |
||||
* about the generic type id will properly get converted to the desired type by the delegate |
||||
* {@link ConversionService}. |
||||
*/ |
||||
@ReadingConverter |
||||
private static class SimpleTypeToAggregateReferenceConverter implements GenericConverter { |
||||
|
||||
private static final Set<ConvertiblePair> CONVERTIBLE_TYPES = Collections |
||||
.singleton(new ConvertiblePair(Object.class, AggregateReference.class)); |
||||
|
||||
private final ConversionService delegate; |
||||
|
||||
SimpleTypeToAggregateReferenceConverter(ConversionService delegate) { |
||||
this.delegate = delegate; |
||||
} |
||||
|
||||
@Override |
||||
public Set<ConvertiblePair> getConvertibleTypes() { |
||||
return CONVERTIBLE_TYPES; |
||||
} |
||||
|
||||
@Override |
||||
public Object convert(@Nullable Object source, TypeDescriptor sourceDescriptor, TypeDescriptor targetDescriptor) { |
||||
|
||||
if (source == null) { |
||||
return null; |
||||
} |
||||
|
||||
ResolvableType componentType = targetDescriptor.getResolvableType().getGenerics()[1]; |
||||
TypeDescriptor targetType = TypeDescriptor.valueOf(componentType.resolve()); |
||||
Object convertedId = delegate.convert(source, TypeDescriptor.valueOf(source.getClass()), targetType); |
||||
|
||||
return AggregateReference.to(convertedId); |
||||
} |
||||
} |
||||
} |
||||
@ -1,99 +0,0 @@
@@ -1,99 +0,0 @@
|
||||
/* |
||||
* Copyright 2021-2025 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.jdbc.core.convert; |
||||
|
||||
import static org.assertj.core.api.Assertions.*; |
||||
|
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.core.convert.TypeDescriptor; |
||||
import org.springframework.core.convert.support.ConfigurableConversionService; |
||||
import org.springframework.core.convert.support.DefaultConversionService; |
||||
import org.springframework.data.jdbc.core.mapping.AggregateReference; |
||||
|
||||
/** |
||||
* Tests for converters from an to {@link org.springframework.data.jdbc.core.mapping.AggregateReference}. |
||||
* |
||||
* @author Jens Schauder |
||||
* @author Mark Paluch |
||||
*/ |
||||
class AggregateReferenceConvertersUnitTests { |
||||
|
||||
ConfigurableConversionService conversionService; |
||||
|
||||
@BeforeEach |
||||
void setUp() { |
||||
conversionService = new DefaultConversionService(); |
||||
AggregateReferenceConverters.getConvertersToRegister(DefaultConversionService.getSharedInstance()) |
||||
.forEach(it -> conversionService.addConverter(it)); |
||||
} |
||||
|
||||
@Test // GH-992
|
||||
void convertsFromSimpleValue() { |
||||
|
||||
ResolvableType aggregateReferenceWithIdTypeInteger = ResolvableType.forClassWithGenerics(AggregateReference.class, |
||||
String.class, Integer.class); |
||||
Object converted = conversionService.convert(23, TypeDescriptor.forObject(23), |
||||
new TypeDescriptor(aggregateReferenceWithIdTypeInteger, null, null)); |
||||
|
||||
assertThat(converted).isEqualTo(AggregateReference.to(23)); |
||||
} |
||||
|
||||
@Test // GH-992
|
||||
void convertsFromSimpleValueThatNeedsSeparateConversion() { |
||||
|
||||
ResolvableType aggregateReferenceWithIdTypeInteger = ResolvableType.forClassWithGenerics(AggregateReference.class, |
||||
String.class, Long.class); |
||||
Object converted = conversionService.convert(23, TypeDescriptor.forObject(23), |
||||
new TypeDescriptor(aggregateReferenceWithIdTypeInteger, null, null)); |
||||
|
||||
assertThat(converted).isEqualTo(AggregateReference.to(23L)); |
||||
} |
||||
|
||||
@Test // GH-992
|
||||
void convertsFromSimpleValueWithMissingTypeInformation() { |
||||
|
||||
Object converted = conversionService.convert(23, TypeDescriptor.forObject(23), |
||||
TypeDescriptor.valueOf(AggregateReference.class)); |
||||
|
||||
assertThat(converted).isEqualTo(AggregateReference.to(23)); |
||||
} |
||||
|
||||
@Test // GH-992
|
||||
void convertsToSimpleValue() { |
||||
|
||||
AggregateReference<Object, Integer> source = AggregateReference.to(23); |
||||
|
||||
Object converted = conversionService.convert(source, TypeDescriptor.forObject(source), |
||||
TypeDescriptor.valueOf(Integer.class)); |
||||
|
||||
assertThat(converted).isEqualTo(23); |
||||
} |
||||
|
||||
@Test // GH-992
|
||||
void convertsToSimpleValueThatNeedsSeparateConversion() { |
||||
|
||||
AggregateReference<Object, Integer> source = AggregateReference.to(23); |
||||
|
||||
Object converted = conversionService.convert(source, TypeDescriptor.forObject(source), |
||||
TypeDescriptor.valueOf(Long.class)); |
||||
|
||||
assertThat(converted).isEqualTo(23L); |
||||
} |
||||
|
||||
} |
||||
@ -1 +1,13 @@
@@ -1 +1,13 @@
|
||||
CREATE TABLE aggregate_one ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, NAME VARCHAR(100), two INTEGER); |
||||
CREATE TABLE aggregate_one |
||||
( |
||||
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, |
||||
NAME VARCHAR(100), |
||||
two INTEGER |
||||
); |
||||
|
||||
CREATE TABLE REFERENCING_AGGREGATE |
||||
( |
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, |
||||
NAME VARCHAR(100), |
||||
REF INTEGER |
||||
); |
||||
|
||||
Loading…
Reference in new issue