Spring (Boot, Data Neo4j), Neo4j: cannot create @QueryResult with a Kotlin class
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I'm struggling to create a projection of a node entity Event with a Kotlin class using Spring Data Neo4j's @QueryResult and a custom @Query.
NodeEntity: Event.java
@NodeEntity
// getter, setter, ... boilerplate (lombok)
@Data @NoArgsConstructor @AllArgsConstructor
class Event {
@Id
@GeneratedValue
private Long id;
private LocalDateTime timestamp;
private String name;
}
Repo: EventRepo.java
@Repository
interface EventRepo extends Neo4jRepository<Event, Long> {
// works
@Query("MATCH (e:Event) " +
"RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name")
EventDtoJava findAsJavaDto();
// meh
@Query("MATCH (e:Event) " +
"RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name")
EventDtoKotlin findAsKotlinDto();
}
Projections: Java and Kotlin version
// Projection with a Java class: works
@QueryResult
// getter, setter, ... boilerplate (lombok)
@Data
class EventDtoJava {
private Long id;
private LocalDateTime timestamp;
private String name;
}
// Projection with a Kotlin class: meh
@QueryResult
data class EventDtoKotlin(
var id: Long,
var timestamp: LocalDateTime,
var name: String
)
The exactly same query that worked for EventDtoJava (EventRepo.findAsJavaDto()) fails with the Kotlin class (EventRepo.findAsKotlinDto()).
As a workaround I could use Java DTOs but this doesn't solve the underlying issue.
As suggested in https://stackoverflow.com/a/52475719 I already added java.time support to Neo4j's ObjectMapper.
I suspected that com.fasterxml.jackson.module:jackson-module-kotlin was missing from their ObjectMapper, but this changed nothing.
Edit: The exception can also be triggered by creating an all args constructor in EventDtoJava.
MATCH (e:Event) RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name
Exception in thread "main" org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.example.demo.EventDtoKotlin using constructor fun <init>(kotlin.Long, java.time.LocalDateTime, kotlin.String): com.example.demo.EventDtoKotlin with arguments 0,2019-01-03T15:11:04.581095,test!
at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:228)
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:84)
at org.springframework.data.neo4j.conversion.Neo4jOgmEntityInstantiatorAdapter.createInstance(Neo4jOgmEntityInstantiatorAdapter.java:58)
at org.springframework.data.neo4j.repository.query.QueryResultInstantiator.createInstance(QueryResultInstantiator.java:52)
at org.neo4j.ogm.metadata.reflect.EntityFactory.instantiate(EntityFactory.java:121)
at org.neo4j.ogm.metadata.reflect.EntityFactory.newObject(EntityFactory.java:90)
at org.neo4j.ogm.context.SingleUseEntityMapper.map(SingleUseEntityMapper.java:91)
at org.springframework.data.neo4j.repository.query.CustomResultConverter.convert(CustomResultConverter.java:80)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:210)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:166)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.doExecute(GraphRepositoryQuery.java:72)
at org.springframework.data.neo4j.repository.query.AbstractGraphRepositoryQuery.execute(AbstractGraphRepositoryQuery.java:52)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.example.demo.$Proxy97.findAsKotlinDto(Unknown Source)
at com.example.demo.DemoApplication.main(DemoApplication.java:24)
Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class java.time.LocalDateTime (java.lang.String and java.time.LocalDateTime are in module java.base of loader 'bootstrap')
at com.example.demo.EventDtoKotlin_Instantiator_5tss1f.newInstance(Unknown Source)
at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:226)
... 31 more
I tried to wrap e.timestamp in localdatetime() without success:
MATCH (e:Event) RETURN id(e) AS id, localdatetime(e.timestamp) AS timestamp, e.name AS name
// with MATCH (e:Event) RETURN id(e) AS id, localdatetime(e.timestamp) AS timestamp, e.name AS name
Exception in thread "main" java.lang.ClassCastException: class java.time.LocalDateTime cannot be cast to class java.lang.String (java.time.LocalDateTime and java.lang.String are in module java.base of loader 'bootstrap')
at org.neo4j.ogm.typeconversion.LocalDateTimeStringConverter.toEntityAttribute(LocalDateTimeStringConverter.java:25)
at org.neo4j.ogm.metadata.FieldInfo.write(FieldInfo.java:368)
at org.neo4j.ogm.context.SingleUseEntityMapper.writeProperty(SingleUseEntityMapper.java:143)
at org.neo4j.ogm.context.SingleUseEntityMapper.setPropertiesOnEntity(SingleUseEntityMapper.java:99)
at org.neo4j.ogm.context.SingleUseEntityMapper.map(SingleUseEntityMapper.java:92)
at org.springframework.data.neo4j.repository.query.CustomResultConverter.convert(CustomResultConverter.java:80)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:210)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:166)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.doExecute(GraphRepositoryQuery.java:72)
at org.springframework.data.neo4j.repository.query.AbstractGraphRepositoryQuery.execute(AbstractGraphRepositoryQuery.java:52)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.example.demo.$Proxy97.findAsJavaDto(Unknown Source)
at com.example.demo.DemoApplication.main(DemoApplication.java:23)
Repro
Create a Spring Initializer project with Gradle and replace the build.gradle with the following content:
build.gradle
plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.11"
id("io.spring.dependency-management") version "1.0.6.RELEASE"
id("org.springframework.boot") version "2.1.1.RELEASE"
id("org.jetbrains.kotlin.plugin.spring") version "1.3.11"
id("org.jetbrains.kotlin.plugin.noarg") version "1.3.11"
}
repositories {
jcenter()
}
sourceCompatibility = 11
targetCompatibility = 11
ext['jackson.version'] = '2.9.8'
noArg {
annotation("org.neo4j.ogm.annotation.NodeEntity")
annotation("org.neo4j.ogm.annotation.RelationshipEntity")
annotation("org.springframework.data.neo4j.annotation.QueryResult")
}
compileKotlin {
kotlinOptions {
jvmTarget = 1.8
javaParameters = true
}
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation('org.springframework.boot:spring-boot-starter-json')
// jackson kotlin classes support
implementation('com.fasterxml.jackson.module:jackson-module-kotlin')
implementation('org.springframework.boot:spring-boot-starter-data-neo4j')
runtimeOnly('org.neo4j:neo4j:3.5.1')
runtimeOnly('org.neo4j:neo4j-ogm-embedded-driver:3.1.5')
compileOnly('org.projectlombok:lombok')
annotationProcessor('org.projectlombok:lombok')
}
DemoApplication.java
package com.example.demo;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.kotlin.KotlinModule;
import lombok.val;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.time.LocalDateTime;
import java.util.Objects;
@SpringBootApplication
public class DemoApplication {
public static void main(String args) {
var ctx = SpringApplication.run(DemoApplication.class, args);
setupNeo4jJavaTimeSupport();
var repo = ctx.getBean(EventRepo.class);
var e = repo.save(new Event(null, LocalDateTime.now(), "test!"));
System.out.println();
System.out.println("e = " + e);
System.out.println("java: " + Objects.requireNonNull(repo.findAsJavaDto()));
System.out.println("kotlin" + Objects.requireNonNull(repo.findAsKotlinDto()));
}
private static void setupNeo4jJavaTimeSupport() {
// see https://stackoverflow.com/a/52475719
var ogmObjectMapper = org.neo4j.ogm.config.ObjectMapperFactory.objectMapper();
ogmObjectMapper.registerModule(new JavaTimeModule());
ogmObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
ogmObjectMapper.registerModule(new KotlinModule());
}
}
kotlin neo4j spring-data-neo4j
add a comment |
I'm struggling to create a projection of a node entity Event with a Kotlin class using Spring Data Neo4j's @QueryResult and a custom @Query.
NodeEntity: Event.java
@NodeEntity
// getter, setter, ... boilerplate (lombok)
@Data @NoArgsConstructor @AllArgsConstructor
class Event {
@Id
@GeneratedValue
private Long id;
private LocalDateTime timestamp;
private String name;
}
Repo: EventRepo.java
@Repository
interface EventRepo extends Neo4jRepository<Event, Long> {
// works
@Query("MATCH (e:Event) " +
"RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name")
EventDtoJava findAsJavaDto();
// meh
@Query("MATCH (e:Event) " +
"RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name")
EventDtoKotlin findAsKotlinDto();
}
Projections: Java and Kotlin version
// Projection with a Java class: works
@QueryResult
// getter, setter, ... boilerplate (lombok)
@Data
class EventDtoJava {
private Long id;
private LocalDateTime timestamp;
private String name;
}
// Projection with a Kotlin class: meh
@QueryResult
data class EventDtoKotlin(
var id: Long,
var timestamp: LocalDateTime,
var name: String
)
The exactly same query that worked for EventDtoJava (EventRepo.findAsJavaDto()) fails with the Kotlin class (EventRepo.findAsKotlinDto()).
As a workaround I could use Java DTOs but this doesn't solve the underlying issue.
As suggested in https://stackoverflow.com/a/52475719 I already added java.time support to Neo4j's ObjectMapper.
I suspected that com.fasterxml.jackson.module:jackson-module-kotlin was missing from their ObjectMapper, but this changed nothing.
Edit: The exception can also be triggered by creating an all args constructor in EventDtoJava.
MATCH (e:Event) RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name
Exception in thread "main" org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.example.demo.EventDtoKotlin using constructor fun <init>(kotlin.Long, java.time.LocalDateTime, kotlin.String): com.example.demo.EventDtoKotlin with arguments 0,2019-01-03T15:11:04.581095,test!
at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:228)
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:84)
at org.springframework.data.neo4j.conversion.Neo4jOgmEntityInstantiatorAdapter.createInstance(Neo4jOgmEntityInstantiatorAdapter.java:58)
at org.springframework.data.neo4j.repository.query.QueryResultInstantiator.createInstance(QueryResultInstantiator.java:52)
at org.neo4j.ogm.metadata.reflect.EntityFactory.instantiate(EntityFactory.java:121)
at org.neo4j.ogm.metadata.reflect.EntityFactory.newObject(EntityFactory.java:90)
at org.neo4j.ogm.context.SingleUseEntityMapper.map(SingleUseEntityMapper.java:91)
at org.springframework.data.neo4j.repository.query.CustomResultConverter.convert(CustomResultConverter.java:80)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:210)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:166)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.doExecute(GraphRepositoryQuery.java:72)
at org.springframework.data.neo4j.repository.query.AbstractGraphRepositoryQuery.execute(AbstractGraphRepositoryQuery.java:52)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.example.demo.$Proxy97.findAsKotlinDto(Unknown Source)
at com.example.demo.DemoApplication.main(DemoApplication.java:24)
Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class java.time.LocalDateTime (java.lang.String and java.time.LocalDateTime are in module java.base of loader 'bootstrap')
at com.example.demo.EventDtoKotlin_Instantiator_5tss1f.newInstance(Unknown Source)
at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:226)
... 31 more
I tried to wrap e.timestamp in localdatetime() without success:
MATCH (e:Event) RETURN id(e) AS id, localdatetime(e.timestamp) AS timestamp, e.name AS name
// with MATCH (e:Event) RETURN id(e) AS id, localdatetime(e.timestamp) AS timestamp, e.name AS name
Exception in thread "main" java.lang.ClassCastException: class java.time.LocalDateTime cannot be cast to class java.lang.String (java.time.LocalDateTime and java.lang.String are in module java.base of loader 'bootstrap')
at org.neo4j.ogm.typeconversion.LocalDateTimeStringConverter.toEntityAttribute(LocalDateTimeStringConverter.java:25)
at org.neo4j.ogm.metadata.FieldInfo.write(FieldInfo.java:368)
at org.neo4j.ogm.context.SingleUseEntityMapper.writeProperty(SingleUseEntityMapper.java:143)
at org.neo4j.ogm.context.SingleUseEntityMapper.setPropertiesOnEntity(SingleUseEntityMapper.java:99)
at org.neo4j.ogm.context.SingleUseEntityMapper.map(SingleUseEntityMapper.java:92)
at org.springframework.data.neo4j.repository.query.CustomResultConverter.convert(CustomResultConverter.java:80)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:210)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:166)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.doExecute(GraphRepositoryQuery.java:72)
at org.springframework.data.neo4j.repository.query.AbstractGraphRepositoryQuery.execute(AbstractGraphRepositoryQuery.java:52)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.example.demo.$Proxy97.findAsJavaDto(Unknown Source)
at com.example.demo.DemoApplication.main(DemoApplication.java:23)
Repro
Create a Spring Initializer project with Gradle and replace the build.gradle with the following content:
build.gradle
plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.11"
id("io.spring.dependency-management") version "1.0.6.RELEASE"
id("org.springframework.boot") version "2.1.1.RELEASE"
id("org.jetbrains.kotlin.plugin.spring") version "1.3.11"
id("org.jetbrains.kotlin.plugin.noarg") version "1.3.11"
}
repositories {
jcenter()
}
sourceCompatibility = 11
targetCompatibility = 11
ext['jackson.version'] = '2.9.8'
noArg {
annotation("org.neo4j.ogm.annotation.NodeEntity")
annotation("org.neo4j.ogm.annotation.RelationshipEntity")
annotation("org.springframework.data.neo4j.annotation.QueryResult")
}
compileKotlin {
kotlinOptions {
jvmTarget = 1.8
javaParameters = true
}
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation('org.springframework.boot:spring-boot-starter-json')
// jackson kotlin classes support
implementation('com.fasterxml.jackson.module:jackson-module-kotlin')
implementation('org.springframework.boot:spring-boot-starter-data-neo4j')
runtimeOnly('org.neo4j:neo4j:3.5.1')
runtimeOnly('org.neo4j:neo4j-ogm-embedded-driver:3.1.5')
compileOnly('org.projectlombok:lombok')
annotationProcessor('org.projectlombok:lombok')
}
DemoApplication.java
package com.example.demo;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.kotlin.KotlinModule;
import lombok.val;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.time.LocalDateTime;
import java.util.Objects;
@SpringBootApplication
public class DemoApplication {
public static void main(String args) {
var ctx = SpringApplication.run(DemoApplication.class, args);
setupNeo4jJavaTimeSupport();
var repo = ctx.getBean(EventRepo.class);
var e = repo.save(new Event(null, LocalDateTime.now(), "test!"));
System.out.println();
System.out.println("e = " + e);
System.out.println("java: " + Objects.requireNonNull(repo.findAsJavaDto()));
System.out.println("kotlin" + Objects.requireNonNull(repo.findAsKotlinDto()));
}
private static void setupNeo4jJavaTimeSupport() {
// see https://stackoverflow.com/a/52475719
var ogmObjectMapper = org.neo4j.ogm.config.ObjectMapperFactory.objectMapper();
ogmObjectMapper.registerModule(new JavaTimeModule());
ogmObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
ogmObjectMapper.registerModule(new KotlinModule());
}
}
kotlin neo4j spring-data-neo4j
add a comment |
I'm struggling to create a projection of a node entity Event with a Kotlin class using Spring Data Neo4j's @QueryResult and a custom @Query.
NodeEntity: Event.java
@NodeEntity
// getter, setter, ... boilerplate (lombok)
@Data @NoArgsConstructor @AllArgsConstructor
class Event {
@Id
@GeneratedValue
private Long id;
private LocalDateTime timestamp;
private String name;
}
Repo: EventRepo.java
@Repository
interface EventRepo extends Neo4jRepository<Event, Long> {
// works
@Query("MATCH (e:Event) " +
"RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name")
EventDtoJava findAsJavaDto();
// meh
@Query("MATCH (e:Event) " +
"RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name")
EventDtoKotlin findAsKotlinDto();
}
Projections: Java and Kotlin version
// Projection with a Java class: works
@QueryResult
// getter, setter, ... boilerplate (lombok)
@Data
class EventDtoJava {
private Long id;
private LocalDateTime timestamp;
private String name;
}
// Projection with a Kotlin class: meh
@QueryResult
data class EventDtoKotlin(
var id: Long,
var timestamp: LocalDateTime,
var name: String
)
The exactly same query that worked for EventDtoJava (EventRepo.findAsJavaDto()) fails with the Kotlin class (EventRepo.findAsKotlinDto()).
As a workaround I could use Java DTOs but this doesn't solve the underlying issue.
As suggested in https://stackoverflow.com/a/52475719 I already added java.time support to Neo4j's ObjectMapper.
I suspected that com.fasterxml.jackson.module:jackson-module-kotlin was missing from their ObjectMapper, but this changed nothing.
Edit: The exception can also be triggered by creating an all args constructor in EventDtoJava.
MATCH (e:Event) RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name
Exception in thread "main" org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.example.demo.EventDtoKotlin using constructor fun <init>(kotlin.Long, java.time.LocalDateTime, kotlin.String): com.example.demo.EventDtoKotlin with arguments 0,2019-01-03T15:11:04.581095,test!
at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:228)
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:84)
at org.springframework.data.neo4j.conversion.Neo4jOgmEntityInstantiatorAdapter.createInstance(Neo4jOgmEntityInstantiatorAdapter.java:58)
at org.springframework.data.neo4j.repository.query.QueryResultInstantiator.createInstance(QueryResultInstantiator.java:52)
at org.neo4j.ogm.metadata.reflect.EntityFactory.instantiate(EntityFactory.java:121)
at org.neo4j.ogm.metadata.reflect.EntityFactory.newObject(EntityFactory.java:90)
at org.neo4j.ogm.context.SingleUseEntityMapper.map(SingleUseEntityMapper.java:91)
at org.springframework.data.neo4j.repository.query.CustomResultConverter.convert(CustomResultConverter.java:80)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:210)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:166)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.doExecute(GraphRepositoryQuery.java:72)
at org.springframework.data.neo4j.repository.query.AbstractGraphRepositoryQuery.execute(AbstractGraphRepositoryQuery.java:52)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.example.demo.$Proxy97.findAsKotlinDto(Unknown Source)
at com.example.demo.DemoApplication.main(DemoApplication.java:24)
Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class java.time.LocalDateTime (java.lang.String and java.time.LocalDateTime are in module java.base of loader 'bootstrap')
at com.example.demo.EventDtoKotlin_Instantiator_5tss1f.newInstance(Unknown Source)
at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:226)
... 31 more
I tried to wrap e.timestamp in localdatetime() without success:
MATCH (e:Event) RETURN id(e) AS id, localdatetime(e.timestamp) AS timestamp, e.name AS name
// with MATCH (e:Event) RETURN id(e) AS id, localdatetime(e.timestamp) AS timestamp, e.name AS name
Exception in thread "main" java.lang.ClassCastException: class java.time.LocalDateTime cannot be cast to class java.lang.String (java.time.LocalDateTime and java.lang.String are in module java.base of loader 'bootstrap')
at org.neo4j.ogm.typeconversion.LocalDateTimeStringConverter.toEntityAttribute(LocalDateTimeStringConverter.java:25)
at org.neo4j.ogm.metadata.FieldInfo.write(FieldInfo.java:368)
at org.neo4j.ogm.context.SingleUseEntityMapper.writeProperty(SingleUseEntityMapper.java:143)
at org.neo4j.ogm.context.SingleUseEntityMapper.setPropertiesOnEntity(SingleUseEntityMapper.java:99)
at org.neo4j.ogm.context.SingleUseEntityMapper.map(SingleUseEntityMapper.java:92)
at org.springframework.data.neo4j.repository.query.CustomResultConverter.convert(CustomResultConverter.java:80)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:210)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:166)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.doExecute(GraphRepositoryQuery.java:72)
at org.springframework.data.neo4j.repository.query.AbstractGraphRepositoryQuery.execute(AbstractGraphRepositoryQuery.java:52)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.example.demo.$Proxy97.findAsJavaDto(Unknown Source)
at com.example.demo.DemoApplication.main(DemoApplication.java:23)
Repro
Create a Spring Initializer project with Gradle and replace the build.gradle with the following content:
build.gradle
plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.11"
id("io.spring.dependency-management") version "1.0.6.RELEASE"
id("org.springframework.boot") version "2.1.1.RELEASE"
id("org.jetbrains.kotlin.plugin.spring") version "1.3.11"
id("org.jetbrains.kotlin.plugin.noarg") version "1.3.11"
}
repositories {
jcenter()
}
sourceCompatibility = 11
targetCompatibility = 11
ext['jackson.version'] = '2.9.8'
noArg {
annotation("org.neo4j.ogm.annotation.NodeEntity")
annotation("org.neo4j.ogm.annotation.RelationshipEntity")
annotation("org.springframework.data.neo4j.annotation.QueryResult")
}
compileKotlin {
kotlinOptions {
jvmTarget = 1.8
javaParameters = true
}
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation('org.springframework.boot:spring-boot-starter-json')
// jackson kotlin classes support
implementation('com.fasterxml.jackson.module:jackson-module-kotlin')
implementation('org.springframework.boot:spring-boot-starter-data-neo4j')
runtimeOnly('org.neo4j:neo4j:3.5.1')
runtimeOnly('org.neo4j:neo4j-ogm-embedded-driver:3.1.5')
compileOnly('org.projectlombok:lombok')
annotationProcessor('org.projectlombok:lombok')
}
DemoApplication.java
package com.example.demo;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.kotlin.KotlinModule;
import lombok.val;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.time.LocalDateTime;
import java.util.Objects;
@SpringBootApplication
public class DemoApplication {
public static void main(String args) {
var ctx = SpringApplication.run(DemoApplication.class, args);
setupNeo4jJavaTimeSupport();
var repo = ctx.getBean(EventRepo.class);
var e = repo.save(new Event(null, LocalDateTime.now(), "test!"));
System.out.println();
System.out.println("e = " + e);
System.out.println("java: " + Objects.requireNonNull(repo.findAsJavaDto()));
System.out.println("kotlin" + Objects.requireNonNull(repo.findAsKotlinDto()));
}
private static void setupNeo4jJavaTimeSupport() {
// see https://stackoverflow.com/a/52475719
var ogmObjectMapper = org.neo4j.ogm.config.ObjectMapperFactory.objectMapper();
ogmObjectMapper.registerModule(new JavaTimeModule());
ogmObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
ogmObjectMapper.registerModule(new KotlinModule());
}
}
kotlin neo4j spring-data-neo4j
I'm struggling to create a projection of a node entity Event with a Kotlin class using Spring Data Neo4j's @QueryResult and a custom @Query.
NodeEntity: Event.java
@NodeEntity
// getter, setter, ... boilerplate (lombok)
@Data @NoArgsConstructor @AllArgsConstructor
class Event {
@Id
@GeneratedValue
private Long id;
private LocalDateTime timestamp;
private String name;
}
Repo: EventRepo.java
@Repository
interface EventRepo extends Neo4jRepository<Event, Long> {
// works
@Query("MATCH (e:Event) " +
"RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name")
EventDtoJava findAsJavaDto();
// meh
@Query("MATCH (e:Event) " +
"RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name")
EventDtoKotlin findAsKotlinDto();
}
Projections: Java and Kotlin version
// Projection with a Java class: works
@QueryResult
// getter, setter, ... boilerplate (lombok)
@Data
class EventDtoJava {
private Long id;
private LocalDateTime timestamp;
private String name;
}
// Projection with a Kotlin class: meh
@QueryResult
data class EventDtoKotlin(
var id: Long,
var timestamp: LocalDateTime,
var name: String
)
The exactly same query that worked for EventDtoJava (EventRepo.findAsJavaDto()) fails with the Kotlin class (EventRepo.findAsKotlinDto()).
As a workaround I could use Java DTOs but this doesn't solve the underlying issue.
As suggested in https://stackoverflow.com/a/52475719 I already added java.time support to Neo4j's ObjectMapper.
I suspected that com.fasterxml.jackson.module:jackson-module-kotlin was missing from their ObjectMapper, but this changed nothing.
Edit: The exception can also be triggered by creating an all args constructor in EventDtoJava.
MATCH (e:Event) RETURN id(e) AS id, e.timestamp AS timestamp, e.name AS name
Exception in thread "main" org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.example.demo.EventDtoKotlin using constructor fun <init>(kotlin.Long, java.time.LocalDateTime, kotlin.String): com.example.demo.EventDtoKotlin with arguments 0,2019-01-03T15:11:04.581095,test!
at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:228)
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:84)
at org.springframework.data.neo4j.conversion.Neo4jOgmEntityInstantiatorAdapter.createInstance(Neo4jOgmEntityInstantiatorAdapter.java:58)
at org.springframework.data.neo4j.repository.query.QueryResultInstantiator.createInstance(QueryResultInstantiator.java:52)
at org.neo4j.ogm.metadata.reflect.EntityFactory.instantiate(EntityFactory.java:121)
at org.neo4j.ogm.metadata.reflect.EntityFactory.newObject(EntityFactory.java:90)
at org.neo4j.ogm.context.SingleUseEntityMapper.map(SingleUseEntityMapper.java:91)
at org.springframework.data.neo4j.repository.query.CustomResultConverter.convert(CustomResultConverter.java:80)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:210)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:166)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.doExecute(GraphRepositoryQuery.java:72)
at org.springframework.data.neo4j.repository.query.AbstractGraphRepositoryQuery.execute(AbstractGraphRepositoryQuery.java:52)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.example.demo.$Proxy97.findAsKotlinDto(Unknown Source)
at com.example.demo.DemoApplication.main(DemoApplication.java:24)
Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class java.time.LocalDateTime (java.lang.String and java.time.LocalDateTime are in module java.base of loader 'bootstrap')
at com.example.demo.EventDtoKotlin_Instantiator_5tss1f.newInstance(Unknown Source)
at org.springframework.data.convert.ClassGeneratingEntityInstantiator$EntityInstantiatorAdapter.createInstance(ClassGeneratingEntityInstantiator.java:226)
... 31 more
I tried to wrap e.timestamp in localdatetime() without success:
MATCH (e:Event) RETURN id(e) AS id, localdatetime(e.timestamp) AS timestamp, e.name AS name
// with MATCH (e:Event) RETURN id(e) AS id, localdatetime(e.timestamp) AS timestamp, e.name AS name
Exception in thread "main" java.lang.ClassCastException: class java.time.LocalDateTime cannot be cast to class java.lang.String (java.time.LocalDateTime and java.lang.String are in module java.base of loader 'bootstrap')
at org.neo4j.ogm.typeconversion.LocalDateTimeStringConverter.toEntityAttribute(LocalDateTimeStringConverter.java:25)
at org.neo4j.ogm.metadata.FieldInfo.write(FieldInfo.java:368)
at org.neo4j.ogm.context.SingleUseEntityMapper.writeProperty(SingleUseEntityMapper.java:143)
at org.neo4j.ogm.context.SingleUseEntityMapper.setPropertiesOnEntity(SingleUseEntityMapper.java:99)
at org.neo4j.ogm.context.SingleUseEntityMapper.map(SingleUseEntityMapper.java:92)
at org.springframework.data.neo4j.repository.query.CustomResultConverter.convert(CustomResultConverter.java:80)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:210)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:224)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:166)
at org.springframework.data.neo4j.repository.query.GraphRepositoryQuery.doExecute(GraphRepositoryQuery.java:72)
at org.springframework.data.neo4j.repository.query.AbstractGraphRepositoryQuery.execute(AbstractGraphRepositoryQuery.java:52)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.example.demo.$Proxy97.findAsJavaDto(Unknown Source)
at com.example.demo.DemoApplication.main(DemoApplication.java:23)
Repro
Create a Spring Initializer project with Gradle and replace the build.gradle with the following content:
build.gradle
plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.11"
id("io.spring.dependency-management") version "1.0.6.RELEASE"
id("org.springframework.boot") version "2.1.1.RELEASE"
id("org.jetbrains.kotlin.plugin.spring") version "1.3.11"
id("org.jetbrains.kotlin.plugin.noarg") version "1.3.11"
}
repositories {
jcenter()
}
sourceCompatibility = 11
targetCompatibility = 11
ext['jackson.version'] = '2.9.8'
noArg {
annotation("org.neo4j.ogm.annotation.NodeEntity")
annotation("org.neo4j.ogm.annotation.RelationshipEntity")
annotation("org.springframework.data.neo4j.annotation.QueryResult")
}
compileKotlin {
kotlinOptions {
jvmTarget = 1.8
javaParameters = true
}
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation('org.springframework.boot:spring-boot-starter-json')
// jackson kotlin classes support
implementation('com.fasterxml.jackson.module:jackson-module-kotlin')
implementation('org.springframework.boot:spring-boot-starter-data-neo4j')
runtimeOnly('org.neo4j:neo4j:3.5.1')
runtimeOnly('org.neo4j:neo4j-ogm-embedded-driver:3.1.5')
compileOnly('org.projectlombok:lombok')
annotationProcessor('org.projectlombok:lombok')
}
DemoApplication.java
package com.example.demo;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.kotlin.KotlinModule;
import lombok.val;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.time.LocalDateTime;
import java.util.Objects;
@SpringBootApplication
public class DemoApplication {
public static void main(String args) {
var ctx = SpringApplication.run(DemoApplication.class, args);
setupNeo4jJavaTimeSupport();
var repo = ctx.getBean(EventRepo.class);
var e = repo.save(new Event(null, LocalDateTime.now(), "test!"));
System.out.println();
System.out.println("e = " + e);
System.out.println("java: " + Objects.requireNonNull(repo.findAsJavaDto()));
System.out.println("kotlin" + Objects.requireNonNull(repo.findAsKotlinDto()));
}
private static void setupNeo4jJavaTimeSupport() {
// see https://stackoverflow.com/a/52475719
var ogmObjectMapper = org.neo4j.ogm.config.ObjectMapperFactory.objectMapper();
ogmObjectMapper.registerModule(new JavaTimeModule());
ogmObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
ogmObjectMapper.registerModule(new KotlinModule());
}
}
kotlin neo4j spring-data-neo4j
kotlin neo4j spring-data-neo4j
edited Jan 3 at 16:45
ingmak
asked Jan 3 at 15:08
ingmakingmak
6016
6016
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54024927%2fspring-boot-data-neo4j-neo4j-cannot-create-queryresult-with-a-kotlin-class%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54024927%2fspring-boot-data-neo4j-neo4j-cannot-create-queryresult-with-a-kotlin-class%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
