From 161b1e80b404af59c3abb8deab9d449d5540d3fa Mon Sep 17 00:00:00 2001 From: Andrey G Date: Mon, 16 Dec 2024 20:25:25 +0200 Subject: [PATCH] FMWK-628 Support null classKey (#801) --- .../config/AerospikeDataConfigurationSupport.java | 5 +---- .../convert/AerospikeTypeAliasAccessor.java | 8 ++------ .../convert/MappingAerospikeWriteConverter.java | 2 +- .../query/AerospikeQueryCreatorUtils.java | 15 ++++++++++----- .../repository/query/MapQueryCreator.java | 10 ++++++++++ .../BaseMappingAerospikeConverterTest.java | 3 ++- .../convert/MappingAerospikeConverterTests.java | 2 +- .../MappingAerospikeConverterTypesTests.java | 2 +- .../query/AerospikeQueryCreatorUnitTests.java | 4 +++- .../data/aerospike/util/QueryUtils.java | 4 +++- 10 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/springframework/data/aerospike/config/AerospikeDataConfigurationSupport.java b/src/main/java/org/springframework/data/aerospike/config/AerospikeDataConfigurationSupport.java index eff4b49f6..54bf505ca 100644 --- a/src/main/java/org/springframework/data/aerospike/config/AerospikeDataConfigurationSupport.java +++ b/src/main/java/org/springframework/data/aerospike/config/AerospikeDataConfigurationSupport.java @@ -107,10 +107,7 @@ public MappingAerospikeConverter mappingAerospikeConverter(AerospikeMappingConte @Bean(name = "aerospikeTypeAliasAccessor") public AerospikeTypeAliasAccessor aerospikeTypeAliasAccessor(AerospikeDataSettings dataSettings) { - String classKey = dataSettings.getClassKey(); - return StringUtils.hasText(classKey) - ? new AerospikeTypeAliasAccessor(classKey) - : new AerospikeTypeAliasAccessor(); + return new AerospikeTypeAliasAccessor(dataSettings.getClassKey()); } @Bean diff --git a/src/main/java/org/springframework/data/aerospike/convert/AerospikeTypeAliasAccessor.java b/src/main/java/org/springframework/data/aerospike/convert/AerospikeTypeAliasAccessor.java index f0500771c..b8e755065 100644 --- a/src/main/java/org/springframework/data/aerospike/convert/AerospikeTypeAliasAccessor.java +++ b/src/main/java/org/springframework/data/aerospike/convert/AerospikeTypeAliasAccessor.java @@ -17,21 +17,17 @@ import org.springframework.data.convert.TypeAliasAccessor; import org.springframework.data.mapping.Alias; +import org.springframework.util.StringUtils; import java.util.Map; -import static org.springframework.data.aerospike.convert.AerospikeConverter.CLASS_KEY_DEFAULT; public class AerospikeTypeAliasAccessor implements TypeAliasAccessor> { private final String classKey; public AerospikeTypeAliasAccessor(String classKey) { - this.classKey = classKey; - } - - public AerospikeTypeAliasAccessor() { - this.classKey = CLASS_KEY_DEFAULT; + this.classKey = StringUtils.hasText(classKey) ? classKey : null; } @Override diff --git a/src/main/java/org/springframework/data/aerospike/convert/MappingAerospikeWriteConverter.java b/src/main/java/org/springframework/data/aerospike/convert/MappingAerospikeWriteConverter.java index f97075b4b..14758cca8 100644 --- a/src/main/java/org/springframework/data/aerospike/convert/MappingAerospikeWriteConverter.java +++ b/src/main/java/org/springframework/data/aerospike/convert/MappingAerospikeWriteConverter.java @@ -267,7 +267,7 @@ protected Map convertMap(final Map source, final } private Map convertCustomType(Object source, TypeInformation type) { - Assert.notNull(source, "Given map must not be null!"); + Assert.notNull(source, "Given source must not be null!"); Assert.notNull(type, "Given type must not be null!"); AerospikePersistentEntity entity; diff --git a/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUtils.java b/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUtils.java index 53a36671e..47633be8b 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUtils.java +++ b/src/main/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUtils.java @@ -25,7 +25,6 @@ import java.util.stream.Stream; import static java.util.function.Predicate.not; -import static org.springframework.data.aerospike.convert.AerospikeConverter.CLASS_KEY_DEFAULT; import static org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeNullQueryCriterion; import static org.springframework.data.aerospike.repository.query.CriteriaDefinition.AerospikeNullQueryCriterion.NULL_PARAM; import static org.springframework.util.ClassUtils.isAssignable; @@ -233,6 +232,10 @@ protected static void validateTypes(MappingAerospikeConverter converter, Class) { params = ((Collection) queryParameters.get(0)).stream(); } + + // skipping further validations as they depend on using classKey + if (!StringUtils.hasText(converter.getAerospikeDataSettings().getClassKey())) return; + if (!params.allMatch(param -> isAssignableValueOrConverted(clazz, param, converter))) { String validTypes = propertyType.getSimpleName(); if (alternativeTypes.length > 0) { @@ -265,12 +268,13 @@ protected static void validateQueryIn(List queryParameters, String query } } + // works only when classKey configuration property is not null protected static boolean isAssignableValueOrConverted(Class propertyType, Object obj, MappingAerospikeConverter converter) { return isAssignableValue(propertyType, obj) || converter.getCustomConversions().hasCustomReadTarget(obj.getClass(), propertyType) // POJOs and enums got converted to Strings when query parameters were set - || isPojoMap(obj, propertyType) + || isPojoMap(obj, propertyType, converter.getAerospikeDataSettings().getClassKey()) || (propertyType.isEnum() && obj instanceof String); } @@ -279,12 +283,13 @@ protected static boolean isAssignableValueOrConverted(Class propertyType, Obj * * @param object Instance to be compared * @param propertyType Class for comparing + * @param classKey Name of the bin to store entity's class * @return Whether the object is a converted POJO of the given class */ - protected static boolean isPojoMap(Object object, Class propertyType) { + protected static boolean isPojoMap(Object object, Class propertyType, String classKey) { if (object instanceof TreeMap treeMap) { - Object classKey = treeMap.get(CLASS_KEY_DEFAULT); - return classKey != null && classKey.equals(propertyType.getName()); + Object className = treeMap.get(classKey); + return className != null && className.equals(propertyType.getName()); } return false; } diff --git a/src/main/java/org/springframework/data/aerospike/repository/query/MapQueryCreator.java b/src/main/java/org/springframework/data/aerospike/repository/query/MapQueryCreator.java index 6f3a68fe3..f95eeb8c5 100644 --- a/src/main/java/org/springframework/data/aerospike/repository/query/MapQueryCreator.java +++ b/src/main/java/org/springframework/data/aerospike/repository/query/MapQueryCreator.java @@ -11,6 +11,7 @@ import org.springframework.data.mapping.PropertyPath; import org.springframework.data.repository.query.parser.Part; import org.springframework.data.util.TypeInformation; +import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.List; @@ -95,6 +96,9 @@ private void validateMapQueryContaining(String queryPartDescription) { "expecting two"); } + // skipping further validations as they depend on using classKey + if (!StringUtils.hasText(converter.getAerospikeDataSettings().getClassKey())) return; + if (!(isValidMapKeyTypeOrUnresolved(part.getProperty().getTypeInformation(), param2))) { throw new IllegalArgumentException(queryPartDescription + ": invalid map key type at position 2"); } @@ -105,6 +109,9 @@ private void validateMapQueryContaining(String queryPartDescription) { "expecting two"); } + // skipping further validations as they depend on using classKey + if (!StringUtils.hasText(converter.getAerospikeDataSettings().getClassKey())) return; + if (!(isValidMapValueTypeOrUnresolved(part.getProperty().getTypeInformation(), param2))) { throw new IllegalArgumentException(queryPartDescription + ": invalid map value type at position 2"); } @@ -115,6 +122,9 @@ private void validateMapQueryContaining(String queryPartDescription) { "expecting three"); } + // skipping further validations as they depend on using classKey + if (!StringUtils.hasText(converter.getAerospikeDataSettings().getClassKey())) return; + if (!(isValidMapKeyTypeOrUnresolved(part.getProperty().getTypeInformation(), param2))) { throw new IllegalArgumentException(queryPartDescription + ": invalid map key type at position 2"); } diff --git a/src/test/java/org/springframework/data/aerospike/convert/BaseMappingAerospikeConverterTest.java b/src/test/java/org/springframework/data/aerospike/convert/BaseMappingAerospikeConverterTest.java index 88aec6e39..1ebaab6dc 100644 --- a/src/test/java/org/springframework/data/aerospike/convert/BaseMappingAerospikeConverterTest.java +++ b/src/test/java/org/springframework/data/aerospike/convert/BaseMappingAerospikeConverterTest.java @@ -61,7 +61,8 @@ protected MappingAerospikeConverter getAerospikeMappingConverterByOption(int con protected MappingAerospikeConverter getMappingAerospikeConverter(AerospikeDataSettings settings, Converter... customConverters) { - return getMappingAerospikeConverter(settings, new AerospikeTypeAliasAccessor(), customConverters); + return getMappingAerospikeConverter(settings, new AerospikeTypeAliasAccessor(settings.getClassKey()), + customConverters); } protected MappingAerospikeConverter getMappingAerospikeConverter(AerospikeDataSettings settings, diff --git a/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTests.java b/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTests.java index f38cc630a..cd63f16b2 100644 --- a/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTests.java +++ b/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTests.java @@ -409,7 +409,7 @@ public void shouldReadObjectWithByteArrayFieldWithOneValueInData(int converterOp @Test public void getConversionService() { MappingAerospikeConverter mappingAerospikeConverter = - getMappingAerospikeConverter(settings, new AerospikeTypeAliasAccessor()); + getMappingAerospikeConverter(settings, new AerospikeTypeAliasAccessor(settings.getClassKey())); assertThat(mappingAerospikeConverter.getConversionService()).isNotNull() .isInstanceOf(DefaultConversionService.class); } diff --git a/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java b/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java index 5a77974fe..c8ddf4449 100644 --- a/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java +++ b/src/test/java/org/springframework/data/aerospike/convert/MappingAerospikeConverterTypesTests.java @@ -775,7 +775,7 @@ void shouldWriteAsByteArrayAndReadAsArrayList() { } @Test - void shouldWriteAndReadNestedPOJOs() { + void shouldWriteAndReadNestedPOJOsWithNullClassKey() { MappingAerospikeConverter converter = getMappingAerospikeConverter(settings, new AerospikeTypeAliasAccessor(null)); diff --git a/src/test/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUnitTests.java b/src/test/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUnitTests.java index 7f0a780d5..10edd897c 100644 --- a/src/test/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUnitTests.java +++ b/src/test/java/org/springframework/data/aerospike/repository/query/AerospikeQueryCreatorUnitTests.java @@ -18,6 +18,8 @@ import java.util.Collections; import java.util.List; +import static org.springframework.data.aerospike.convert.AerospikeConverter.CLASS_KEY_DEFAULT; + /** * @author Peter Milne * @author Jean Mercier @@ -66,7 +68,7 @@ tree1, new StubParameterAccessor( private MappingAerospikeConverter getMappingAerospikeConverter(AerospikeCustomConversions conversions) { MappingAerospikeConverter converter = new MappingAerospikeConverter(new AerospikeMappingContext(), - conversions, new AerospikeTypeAliasAccessor(), new AerospikeDataSettings(null)); + conversions, new AerospikeTypeAliasAccessor(CLASS_KEY_DEFAULT), new AerospikeDataSettings(null)); converter.afterPropertiesSet(); return converter; } diff --git a/src/test/java/org/springframework/data/aerospike/util/QueryUtils.java b/src/test/java/org/springframework/data/aerospike/util/QueryUtils.java index 9c95b71e0..823bd1013 100644 --- a/src/test/java/org/springframework/data/aerospike/util/QueryUtils.java +++ b/src/test/java/org/springframework/data/aerospike/util/QueryUtils.java @@ -27,6 +27,8 @@ import java.util.Map; import java.util.stream.Stream; +import static org.springframework.data.aerospike.convert.AerospikeConverter.CLASS_KEY_DEFAULT; + public class QueryUtils { private static final Map, Class> WRAPPERS_TO_PRIMITIVES @@ -107,7 +109,7 @@ private static Class checkForPageable(Class argType) { private static MappingAerospikeConverter getMappingAerospikeConverter(AerospikeCustomConversions conversions) { MappingAerospikeConverter converter = new MappingAerospikeConverter(new AerospikeMappingContext(), - conversions, new AerospikeTypeAliasAccessor(), new AerospikeDataSettings(null)); + conversions, new AerospikeTypeAliasAccessor(CLASS_KEY_DEFAULT), new AerospikeDataSettings(null)); converter.afterPropertiesSet(); return converter; }