Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid parent parameter provided to static inner class constructors #3038

Closed
G0dC0der opened this issue Feb 4, 2024 · 6 comments
Closed
Assignees
Labels
in: mapping Mapping and conversion infrastructure type: bug A general bug

Comments

@G0dC0der
Copy link

G0dC0der commented Feb 4, 2024

This is a document in collection, exported via MongoDB Compass:

{
  "_id": {
    "$numberLong": "24"
  },
  "name": "attr",
  "storageFormat": {
    "elementFormat": {
      "elementFormat": {
        "elementFormat": {
          "datatype": "DOUBLE",
          "_class": "com.company.cms.persistence.entity.StorageFormatEntity$DataTypeEntity"
        },
        "_class": "com.company.cms.persistence.entity.StorageFormatEntity$ArrayFormatEntity"
      },
      "_class": "com.company.cms.persistence.entity.StorageFormatEntity$ArrayFormatEntity"
    },
    "_class": "com.company.cms.persistence.entity.StorageFormatEntity$ArrayFormatEntity"
  },
  "_class": "com.company.cms.persistence.entity.AttributeEntity"
}

At this point, everything looks correct. However, when I read it, storageFormat.elementFormat is null.
This is the class:

public sealed interface StorageFormatEntity {

    record DataTypeEntity(String datatype) implements StorageFormatEntity {}

    record ContentRefEntity(List<Long> templates) implements StorageFormatEntity {}

    record ArrayFormatEntity(StorageFormatEntity elementFormat) implements StorageFormatEntity {}
}

I have temporarily solved this by registering a custom read converter, but I feel like this shouldn't be necessary. I feel like this is a bug in the framework.

I am using Spring Boot 3.2.1.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Feb 4, 2024
@mp911de
Copy link
Member

mp911de commented Feb 5, 2024

If you would like us to spend some time helping you to diagnose the problem, please spend some time describing it and, ideally, providing a minimal yet complete sample that reproduces the problem. Looking at the example, AttributeEntity is missing so we do not have a complete example here.
You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.

@mp911de mp911de added the status: waiting-for-feedback We need additional information before we can continue label Feb 5, 2024
@G0dC0der
Copy link
Author

G0dC0der commented Feb 5, 2024

A simple demo. Look at class DemoApplication. There is also a docker-compose file, that starta a Mongo instance.
demo.zip

package com.example.demo;

import com.example.demo.DemoApplication.Format.RecursiveFormat;
import com.example.demo.DemoApplication.Format.StaticFormat;
import java.util.Random;
import org.bson.json.JsonWriterSettings;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.Document;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

	@Document("attributes")
	public record Attribute(@Id ObjectId id, Format format) {}

	public sealed interface Format {
		public record RecursiveFormat(Format format) implements Format {}

		public record StaticFormat(String format) implements Format {}
	}

	@Autowired
	private MongoTemplate mongoTemplate;

	@Override
	public void run(final String... args) throws Exception {
		var id = new ObjectId();
		var attribute = new Attribute(id, new RecursiveFormat(new RecursiveFormat(new RecursiveFormat(new StaticFormat("FOO")))));

		mongoTemplate.save(attribute);
		System.out.println("Saved: " + attribute);

		var document = mongoTemplate.execute("attributes", collection -> collection.find(new org.bson.Document("_id", id)).first());
		System.out.println("Reading document as a org.bson.Document" + document.toJson(JsonWriterSettings.builder().indent(true).build()));

		var readAttribute = mongoTemplate.findById(id, Attribute.class);
		System.out.println("Reading document as Attribute: " + readAttribute);
	}
}

Logs:

Saved: Attribute[id=65c1423f0fbf892135c39397, format=RecursiveFormat[format=RecursiveFormat[format=RecursiveFormat[format=StaticFormat[format=FOO]]]]]
Reading document as a org.bson.Document{
  "_id": {
    "$oid": "65c14305757b715020f450cd"
  },
  "format": {
    "format": {
      "format": {
        "format": {
          "format": "FOO",
          "_class": "com.example.demo.DemoApplication$Format$StaticFormat"
        },
        "_class": "com.example.demo.DemoApplication$Format$RecursiveFormat"
      },
      "_class": "com.example.demo.DemoApplication$Format$RecursiveFormat"
    },
    "_class": "com.example.demo.DemoApplication$Format$RecursiveFormat"
  },
  "_class": "com.example.demo.DemoApplication$Attribute"
}
Reading document as Attribute: Attribute[id=65c1423f0fbf892135c39397, format=RecursiveFormat[format=null]]

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Feb 5, 2024
@G0dC0der
Copy link
Author

G0dC0der commented Feb 5, 2024

So, when fetching the object with mongTemplate.execute, the returned object looks perfectly fine. However, when findById is used, it does not!

@christophstrobl
Copy link
Member

@G0dC0der thanks for the reproducer - we'll have a look.

@christophstrobl christophstrobl self-assigned this Feb 6, 2024
@christophstrobl christophstrobl added type: bug A general bug in: mapping Mapping and conversion infrastructure and removed status: waiting-for-triage An issue we've not yet triaged status: feedback-provided Feedback has been provided labels Feb 6, 2024
@christophstrobl
Copy link
Member

So apparently this is an issue when the mapping requires objects to be created via an argument constructor. Things works as expected when switching RecursiveFormat to a class having a noargs constructor.

@christophstrobl
Copy link
Member

The issue stems from PersistentEntityParameterValueProvider which considers the constructor Parameter to belong to the parent type and then returning null for the actual value.

@christophstrobl christophstrobl transferred this issue from spring-projects/spring-data-mongodb Feb 7, 2024
@mp911de mp911de added this to the 3.1.9 (2023.0.9) milestone Feb 8, 2024
@mp911de mp911de changed the title Reading document with recursive structure Invalid parent parameter provided to static inner classes constructors Feb 8, 2024
@mp911de mp911de changed the title Invalid parent parameter provided to static inner classes constructors Invalid parent parameter provided to static inner classe constructors Feb 8, 2024
@mp911de mp911de changed the title Invalid parent parameter provided to static inner classe constructors Invalid parent parameter provided to static inner class constructors Feb 8, 2024
@mp911de mp911de closed this as completed in 45b810a Feb 8, 2024
mp911de added a commit that referenced this issue Feb 8, 2024
Add additional tests, add Javadoc to explain isEnclosingClassParameter() behavior.

See #3038
Original pull request: #3039
mp911de pushed a commit that referenced this issue Feb 8, 2024
mp911de added a commit that referenced this issue Feb 8, 2024
Add additional tests, add Javadoc to explain isEnclosingClassParameter() behavior.

See #3038
Original pull request: #3039
mp911de pushed a commit that referenced this issue Feb 8, 2024
mp911de added a commit that referenced this issue Feb 8, 2024
Add additional tests, add Javadoc to explain isEnclosingClassParameter() behavior.

See #3038
Original pull request: #3039
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: mapping Mapping and conversion infrastructure type: bug A general bug
Projects
None yet
4 participants