Skip to content

TypeInformation.OBJECT is null when only ClassTypeInformation.COLLECTION has been accessed #3340

@gvozdovvalera-droid

Description

@gvozdovvalera-droid

Hi, spring-boot migration 3.5.3->3.5.4 causes NPE (spring-data-relational 3.5.2)

this happens in
MappingRelationalConverter.writeValue() because
if (TypeInformation.OBJECT != type) { was replaced with if (!TypeInformation.OBJECT.equals(type)) {

I have a rather specific app: This app is used for testing purposes. It allows to start several spring-boot based micro-services in a single jvm.
Because of complex hierarchy TypeInformation <-> ClassTypeInformation and dependencies of static objects
the field TypeInformation.OBJECT may have a null value, which causes npe:

java.lang.NullPointerException: Cannot invoke "Object.equals(Object)" because "org.springframework.data.util.TypeInformation.OBJECT" is null
	at org.springframework.data.relational.core.conversion.MappingRelationalConverter.writeValue(MappingRelationalConverter.java:705)
	at org.springframework.data.jdbc.core.convert.MappingJdbcConverter.writeValue(MappingJdbcConverter.java:214)
	at org.springframework.data.jdbc.core.convert.MappingJdbcConverter.writeJdbcValue(MappingJdbcConverter.java:247)
	at org.springframework.data.jdbc.repository.query.StringBasedJdbcQuery.writeValue(StringBasedJdbcQuery.java:320)
	at org.springframework.data.jdbc.repository.query.StringBasedJdbcQuery.bindParameters(StringBasedJdbcQuery.java:281)
	at org.springframework.data.jdbc.repository.query.StringBasedJdbcQuery.execute(StringBasedJdbcQuery.java:230)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170)
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:170)
	at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:149)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:380)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:138)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at io.opentelemetry.javaagent.instrumentation.spring.data.v1_8.SpringDataInstrumentationModule$RepositoryInterceptor.invoke(SpringDataInstrumentationModule.java:112)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)
	at jdk.proxy6/jdk.proxy6.$Proxy217.getUIDealsStatistic(Unknown Source)
	at foo.baz.service.FooIndex.loadCache(FooIndex.java:61)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130)
	at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124)
	at io.micrometer.observation.Observation.observe(Observation.java:498)
	at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124)

There is a workaround to fix:
add TypeInformation.of(String.class); as a first statement in main method.

I found a simple option to reproduce the issue:
adding two lines in main method

    public static void main(String[] args) {
        Object ignore = ClassTypeInformation.COLLECTION;
        Object ignore2 = TypeInformation.OBJECT;
        // ...

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions