Uploaded image for project: 'Spring Data MongoDB'
  1. Spring Data MongoDB
  2. DATAMONGO-2346

Field annotated with @LastModifiedDate is not persisted in Kotlin data classes

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Minor
    • Resolution: Fixed
    • Affects Version/s: 2.1.10 (Lovelace SR10)
    • Fix Version/s: 2.2 RC3 (Moore)
    • Component/s: None
    • Labels:
      None

      Description

      After updating from 2.0.x to 2.1.10, we noticed that the new value of a field annotated with the @LastModifiedDate annotation is not persisted, in case of Kotlin data classes.

      Please, consider the following data class: 

      @Document("entities")
      data class Entity(
       // ...
       @LastModifiedDate val modificationDate: Instant?,
       // ...
      )
      

       and the following use case:

      def inserted = entityRepository.save(entity)
      def modified = // do modifications of 'inserted' that take some time
      
      def updated = entityRepository.save(modified)
      def fetched = entityRepository.findById(100L).get()
      

      Now, updated.modificationDate is updated and points to a correct point of time, but fetched.modificationDate is has the old value and is the same as inserted.modificationDate.

      When the field is var instead of val then the new value of modificationDate is persisted, and fetched.modificationDate has the expected value.

      @Document("entities")
      data class Entity(
       // ...
       @LastModifiedDate var modificationDate: Instant?,
       // ...
      )
      

       
      Adding a wither doesn't change much, and the field is not persisted, too.

      @Document("entities")
      data class Entity(
       // ...
       @LastModifiedDate val modificationDate: Instant?,
       // ...
      ) {
       fun withModificationDate(modificationDate: Instant): EntityWither = copy(modificationDate = modificationDate)
      }
      
      

      I prepared a minimal, example project that shows the issue here.

      Also, I noticed that in ReactiveMongoTemplate::doSaveVersioned the annotated field is changed, but then the old value is persisted:

      BeforeConvertEvent<T> event = new BeforeConvertEvent<>(toSave, collectionName);
      
      // The 'afterEvent' contains the correct value of the 'modificationDate' field 
      T afterEvent = ReactiveMongoTemplate.this.maybeEmitEvent(event).getSource();
      
      // Notice that 'toSave' is mapped, not 'afterEvent'. It means that we skip the changes in the entity caused by the auditing process. 'AfterEvent' should be passed to forEntity(), not 'toSave', I guess(?)
      MappedDocument mapped = operations.forEntity(toSave).toMappedDocument(mongoConverter);
      Document document = mapped.getDocument();
      
      ReactiveMongoTemplate.this.maybeEmitEvent(new BeforeSaveEvent<>(afterEvent, document, collectionName));
      
      // There's an inconsistency, we persist 'toSave' which doesn't contain the auditing changes, but then we return 'afterEvent' with the changes.
      return doUpdate(collectionName, query, mapped.updateWithoutId(), afterEvent.getClass(), false, false)
       .map(result -> {
       return maybeEmitEvent(new AfterSaveEvent<T>(afterEvent, document, collectionName)).getSource();
       });
      

      If this is indeed a bug, I would like to take a deeper look at it, and prepare a PR with a fix.
       

        Attachments

          Activity

            People

            Assignee:
            cstrobl Christoph Strobl
            Reporter:
            wjur Wojciech Jurczyk
            Last updater:
            Mark Paluch
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: