Announcement Announcement Module
Collapse
No announcement yet.
Inheritance question for Spring Data Neo4j Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Inheritance question for Spring Data Neo4j

    Hi,
    I'm running into a problem with Spring Data Neo4j and inheritance.
    My model looks like:
    @NodeEntity
    public abstract class Shape implements IEntity {
    @GraphId
    private Long id;
    }
    and
    public class Polygon extends Shape { ... }
    public class Circle extends Shape { ... }

    Now, I'm using a simple DAO:
    public interface IShapeNeo4JDAO extends GraphRepository<Shape> { ... }

    When doing:
    shapeDao.findAll();
    I am getting:
    Code:
    java.lang.IllegalArgumentException: java.lang.InstantiationException
    	at org.springframework.data.neo4j.support.mapping.AbstractConstructorEntityInstantiator.createEntityFromState(AbstractConstructorEntityInstantiator.java:63)
    	at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedInstantiator.createEntityFromState(Neo4jEntityPersister.java:133)
    	at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedInstantiator.createEntityFromState(Neo4jEntityPersister.java:120)
    	at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.read(Neo4jEntityConverterImpl.java:84)
    	at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.read(Neo4jEntityPersister.java:168)
    	at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.createEntityFromState(Neo4jEntityPersister.java:186)
    	at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.projectTo(Neo4jEntityPersister.java:213)
    	at org.springframework.data.neo4j.support.conversion.EntityResultConverter.doConvert(EntityResultConverter.java:51)
    	at org.springframework.data.neo4j.conversion.DefaultConverter.convert(DefaultConverter.java:43)
    	at org.springframework.data.neo4j.support.conversion.EntityResultConverter.convert(EntityResultConverter.java:82)
    	at org.springframework.data.neo4j.conversion.QueryResultBuilder$1.convert(QueryResultBuilder.java:102)
    	at org.springframework.data.neo4j.conversion.QueryResultBuilder$1.access$300(QueryResultBuilder.java:81)
    	at org.springframework.data.neo4j.conversion.QueryResultBuilder$1$1.underlyingObjectToObject(QueryResultBuilder.java:120)
    	at org.neo4j.helpers.collection.IteratorWrapper.next(IteratorWrapper.java:47)
    	at com.google.common.collect.Lists.newArrayList(Lists.java:145)
    	at com.google.common.collect.Lists.newArrayList(Lists.java:125)
    	at org.rest.persistence.service.AbstractService.findAll(AbstractService.java:52)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:601)
    	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    	at $Proxy61.findAll(Unknown Source)
    	at com.geogrep.persistence.service.impl.ShapePersistenceIntegrationTest.givenAnEntityExists_whenEntitiesAreRetrieved_thenTheExistingEntityIsIndeedAmongThem(ShapePersistenceIntegrationTest.java:88)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:601)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    Caused by: java.lang.InstantiationException
    	at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
    	at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    	at org.springframework.data.neo4j.support.mapping.AbstractConstructorEntityInstantiator$2.create(AbstractConstructorEntityInstantiator.java:109)
    	at org.springframework.data.neo4j.support.mapping.AbstractConstructorEntityInstantiator.createEntityFromState(AbstractConstructorEntityInstantiator.java:56)
    	... 57 more
    Which kind of makes sense, as the type information is for Shape, so Shape is being instantiated (and fails because is abstract). Is there any way to inform Spring Data about the type information so that the result of the findAll() operation would be a list containing the correct Circle and Polygon entities?
    If not, what's the best way to construct this findAll operation - I'd like to be able to retrieve all shapes (entities that extend Shape) in the system.
    Any help is appreciated.
    Thanks.
    Eugen.

  • #2
    Update: the much weirder behavior is that this exception happens inconsistently - one time, findAll() actually returns as expected, a mixture of Circle and Polygon, and some other time is fails with that exception; running the exact same tests again results in another test failing and another one passing - extremely strange and non deterministic. It may be related to the fact that the node instantiators are cached, so, depending on the order the tests run in, a cached instantiator will be used one time and a fresh one the next run, when the order of the tests is different.
    Last edited by eugenparaschiv; Jun 26th, 2012, 06:20 PM.

    Comment


    • #3
      Turns out that it was the way I was persisting the entities - persisting them via the DAOs of the concrete child classes stores the type information properly; persisting them via the more generic DAO (for Shape) will not.

      Comment


      • #4
        I have found an extension to this problem. The solutions presented here works if you are not using the @TypAlias annotation. When using the @TypeAlias annotation the class lookup does not work which i kind of get but at the same time should this not be mapped to some class by the code that scans the annotations?

        The solution is to remove the @TypeAlias annotations from the inheritance tree. Unfortunately this also means that you will potentially brake your graph mapping by refactoring...

        Comment


        • #5
          Actually TypeAlias was explicitely added to support inheritance hierarchies, can you provide a failing unit-test?

          Thanks a lot

          Michael

          Comment


          • #6
            Have you guys figured out a better solution for this issue. I am using TypeAlias as well, and things do not appear to work correctly until I do a first save. Once initial save has been executed consequent finds work just fine, however, if I do a find first, I get an exception mentioned at start of this thread. It appears, that something is not being scanned before initial save is done. Is there something that I am missing? Almost feels like something similar to context-component-scan, is missing in my wiring.

            Comment

            Working...
            X