neo4j / neo4j-ogm

Java Object-Graph Mapping Library for Neo4j
https://neo4j.com/docs/ogm-manual/
Apache License 2.0
337 stars 164 forks source link

Loading fails with IllegalArgumentException when using spring boot 2.0.0.M7 #444

Closed chriskazakos closed 6 years ago

chriskazakos commented 6 years ago
public abstract class Neo4jObject implements Serializable {
    protected Long id;
}
@NodeEntity(label = NodeType.Supplier)
public class SupplierNode extends Neo4jObject {
    @Index(unique = true)
    private Long supplierId;
}
@Repository
public interface SupplierNodeRepository extends Neo4jRepository<SupplierNode, Long> {

    SupplierNode findBySupplierId(Long supplierId);
}

The issue happens when loading a node or after saving it (probably when it tries to set the id)

This issue seems not to exist when using spring boot 2.0.0.M5.

Current Behavior

Fails with the following exception:

Caused by: java.lang.IllegalArgumentException: Can not set java.lang.Long field com.xxx.neo4j.node.Neo4jObject.id to com.xxx.neo4j.node.SupplierNode
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
    at java.lang.reflect.Field.get(Field.java:393)
    at org.neo4j.ogm.metadata.FieldInfo.read(FieldInfo.java:373)
    at org.neo4j.ogm.metadata.FieldInfo.readProperty(FieldInfo.java:432)
    at org.neo4j.ogm.utils.EntityUtils.identity(EntityUtils.java:54)
    at org.neo4j.ogm.context.MappingContext.nativeId(MappingContext.java:475)
    at org.neo4j.ogm.context.EntityGraphMapper.getNodeBuilder(EntityGraphMapper.java:278)
    at org.neo4j.ogm.context.EntityGraphMapper.mapEntity(EntityGraphMapper.java:216)
    at org.neo4j.ogm.context.EntityGraphMapper.map(EntityGraphMapper.java:127)
    at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:80)
    at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:41)
    at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:451)
    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:497)
    at org.springframework.data.neo4j.transaction.SharedSessionCreator$SharedSessionInvocationHandler.invoke(SharedSessionCreator.java:131)
    at com.sun.proxy.$Proxy113.save(Unknown Source)
    at org.springframework.data.neo4j.repository.support.SimpleNeo4jRepository.save(SimpleNeo4jRepository.java:73)
    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:497)
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377)
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:636)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:600)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:580)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    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:185)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy122.save(Unknown Source)

Your Environment

meistermeier commented 6 years ago

Tried to reproduce it but it works with SpringBoot-M7/SDN-5.0.2 (and of course SpringBoot-M5/SDN-5.0.0). Can you provide a sample or a test method with all needed configuration, if there is any?

StefanPenndorf commented 6 years ago

I had the same issue and could track it down to a spring-dev-tools related thing. If spring-dev-tools is enabled the current entity will be loaded in spring dev-tools class loader but meta data in MetaData refers to Class from Sun class loader. Thus identityField.readProperty(entity); fails, because identifiyField refers to a Class from Sun ClassLoader and entity.getClass() refers to a Class from Spring Dev Tools ClassLoader.

StefanPenndorf commented 6 years ago

Might be related to #374 but this issue was solved in 3.0.2 which is the version used by @helocabalus and me.

I could not find any working solution with a previous version auf neither spring boot nor neo4j ogm (tried several combinations of spring boot M5-M7 and neo4j-ogm 3.0.0/3.0.1/3.0.2)

meistermeier commented 6 years ago

Thanks for the detailed information. We will investigate this.

frant-hartm commented 6 years ago

Found the cause for this issue between M5 working and M6/7 not working.

We upgraded fast classpath scanner library between 3.0.0 and 3.0.1 and now it gives the domain class loaded by Laucher$AppClassLoader, instead of one loaded by RestartClassLoader.

We have been playing Whac-A-Mole with these reload issues.

Testing this manually for each release is not feasible, integration tests for these are hard to write and maintain, environment specific and usually flaky.

Suggestions how to improve this welcome.

meistermeier commented 6 years ago

This will be part of the upcoming 3.1.0 release that will be API compatible with the latest SDN release.