spring-data-mongodb: BeanInstantiationException: Failed to instantiate []: Specified class is an interface [DATAMONGO-2391]

Ilya Zinkevich opened DATAMONGO-2391 and commented

Hi,

I get error with package org.springframework.boot:spring-boot-starter-data-mongodb:2.1.5.RELEASE

Description: I have interface Call and class TokBoxCall (implements Call) in the code. There is default typeKey in the records in Mongo DB: "_class":"com.xxxxx.server.data.model.call.TokBoxCall".

And I didn’t overwrite it in Spring Mongo Config. However, when I perform reading operations, e.g. callRepository.findById(id), I get Exception:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.xxxxx.server.data.model.Call]: Specified class is an interface
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:119)
        at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:64)}}

Affects: 2.1.11 (Lovelace SR11)

1 votes, 4 watchers

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 3
  • Comments: 15 (3 by maintainers)

Most upvoted comments

Thank you @DobryninVyacheslav for the additional context. EntityScanner is part of spring-boot and using an AnnotationTypeFilter that by default does not consider interface types. There’s however an open issue spring-projects/spring-boot#12828 to allow more fine grained filtering. At this point I’m inclined to close this issue in favor of the spring-boot one.

Hey @christophstrobl , thanks for the prompt reply!

Providing an initial entity set should solve the issue.

Yeah, initial entity set seems to do the job, although I’d go with something like this:

    override fun getInitialEntitySet() = super.getInitialEntitySet().apply {
        add(FieldType.FieldTypeImpl::class.java)
        add(FieldType.OtherFieldTypeImpl::class.java)
    }

Could it have any unexpected side effects though? Is there a chance FieldTypeImpl and OtherFieldTypeImpl will be treated as separate collections in mongo?

Unless I’m missing something the behaviour is the expected one as documented in the Customizing Type Mapping section of the reference documentation.

Yeah, the documentation does mention it, that’s why I came up with a solution like this:

    override fun mappingMongoConverter(
        databaseFactory: MongoDatabaseFactory,
        customConversions: MongoCustomConversions,
        mappingContext: MongoMappingContext
    ) = super.mappingMongoConverter(databaseFactory, customConversions, mappingContext).apply {
        setTypeMapper(
            DefaultMongoTypeMapper(
                DEFAULT_TYPE_KEY,
                listOf(
                    ConfigurableTypeInformationMapper(
                        mapOf(
                            FieldTypeImpl::class.java to "field_type_impl",
                            OtherFieldTypeImpl::class.java to "other_field_type_impl",
                        )
                    ),
                    SimpleTypeInformationMapper(),
                )
            )
        )
    }

But the thing is, you wouldn’t go to the documentation when having a polymorphic field seems to just work out of the box. Having a test like SaveAndGetWithRepositoryTest might create an impression it just works. And the worst thing is that even if you save a document without using repository, you might still have other tests that save it with repository, thus affecting the test via a shared context.

I think the behavior should be consistent here: if there is no mapping for the type then it should fail while saving it. It shouldn’t only fail when you didn’t save a document first before getting another one from the DB.