Skip to content

MappingMongoJsonSchemaCreator does not resolve embedded documents subclasses/interfaces implementations attributes #3870

Closed
@Pastissad

Description

@Pastissad

I am trying to setup automatic Client-Side Field Level Encryption via a generated Json Schema using the new@Encrypted annotation.
Doc. reference : https://docs.spring.io/spring-data/mongodb/docs/3.3.x/reference/html/#mongo.jsonSchema
Example 90. Client-Side Field Level Encryption via Json Schema

I stumbled into a severe limitation that impacts the schema generation through MappingMongoJsonSchemaCreator : embedded documents using subclasses or interfaces implementations have their attributes partially ignored.

Here's a test that highlights the issue :

@Test
public void test_embedded_subclasses_ignored() {
    final MongoJsonSchema schema = MongoJsonSchemaCreator.create().createSchemaFor(Doc.class);
    final Document schemaDocument = schema.schemaDocument();
    final Document embeddedDocDocument = schemaDocument.get("properties", Document.class).get("embeddedDoc", Document.class)
                                                       .get("properties", Document.class);
    final Document embeddedDocInterfaceDocument = schemaDocument.get("properties", Document.class).get("embeddedDocInterface", Document.class)
                                                       .get("properties", Document.class);
    assertAll(() -> assertThat(embeddedDocDocument).isNotNull().containsKeys("a", "childBAttr", "childCAttr"),
              () -> assertThat(embeddedDocInterfaceDocument).isNotNull().containsKeys("interfaceAttr", "interfaceAttrB"));
}

@Data
static class Doc {
    String attr1;
    A embeddedDoc;
    AnInterface embeddedDocInterface;
}

interface AnInterface {
    String getInterfaceAttr();
}

@Data
static class InterfaceImpl implements AnInterface {
    @Encrypted
    String interfaceAttr;
    @Encrypted
    String interfaceAttrB;
}

@Data
static class B extends A {
    @Encrypted
    String childBAttr;
}

@Data
static class C extends A {
    @Encrypted
    String childCAttr;
}

@Data
static abstract class A {
    @Encrypted
    String a;
}

The resulting schema contains definitions for attributes attr1, embeddedDoc.a and embeddedDocInterface.interfaceAttr only.
I'd expect the schema to contain all a, childBAttr and childCAttr properties defined for 'embeddedDoc', and interfaceAttr + interfaceAttrB for the 'embeddedDocInterface'.

The issue originates here as it will only consider the base class or interface to resolve attributes :
MappingMongoJsonSchemaCreator#computePropertiesForEntity (L129)

...
List<JsonSchemaProperty> schemaProperties = new ArrayList<>();
for (MongoPersistentProperty nested : nestedProperties) {
...

Here's a potential solution I'm using in the meantime with a custom version of the class, getSubClasses() being any implementation for extracting the subclasses of a given class or interface :

...
List<JsonSchemaProperty> schemaProperties = new ArrayList<>();

final Set<? extends MongoPersistentEntity<?>> subclassesEntities = getSubClasses(entity.getType())
                                                                                      .stream().map(mappingContext::getRequiredPersistentEntity)
                                                                                      .collect(Collectors.toSet());

final Set<MongoPersistentProperty> nestedProperties =
      subclassesEntities.isEmpty() ? new HashSet<>(IteratorUtils.toList(entity.iterator())) :
      subclassesEntities.stream().flatMap(subClassEntity -> IteratorUtils.toList(subClassEntity.iterator()).stream())
                        .collect(Collectors.toSet()); 

for (MongoPersistentProperty nested : nestedProperties) {
...

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions