Javers - PROPERTY_NOT_FOUND: Property 'id' not found in class 'EntityName$HibernateProxy$Azi44O4n' - spring-boot

I am trying to audit my entities using Javers (6.5.2). When I am doing .save() or .saveAndFlush() operation in Spring Boot (2.5.5), I randomly get the following exception:
org.javers.common.exception.JaversException: PROPERTY_NOT_FOUND: Property 'id' not found in class package.to.entity.EntityName$HibernateProxy$Azi44O4n'. If the name is correct - check annotations. Properties with #DiffIgnore or #Transient are not visible for JaVers.
at org.javers.core.metamodel.type.ManagedClass.getProperty(ManagedClass.java:83)
at org.javers.core.metamodel.type.ManagedClass.lambda$getProperties$1(ManagedClass.java:93)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.javers.core.metamodel.type.ManagedClass.getProperties(ManagedClass.java:93)
at org.javers.core.metamodel.type.EntityType.spawn(EntityType.java:60)
at org.javers.core.metamodel.type.EntityType.spawn(EntityType.java:44)
at org.javers.core.metamodel.type.TypeFactory.spawnFromPrototype(TypeFactory.java:145)
at org.javers.core.metamodel.type.TypeFactory.infer(TypeFactory.java:98)
at org.javers.core.metamodel.type.TypeMapper.lambda$getJaversType$0(TypeMapper.java:99)
at org.javers.core.metamodel.type.TypeMapperEngine.computeIfAbsent(TypeMapperEngine.java:110)
at org.javers.core.metamodel.type.TypeMapper.getJaversType(TypeMapper.java:99)
at org.javers.core.JaversCore.assertJaversTypeNotValueTypeOrPrimitiveType(JaversCore.java:98)
at org.javers.core.JaversCore.commit(JaversCore.java:85)
at org.javers.spring.transactions.JaversTransactionalDecorator.commit(JaversTransactionalDecorator.java:68)
at org.javers.spring.jpa.JaversTransactionalJpaDecorator.commit(JaversTransactionalJpaDecorator.java:50)
at org.javers.spring.jpa.JaversTransactionalJpaDecorator$$FastClassBySpringCGLIB$$8b0feaeb.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
at org.javers.spring.jpa.JaversTransactionalJpaDecorator$$EnhancerBySpringCGLIB$$3ff29c58.commit(<generated>)
at org.javers.spring.auditable.aspect.JaversCommitAdvice.commitObject(JaversCommitAdvice.java:93)
at java.base/java.util.Arrays$ArrayList.forEach(Arrays.java:4390)
at java.base/java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1085)
at org.javers.spring.auditable.aspect.springdata.AbstractSpringAuditableRepositoryAspect.lambda$onSave$0(AbstractSpringAuditableRepositoryAspect.java:28)
at java.base/java.util.Optional.ifPresent(Optional.java:183)
at org.javers.spring.auditable.aspect.springdata.AbstractSpringAuditableRepositoryAspect.onSave(AbstractSpringAuditableRepositoryAspect.java:27)
at org.javers.spring.auditable.aspect.springdatajpa.JaversSpringDataJpaAuditableRepositoryAspect.onSaveAndFlushExecuted(JaversSpringDataJpaAuditableRepositoryAspect.java:51)
at jdk.internal.reflect.GeneratedMethodAccessor541.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:617)
at org.springframework.aop.aspectj.AspectJAfterReturningAdvice.afterReturning(AspectJAfterReturningAdvice.java:66)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:58)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy313.saveAndFlush(Unknown Source)
at package.to.entity.EntityService.add(EntityName.java:139)
at package.to.entity.EntityService$$FastClassBySpringCGLIB$$4a066350.invoke(<generated>)...
This happens randomly (at least on my local backend). Yesterday, at first, everything was working fine, then after application restart, I just couldn't save my entity (I am not aware of changing anything important in my code). Today (still not aware of changing anything), it just suddenly started working locally and I can not simulate this problem anymore. I could only simulate in on environment from frontend deployed branch, so I could get at least exception from OpenShift console.
How id attribute in entity is defined:
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
How I save entity:
public EntityName add(Dto dto) {
EntityName entity = dto.mapToEntity();
entity = repository.saveAndFlush(entity);
repository.refresh(entity); // In debug it wasn't even able to make it here
return entity;
}
I have #TypeName in my entity defined.
Javers configuration:
#Bean(name = "JaversFromStarter")
public Javers javers(
JaversSqlRepository sqlRepository, PlatformTransactionManager txManager,
JaversSqlProperties sqlProperties
) {
return TransactionalJpaJaversBuilder.javers()
.withTxManager(txManager)
.registerJaversRepository(sqlRepository)
.withObjectAccessHook(sqlProperties.createObjectAccessHookInstance())
.withProperties(sqlProperties)
.registerValueTypeAdapter(new JsonNodeTypeAdapter())
.registerValueTypeAdapter(new InstantTypeAdapter())
.build();
}
When I checked JaversSqlProperties, it is using HibernateUnproxyObjectAccessHook so I think it should be able to unproxy the entity properly before auditing it.
Javers configuration in application.yml:
javers:
mappingStyle: FIELD
algorithm: SIMPLE
commitIdGenerator: synchronized_sequence
prettyPrint: true
typeSafeValues: false
newObjectSnapshot: false
auditableAspectEnabled: true
springDataAuditableRepositoryAspectEnabled: true
sqlSchemaManagementEnabled: true
sqlGlobalIdCacheDisabled: false
prettyPrintDateFormats:
localDateTime: "dd MMM yyyy, HH:mm:ss"
zonedDateTime: "dd MMM yyyy, HH:mm:ssZ"
localDate: "dd MMM yyyy"
localTime: "HH:mm:ss"
PS: This entity has a reference to other audited entity (which is saved before this one).
Does anyone please have any idea, what could be wrong?

As a rule of thumb, you should newer treat Hibernate proxies as your Entities.
Do you use HibernateUnproxyHook? I recommend using the javers' starter. It sets up all javers' beans (including this hook).

Related

Spring boot Mongo on update: E11000 duplicate key error with #Version annotation

I have a Spring boot (v2.3.0.RELEASE) application with spring-data-mongodb (v3.0.0).
Basically when I add #Version annotation in my document, the application fails when I am trying to update an existing document and the code is as follows:
My document is as follows:
#Id
private String paymentId;
private String transactionId;
private String transactionTypeCode;
#Version
private Integer version;
My repository is as follows:
public interface PaymentRepository extends MongoRepository<Payment, String>, PaymentRepositoryCustom {
}
The update that fails is as follows:
Optional<Payment> paymentSaved = Optional.ofNullable(paymentRepository.findMaxIdByRefer(request.getAdd().getRefer()));
populatePayment(paymentSaved, payment);
paymentRepository.save(payment);
public static void populatePayment( Optional<Payment> paymentSaved, Payment payment) {
if (paymentSaved.isPresent() && !ObjectUtils.isEmpty(payment)) {
payment.setTransactionId(paymentSaved.get().getTransactionId());
payment.setCreationDate(paymentSaved.get().getCreationDate());
payment.setPaymentId(paymentSaved.get().getPaymentId());
}
}
The application fails on paymentRepository.save(payment) method with the following exception:
org.springframework.dao.DuplicateKeyException: E11000 duplicate key error collection: test.payment index: _id_ dup key: { _id: ObjectId('627a35b7f1ea29549008487e') }; nested exception is com.mongodb.MongoWriteException: E11000 duplicate key error collection: test.payment index: _id_ dup key: { _id: ObjectId('627a35b7f1ea29549008487e') }
at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:99)
at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java:2863)
at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:568)
at org.springframework.data.mongodb.core.MongoTemplate.insertDocument(MongoTemplate.java:1436)
at org.springframework.data.mongodb.core.MongoTemplate.doInsert(MongoTemplate.java:1236)
at org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:1168)
at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:84)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.springframework.data.repository.core.support.ImplementationInvocationMetadata.invoke(ImplementationInvocationMetadata.java:72)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:382)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:205)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:549)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:155)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:130)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke
It looks like it is trying to do an insert instead of update when I add the #Version annotation, any idea how i can resolve this issue please?
However, I cannot remove the #Version annotation.
I have found the issue basically on update the version was null that is why it was trying to create a new payment instead of update.I have retrieved the version from DB and now the update works fine.

Kotlin based Spring RabbitListener produces endlessloop trying to send back `kotlin.Unit`

We have a RabbitListener implemented in Kotlin. The method returns Unit, so I dont expect Spring to send a result but we are getting the following error message. It looks like Spring tries to iterprete Unit as the result and send a rabbit message back:
2021-04-16 16:39:21
msg="Execution of Rabbit message listener failed." thread="org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-2" level=WARN logger="org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler" exception="org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Listener threw exception
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.java:1746)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1636)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1551)
at jdk.internal.reflect.GeneratedMethodAccessor64.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at brave.spring.rabbit.TracingRabbitListenerAdvice.invoke(TracingRabbitListenerAdvice.java:108)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at org.springframework.amqp.rabbit.listener.$Proxy146.invokeListener(Unknown Source)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1539)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1530)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1474)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:967)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:913)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1288)
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1194)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.amqp.rabbit.listener.adapter.ReplyFailureException: Failed to send reply with payload 'InvocationResult [returnValue=kotlin.Unit, returnType=class java.lang.Object, bean=com.xxx.EventHandler#4aaf6902, method=public java.lang.Object com.xxx.EventHandler.receiveMessage(org.springframework.amqp.core.Message)]'
at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.doHandleResult(AbstractAdaptableMessageListener.java:476)
at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.handleResult(AbstractAdaptableMessageListener.java:400)
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandlerAndProcessResult(MessagingMessageListenerAdapter.java:152)
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:135)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1632)
... 20 common frames omitted
Caused by: java.lang.IllegalArgumentException: SimpleMessageConverter only supports String, byte[] and Serializable payloads, received: kotlin.Unit
at org.springframework.amqp.support.converter.SimpleMessageConverter.createMessage(SimpleMessageConverter.java:164)
at org.springframework.amqp.support.converter.AbstractMessageConverter.createMessage(AbstractMessageConverter.java:88)
at org.springframework.amqp.support.converter.AbstractMessageConverter.toMessage(AbstractMessageConverter.java:70)
at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.convert(AbstractAdaptableMessageListener.java:519)
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.buildMessage(MessagingMessageListenerAdapter.java:257)
at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.doHandleResult(AbstractAdaptableMessageListener.java:464)
... 24 common frames omitted
" time="2021-04-16 14:39:21,726"
here a simplified version of the RabbitLister:
#Component
class EventHandler {
#RabbitListener(queues = ["someQueue"])
fun receiveMessage(message: Message): Unit {
log.debug("Received message")
}
}
We use Spring Boot 2.4.4, Spring Rabbit 2.3.6 and Spring Framework 5.3.6
debugging the issue, I got the following result:
What version are you using?
This works fine for me (with and without the Unit return type)...
#RabbitListener(queues = ["foo"])
open fun listen(data: String?): Unit {
println(data)
}
Even with : Unit, I see void as the return type and null:

Cannot disable spring-data-mongodb-reactive autoconfiguration in spring-boot

No matter what I try, I cannot disable auto-configuration of spring-data-mongodb-reactive.
Properties
spring:
profiles: dev
data:
mongodb:
uri: "mongodb://user:pw#some-ip.amazonaws.com:27017/my-db"
repositories:
type: reactive
authentication-database: admin
Repository
#Repository
interface IMembersRepository: ReactiveMongoRepository<Member, String> {}
MongoConfig
#Configuration
#EnableReactiveMongoRepositories(basePackages = ["com.my.package.repository"])
class MongoConfig : AbstractReactiveMongoConfiguration() {
override fun reactiveMongoClient(): MongoClient = mongoClient()
override fun getDatabaseName(): String = "my-db"
#Bean()
fun mongoClient() = MongoClients.create()
#Bean()
override fun reactiveMongoTemplate() = ReactiveMongoTemplate(mongoClient(), databaseName)
}
AppConfig
#Configuration
#EnableWebFlux
#ComponentScan("com.my.package")
class AppConfig: WebFluxConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("api/**")
}
}
SpringBootApplication
#SpringBootApplication(exclude = [
MongoReactiveAutoConfiguration::class,
MongoReactiveDataAutoConfiguration::class,
MongoReactiveRepositoriesAutoConfiguration::class,
MongoAutoConfiguration::class,
MongoDataAutoConfiguration::class,
MongoRepositoriesAutoConfiguration::class,
EmbeddedMongoAutoConfiguration::class
])
class AstridServerApplication
fun main(args: Array<String>) {
runApplication<AstridServerApplication>(*args)
}
As you can see, I even went as far as disabling all available MongoDB auto-configs, and Boot still tries to establish connection to a local instance, which I do not have. But I did also try different combinations.
[localhost:27017] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server localhost:27017
com.mongodb.MongoSocketOpenException: Exception opening socket
at com.mongodb.internal.connection.AsynchronousSocketChannelStream$OpenCompletionHandler.failed(AsynchronousSocketChannelStream.java:117) ~[mongodb-driver-core-3.11.2.jar:na]
at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:129) ~[na:na]
at java.base/sun.nio.ch.Invoker.invokeDirect(Invoker.java:158) ~[na:na]
at java.base/sun.nio.ch.Invoker.invoke(Invoker.java:186) ~[na:na]
at java.base/sun.nio.ch.Invoker.invoke(Invoker.java:298) ~[na:na]
at java.base/sun.nio.ch.WindowsAsynchronousSocketChannelImpl$ConnectTask.failed(WindowsAsynchronousSocketChannelImpl.java:308) ~[na:na]
at java.base/sun.nio.ch.Iocp$EventHandlerTask.run(Iocp.java:389) ~[na:na]
at java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]
Caused by: java.io.IOException: The remote computer refused the network connection
at java.base/sun.nio.ch.Iocp.translateErrorToIOException(Iocp.java:299) ~[na:na]
... 5 common frames omitted
The client is connecting to the default address. I would focus on understanding why your config file isn't taking effect rather than on "disabling auto-configuration". The behavior you are seeing is consistent with the client not receiving any external configuration and using its built-in defaults.

Spring boot 2 Prometheus not pulling db metrics

I am using spring boot2 with Prometheus. we are using Postgres as db. The Prometheus url is not fetching db metrics.
Any references would be very helpful.
I have tried
#Configuration
#AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class MyConfiguration {
#Autowired
HikariDataSource dataSource;
#Bean
PostgreSQLDatabaseMetrics dbMeterics() {
return new PostgreSQLDatabaseMetrics(dataSource, "database-name");
}
}
When I hit the end point /prometheus, I get this error
java.lang.NullPointerException: null
at io.micrometer.core.instrument.binder.db.PostgreSQLDatabaseMetrics.lambda$bindTo$1(PostgreSQLDatabaseMetrics.java:101)
at io.micrometer.core.instrument.internal.DefaultGauge.value(DefaultGauge.java:40)
at io.micrometer.prometheus.PrometheusMeterRegistry.lambda$newGauge$3(PrometheusMeterRegistry.java:235)
at io.micrometer.prometheus.MicrometerCollector.collect(MicrometerCollector.java:69)
at io.prometheus.client.CollectorRegistry$MetricFamilySamplesEnumeration.findNextElement(CollectorRegistry.java:183)
at io.prometheus.client.CollectorRegistry$MetricFamilySamplesEnumeration.nextElement(CollectorRegistry.java:216)
at io.prometheus.client.CollectorRegistry$MetricFamilySamplesEnumeration.nextElement(CollectorRegistry.java:137)
at io.prometheus.client.exporter.common.TextFormat.write004(TextFormat.java:22)
at org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScrapeEndpoint.scrape(PrometheusScrapeEndpoint.java:50)
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:498)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
at org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker.invoke(ReflectiveOperationInvoker.java:76)
In line 101 the registry received via DI is used to build the pgMetrics object. Since you are getting the null pointer at this line, you might be missing the import of Prometheus registry as a dependency.

Spring data Cassandra Rest Id must be assignable to Serializable!: null

Given below Entity and Repository, I get Id must be assignable to Serializable!: null error when I access rest resource for repository.
curl -H 'Accept: application/json' http://localhost:8080/properties
{"cause":null,"message":"Id must be assignable to Serializable!: null"}
Groovy code
#Component
interface PropertyRepository extends CassandraRepository<Property, String> {
}
#Table("property_v1")
#Canonical
class Property {
#PrimaryKeyColumn(value = "name", type = PARTITIONED)
String name
#PrimaryKeyColumn(value = "environment", type = CLUSTERED)
String environment
#Column("value")
String value
}
I tried adding #Id annotation to primary key field but spring does not allow #Id and #PrimaryKeyColumn annotations on the same entity.
I get #Table types must not define both #Id and #PrimaryKeyColumn properties error.
How do I access spring data Cassandra entities over rest?
I tried using RepositoryRestResource annotation as well on Repository class but received same error.
#RepositoryRestResource(path = "/properties", collectionResourceRel = "properties")
Versions:
Spring boot: 2.0.1.RELEASE
Uses spring-boot-starter-data-cassandra, spring-boot-starter-data-rest moduldes
Exception Stacktrace:
java.lang.IllegalArgumentException: Id must be assignable to Serializable!: null
at org.springframework.util.Assert.instanceCheckFailed(Assert.java:637)
at org.springframework.util.Assert.isInstanceOf(Assert.java:537)
at org.springframework.data.rest.webmvc.support.RepositoryEntityLinks.linkToSingleResource(RepositoryEntityLinks.java:135)
at org.springframework.data.rest.core.support.DefaultSelfLinkProvider.createSelfLinkFor(DefaultSelfLinkProvider.java:68)
at org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.getSelfLinkFor(PersistentEntityResourceAssembler.java:99)
at org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.wrap(PersistentEntityResourceAssembler.java:76)
at org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler.toResource(PersistentEntityResourceAssembler.java:55)
at org.springframework.data.rest.webmvc.AbstractRepositoryRestController.entitiesToResources(AbstractRepositoryRestController.java:110)
at org.springframework.data.rest.webmvc.AbstractRepositoryRestController.toResources(AbstractRepositoryRestController.java:80)
at org.springframework.data.rest.webmvc.RepositoryEntityController.getCollectionResource(RepositoryEntityController.java:209)
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:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
Figured out the issue.
If an entity class has a composite key, spring data rest works only if I have a dedicated class for Primary Key columns.
Changing the class structure to below, enabled rest resources for spring data entities. I used a nested static class for key. But it could be very well a public class of its own.
I feel this boiler plate should be removed from developers and instead spring could look into partition key column and use it as Id.
#Component
interface PropertyRepository extends CassandraRepository<Property, Property.PropertyKey> {
}
#Table("property_v1")
#Canonical
class Property {
#PrimaryKey
PropertyKey key
#Column("value")
String value
#PrimaryKeyClass
#Canonical
static class PropertyKey implements Serializable {
#PrimaryKeyColumn(value = "name", type = PARTITIONED)
String name
#PrimaryKeyColumn(value = "environment", type = CLUSTERED)
String environment
}
}

Resources