spring-projects / spring-projects/spring-data-mongodb

ConversionFailedException when using specific String->ObjectId-converter [DATAMONGO-1329]

Open
#2,241 0 comments 0 reactions 1 assignee View on GitHub

@odrotbohm is already working on this.

Since Dec 30, 2020.

in: mapping type: enhancement
Dominant language
Java
Stars
1.7k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Description

Christian Laakmann opened DATAMONGO-1329 and commented

While investigating DATAMONGO-1324 we tried adding custom converters to handle the conversion between String and ObjectId without the use of reflection.

Side note: this has to be done explicitly, although AbstractMongoConverter tries to create converters for String->ObjectId, ObjectId->String etc. However, those are never added. Spring examines the source's and target's class hierarchy and finds a matching converter in Spring's ObjectToObjectConverter, which can handle Object -> Object.

We copied the existing String->ObjecId / ObjectId->String-converters from MongoConverters and added them using a CustomConversions bean.

Before we could test the new converter, the initialisation of our app failed with the following exception:

org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type org.bson.types.ObjectId for value 'de-DE'; nested exception is java.lang.IllegalArgumentException: invalid ObjectId [de-DE]

	at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:176)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getPotentiallyConvertedSimpleWrite(MappingMongoConverter.java:792)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeSimpleInternal(MappingMongoConverter.java:773)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.access$100(MappingMongoConverter.java:78)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:430)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:416)
	at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:309)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:416)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:390)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:354)
	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:78)
	at org.springframework.data.mongodb.core.MongoTemplate.toDbObject(MongoTemplate.java:813)
	at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:972)
	at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:921)
	at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:78)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:483)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:468)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:440)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
	at com.sun.proxy.$Proxy51.save(Unknown Source)
	at com.example.LoadLocaleWithCustomConverter.setup(LoadLocaleWithCustomConverter.java:36)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.IllegalArgumentException: invalid ObjectId [de-DE]
	at org.bson.types.ObjectId.<init>(ObjectId.java:200)
	at org.bson.types.ObjectId.<init>(ObjectId.java:186)
	at com.example.LoadLocaleWithCustomConverter$StringToObjectIdConverter.convert(LoadLocaleWithCustomConverter.java:85)
	at com.example.LoadLocaleWithCustomConverter$StringToObjectIdConverter.convert(LoadLocaleWithCustomConverter.java:81)
	at org.springframework.core.convert.support.GenericConversionService$ConverterAdapter.convert(GenericConversionService.java:375)
	at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:35)
	... 71 more

We tried to load a document using a custom method in one of our Repositories, that takes a String. For some reason, MappingMongoConverter.getPotentiallyConvertedSimpleWrite tries to convert the String to ObjectId which fails, because it's not a valid object id.

I have created a project that shows the problem: https://github.com/christian-laakmann/spring-data-issues

Run LoadLocale[With / Without]CustomConverter to reproduce the problem


Affects: 1.8.1 (Gosling SR1)

Reference URL: https://github.com/christian-laakmann/spring-data-issues

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.