Reputation: 139
I'm trying to upgrade from Spring Boot 2.3.12 to 2.7.15 and are having some issues.
In 2.3.12 I had a Neo4j node with the following property with the @Properties
annotation:
@Properties(prefix = "params")
var params: MutableMap<String, Any?>
In 2.7.17 the annotation @Properties
has bee replaced with @CompositeProperty
@CompositeProperty(prefix = "params")
var params: MutableMap<String, Any?>
This works as long as the value is simple. My problem is that I have values in the map that is a map.
This worked fine in 2.3.12 as the properties got stored in the database like this:
params.key1: "Some string"
params.key2.mapKey1: "Some other string 1"
params.key2.mapKey2: "Some other string 2"
In 2.7.17, if I try to put a map as a value in the map just get the following error message:
Property values can only be of primitive types or arrays thereof. Encountered: Map{}.; Error code 'Neo.ClientError.Statement.TypeError'
Am I missing something, or has this feature been removed?
Yes. I can probably change my database model or replace Neo4j, but I already have a lot of data and I do not really want to migrate.
Thanks
Upvotes: 2
Views: 92
Reputation: 8262
The Spring Data Neo4j version in place is stricter when it comes to types, as you have already experienced.
I am not this experienced with Kotlin type handling but the general way to make this work is to provide a converter for your expected type.
But since this is Any
, this converter might be triggered also for properties that you don't want to convert.
I am just abstracting from the example, you have given.
@CompositeProperty(prefix = "params")
var params: MutableMap<String, CustomType?>
the converter definition:
public static class CustomTypeConverter implements GenericConverter {
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
Set<ConvertiblePair> convertiblePairs = new HashSet<>();
convertiblePairs.add(new ConvertiblePair(Value.class, CustomType.class));
convertiblePairs.add(new ConvertiblePair(CustomType.class, Value.class));
return convertiblePairs;
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (StringValue.class.isAssignableFrom(sourceType.getType())) {
return CustomType.of(((StringValue) source).asString());
} else {
return Values.value(((CustomType) source).getValue());
}
}
}
and registering it as:
@Override
public Neo4jConversions neo4jConversions() {
return new Neo4jConversions(Collections.singleton(new CustomTypeConverter()));
}
It would be also possible to do this explicitly for the attribute, but this would require to also map the Map
.
On the other hand, you can keep the Any
type.
More can be found in the reference: https://docs.spring.io/spring-data/neo4j/reference/appendix/conversions.html#custom.conversions
Upvotes: 0