Uploaded image for project: 'Spring Data Commons'
  1. Spring Data Commons
  2. DATACMNS-1458

MappingException when persisting Entity that implements Collection

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open
    • Priority: Minor
    • Resolution: Unresolved
    • Affects Version/s: 2.1.3 (Lovelace SR3)
    • Fix Version/s: None
    • Component/s: Mapping / Conversion
    • Labels:
      None

      Description

      When trying to persist an Entity, using EntityManager.persist(Object), if that Entity also implements java.util.Collection then an exception is thrown:

      org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type java.lang.Object!
       at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:119)
       at org.springframework.data.mapping.context.PersistentPropertyPathFactory.from(PersistentPropertyPathFactory.java:248)
       at org.springframework.data.mapping.context.PersistentPropertyPathFactory.from(PersistentPropertyPathFactory.java:176)
       at org.springframework.data.mapping.context.AbstractMappingContext.doFindPersistentPropertyPaths(AbstractMappingContext.java:322)
       at org.springframework.data.jpa.mapping.JpaMetamodelMappingContext.findPersistentPropertyPaths(JpaMetamodelMappingContext.java:100)
       at org.springframework.data.auditing.MappingAuditableBeanWrapperFactory$MappingAuditingMetadata.<init>(MappingAuditableBeanWrapperFactory.java:115)
       at org.springframework.data.auditing.MappingAuditableBeanWrapperFactory.lambda$null$0(MappingAuditableBeanWrapperFactory.java:83)
       at java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:324)
       at org.springframework.data.auditing.MappingAuditableBeanWrapperFactory.lambda$null$1(MappingAuditableBeanWrapperFactory.java:82)
       at org.springframework.data.mapping.context.PersistentEntities.lambda$mapOnContext$4(PersistentEntities.java:115)
       at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
       at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
       at java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1812)
       at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
       at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
       at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
       at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
       at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
       at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
       at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
       at org.springframework.data.mapping.context.PersistentEntities.mapOnContext(PersistentEntities.java:116)
       at org.springframework.data.auditing.MappingAuditableBeanWrapperFactory.lambda$getBeanWrapperFor$3(MappingAuditableBeanWrapperFactory.java:80)
       at java.util.Optional.flatMap(Optional.java:241)
       at org.springframework.data.auditing.MappingAuditableBeanWrapperFactory.getBeanWrapperFor(MappingAuditableBeanWrapperFactory.java:74)
       at org.springframework.data.auditing.AuditingHandler.touch(AuditingHandler.java:161)
       at org.springframework.data.auditing.AuditingHandler.markCreated(AuditingHandler.java:131)
       at org.springframework.data.jpa.domain.support.AuditingEntityListener.touchForCreate(AuditingEntityListener.java:92)
       at java.lang.reflect.Method.invoke(Method.java:498)
       at org.hibernate.jpa.event.internal.ListenerCallback.performCallback(ListenerCallback.java:35)
       at org.hibernate.jpa.event.internal.CallbackRegistryImpl.callback(CallbackRegistryImpl.java:97)
       at org.hibernate.jpa.event.internal.CallbackRegistryImpl.preCreate(CallbackRegistryImpl.java:57)
       at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:116)
       at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:192)
       at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
       at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:62)
       at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:800)
       at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:785)
       at java.lang.reflect.Method.invoke(Method.java:498)
       at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308)

      This used to work when using spring-boot 2.0.7.RELEASE, but I am trying to upgrade to spring-boot 2.1.1.RELEASE (which uses spring-data-jpa:2.1.3.RELEASE).

      From what I can tell, there is a "new" PersistentPropertyPathFactory that now uses the "actualType" to determine what type the Entity is that needs to be persisted. However, the "actualType" for my Entity ends up just be java.lang.Object because it isCollectionLike (i.e. my type is a Collection so it satisfies the Collection.class.isAssignableFrom(rawType) check).

      Here is a simplified example of the Entity/Collection class:

      @Entity
      public class ContainerCollection<C extends Container> extends Container implements Collection<C> {
      
          @JoinTable(
              name = "mod_container_collections",
              joinColumns = @JoinColumn(name = "container_collection_id"),
              inverseJoinColumns = @JoinColumn(name = "container_id"))
          protected Set<C> containers = new HashSet<>();
      
          @Override
          public int size() {
              return containers.size();
          }
      
          @Override
          public boolean isEmpty() {
              return containers.isEmpty();
          }
      
          // other Collection methods implemented to delegate to containers
          // with some relationship management in add(Object) and remove(Object)
      
      }
      
      

      And here is a really simple test that demonstrates the exception:

      public class PersistenceTest {
      
          @PersistenceContext
          private EntityManager em;
      
          public void testPersist() {
              ContainerCollection<> collection = new ContainerCollection<>();
              em.persist(collection);  // this line throws MappingException
          }
      
      }
      

        Attachments

          Activity

            People

            Assignee:
            olivergierke Oliver Drotbohm
            Reporter:
            mdamone Michael A. Damone
            Last updater:
            Michael A. Damone
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Dates

              Created:
              Updated: