Skip to content

fix issue with id in nested objects caused by DATACOUCH-533 [DATACOUCH-620] #928

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

Closed
spring-projects-issues opened this issue Oct 1, 2020 · 7 comments
Assignees
Labels
type: enhancement A general enhancement

Comments

@spring-projects-issues
Copy link

Michael Reiche opened DATACOUCH-620 and commented

DATACOUCH-533 assumes fields named 'id' are document id's. As such they are removed from the data to be used as the "key".   
When a nested document - such as Submission in the User object - contains an 'id', it is also removed from the data.

public class User {
  private String id;
  private String username;
  private List<Submission> submissions;
}

public class Submission {
  private final String id;
  private final String userId;
  private final String talkId;
}


Referenced from: pull request #266

Backported to: 4.0.5 (Neumann SR5)

1 votes, 3 watchers

@spring-projects-issues
Copy link
Author

Martin commented

This issue is still not fixed in 4.0.5. When I read document from CB the ids are always null.

Document

 

{
  "embedded": [
    {
      "id": "9Hc6nb7T",
      "title": "Test",
      "embedded": [
        {
          "id": "4fw8cfw5",
          "title": "Embedded in embedded"
        }
      ]
    }
  ],
  "name": "Embedded Id test",
  "_class": "com.example.EmbeddedIdParent"
}

Entity

 

public class EmbeddedIdParent {

    public static final String PREFIX = "t";

    @IdPrefix
    private String prefix = PREFIX;

    @Id
    @GeneratedValue(strategy = GenerationStrategy.UNIQUE, delimiter = "_")
    private String id;

    @Field
    private String name;

    @Field
    private List<Embedded> embedded = new ArrayList<>();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Embedded> getEmbedded() {
        return embedded;
    }

    public void setEmbedded(List<Embedded> embedded) {
        this.embedded = embedded;
    }

    public static class Embedded {
        private String id;
        private String title;
        private List<Embedded> embedded;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public List<Embedded> getEmbedded() {
            return embedded;
        }

        public void setEmbedded(List<Embedded> embedded) {
            this.embedded = embedded;
        }
    }
}

 

 

@spring-projects-issues
Copy link
Author

Michael Reiche commented

Hi martin8877 - 

I reproduced this.  I will fix it.  If you create a constructor that takes the 'id' as an argument, or an all-args constructor for Embedded, the issue will be avoided.

public Embedded( String id){
  this.id = id;}

public Embedded( String id, String title, List<Embedded> embedded){
  this.id = id;
  this.title = title;
  this.embedded = embedded;
}

@spring-projects-issues
Copy link
Author

Michael Reiche commented

fix does not work unless a constructor using the 'id' as an arg was used.

line 264 in MappingCouchbaseConverter needs to check if parent == null

Object obj = prop.isIdProperty() && parent != null ? source.getId() : getValueInternal(prop, source, instance);

@spring-projects-issues
Copy link
Author

Martin commented

I tried to extend MappingCouchbaseConverter and override read method with suggested fix (parent == null, not parent != null)

@Override
protected <R> R read(CouchbasePersistentEntity<R> entity, CouchbaseDocument source, Object parent) {
    R instance = super.read(entity, source, parent);
    final ConvertingPropertyAccessor accessor = getPropertyAccessor(instance);

    entity.doWithProperties(new PropertyHandler<CouchbasePersistentProperty>() {
        @Override
        public void doWithPersistentProperty(final CouchbasePersistentProperty prop) {
            if (!doesPropertyExistInSource(prop) || entity.isConstructorArgument(prop) || isIdConstructionProperty(prop)
                    || prop.isAnnotationPresent(N1qlJoin.class)) {
                return;
            }
            Object obj = prop.isIdProperty() && parent == null ? source.getId() : getValueInternal(prop, source, instance);
            accessor.setProperty(prop, obj);
        }

        private boolean doesPropertyExistInSource(final CouchbasePersistentProperty property) {
            return property.isIdProperty() || source.containsKey(property.getFieldName());
        }

        private boolean isIdConstructionProperty(final CouchbasePersistentProperty property) {
            return property.isAnnotationPresent(IdPrefix.class) || property.isAnnotationPresent(IdSuffix.class);
        }
    });
    return instance;
}

private ConvertingPropertyAccessor<Object> getPropertyAccessor(Object source) {
    CouchbasePersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(source.getClass());
    PersistentPropertyAccessor<Object> accessor = entity.getPropertyAccessor(source);
    return new ConvertingPropertyAccessor<>(accessor, conversionService);
}

It looks like it works but I don't like it cause it's ugly and not very effective I guess.

I will wait for fix. Thank you

@martin8877
Copy link

Hi,
Has this issue been resolved?

@chokirock
Copy link

Just as info, we updated our project to Spring Boot 2.3.7 (Spring Data Couchbase 4.0.6 released on December) and still facing same issue when retrieving embedded object id.

In the meantime as a workaround we applied @mikereiche approach using an all-args constructor for the embedded object.

@mikereiche
Copy link
Collaborator

mikereiche commented Jan 15, 2021

The fix is available now in 4.2-SNAPSHOT, if I understand how SNAPSHOT works correctly.
It will be in RELEASE version starting with 4.1.4 which is due February 10.


fix does not work unless a constructor using the 'id' as an arg was used.

line 264 in MappingCouchbaseConverter needs to check if parent == null

Object obj = prop.isIdProperty() && parent != null ? source.getId() : getValueInternal(prop, source, instance);

MappingCouchbaseConverter - Line 270
3364e0f#diff-fe5ee5c3b9e5ec163fde2c91c9d6e98b53296201957903dacc0479bddf95c7d7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants