spring-data-neo4j icon indicating copy to clipboard operation
spring-data-neo4j copied to clipboard

@CompositeProperty converter rejected when entity field uses parameterized generic type

Open dpkass opened this issue 5 months ago • 0 comments

When an entity field is declared as a parameterized type (e.g. LocalizedValue<String>), a matching Neo4jPersistentPropertyToMapConverter<String, LocalizedValue<String>> is rejected with:

The property type [...].LocalizedValue<java.lang.String> created by [...].LocalizedValueMapConverter
used on name in [...].OrganizationUnit doesn't match the actual property type

If the converter is changed to use the raw type (LocalizedValue), it works.

Versions • Spring Data Neo4j: 7.5.2 • Spring Data Commons: 3.5.2 • Spring Data REST: 4.5.2 • Spring Boot: 3.5.4 • Neo4j Java Driver: 5.28.9 • Java: 21

Minimal example

Domain value type

package com.example.localized;

public class LocalizedValue<T> {
  // internally holds Map<Locale,T>; getters omitted for brevity
}

Converter (fails)

public class LocalizedValueMapConverter
    implements Neo4jPersistentPropertyToMapConverter<String, LocalizedValue<String>> {

  @Override public Map<String, Value> decompose(LocalizedValue<String> lv, Neo4jConversionService cs) { ... }
  @Override public LocalizedValue<String> compose(Map<String, Value> src, Neo4jConversionService cs) { ... }
}

Entity

@Node
public class OrganizationUnit {
  @Id @GeneratedValue Long id;

  @CompositeProperty(converter = LocalizedValueMapConverter.class, prefix = "name")
  private LocalizedValue<String> name;

  // getters/setters use the same parameterized type
}

Observed

  • Throws IllegalArgumentException above.
  • Neo4jMappingContext appears to resolve the property type as raw LocalizedValue, so the parameterized converter is considered a mismatch.
  • I tried a Converter with Neo4jPersistentPropertyToMapConverter<String, LocalizedValue<T>> aswell, same issue.

Workarounds

• Make the converter raw:

class LocalizedValueMapConverter
    implements Neo4jPersistentPropertyToMapConverter<String, LocalizedValue> { ... }

(Works, but loses compile-time type safety.)

Expected

  • A converter targeting LocalizedValue<String> should match a field declared as LocalizedValue<String>.

Happy to provide a tiny reproducer repo if helpful.

dpkass avatar Aug 13 '25 11:08 dpkass