Announcement Announcement Module
Collapse
No announcement yet.
Understanding Entity Persistent State Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Understanding Entity Persistent State

    I'm trying to understand the nature of Node persistent states for running my unit tests. I've setup a helper class that generates domain objects for testing purposes. I only want a limited number of objects created in order to easily see that the relationships are getting created correctly in the graph. So to do this, once I create them in my helper class, I'm storing them in a Map for later access. The issue I'm having is I occasionally get a org.neo4j.graphdb,NotFoundException in my tests, which I've tracked down to be related to the stored Domain objects in my helper class no longer having a corresponding Node entity in the graph. I wouldn't think this to be an issue, since my tests are transactional and I assume the nodes lifecycle are managed within the transaction - rolled back with the transaction once the unit test ends. I've attached my project files for further clarity.

    Here's my helper class:

    Code:
    @Component
    public class DomainObjectsAccessor
    {
      private String[] personNames = new String[]
      {
          "Joe Smith", "John Doe", "Jimmy Jones", "Paul Henry", "Sam Adams",
          "Glen Dale"
      };
      private Map<Integer, Person> mapOfPeople = new HashMap<Integer, Person>(
          personNames.length);
    
      public Person getPerson()
      {
        Random random = new Random(System.currentTimeMillis());
        int nameIndex = random.nextInt(personNames.length - 1);
    
        Person retVal = null;
    
        // prefer map if key exists
        if (mapOfPeople.containsKey(nameIndex))
        {
          retVal = mapOfPeople.get(nameIndex);
        }
        // else create new person, add to map for later
        else
        {
          retVal = new Person(UUID.randomUUID().toString(), personNames[nameIndex]);
          mapOfPeople.put(nameIndex, retVal);
        }
    
        return retVal;
      }
    }
    Here's my 2 Domain Objects:

    Code:
    @NodeEntity
    public class Person
    {
      private String id;
      private String name;
    
    ...
    }
    
    @NodeEntity
    public class Manager
    {
      private String id;
    
      @RelatedTo(elementClass = Person.class)
      private Set<Person> employees;
    ...
    }

    And finally my test that fails:

    Code:
    @TestExecutionListeners(TransactionalTestExecutionListener.class)
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(loader = AnnotationConfigContextLoader.class, value = "org.mycompany.graph.config.AppConfig")
    public class DomainObjectTests extends AbstractJUnit4SpringContextTests
    {
      @Autowired
      private DomainObjectsAccessor accessor;
    
      @Test
      @Transactional
      @Repeat(10)
      public void tests() throws Exception
      {
        Person person = accessor.getPerson();
        Set<Person> employees = new HashSet<Person>();
        employees.add(person);
        Manager manager = new Manager(UUID.randomUUID().toString(), employees);
        manager.persist();
      }
    }
    Stack Trace from failed Unit Test:
    Code:
    org.neo4j.graphdb.NotFoundException: Node[71] not found.
    	at org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:447)
    	at org.neo4j.kernel.impl.core.NodeProxy.hasProperty(NodeProxy.java:139)
    	at org.springframework.data.graph.neo4j.fieldaccess.PropertyFieldAccessorFactory$PropertyFieldAccessor.doGetValue(PropertyFieldAccessorFactory.java:93)
    	at org.springframework.data.graph.neo4j.fieldaccess.PropertyFieldAccessorFactory$PropertyFieldAccessor.getValue(PropertyFieldAccessorFactory.java:88)
    	at org.springframework.data.graph.neo4j.fieldaccess.PropertyFieldAccessorFactory$PropertyFieldAccessor.getValue(PropertyFieldAccessorFactory.java:1)
    	at org.springframework.data.graph.neo4j.fieldaccess.DefaultEntityState.getValue(DefaultEntityState.java:90)
    	at org.springframework.data.graph.neo4j.fieldaccess.DetachedEntityState.getValue(DetachedEntityState.java:80)
    	at org.mycompany.graph.model.common.Person.id_aroundBody13$advice(Person.java:255)
    	at org.mycompany.graph.model.common.Person.toString(Person.java:46)
    	at java.lang.String.valueOf(String.java:2826)
    	at java.lang.StringBuilder.append(StringBuilder.java:115)
    	at java.util.AbstractCollection.toString(AbstractCollection.java:422)
    	at java.lang.String.valueOf(String.java:2826)
    	at java.lang.StringBuilder.append(StringBuilder.java:115)
    	at org.springframework.data.graph.neo4j.fieldaccess.DetachedEntityState.flushDirty(DetachedEntityState.java:163)
    	at org.springframework.data.graph.neo4j.fieldaccess.DetachedEntityState.persist(DetachedEntityState.java:238)
    	at org.springframework.data.graph.neo4j.support.node.Neo4jNodeBacking.ajc$interMethod$org_springframework_data_graph_neo4j_support_node_Neo4jNodeBacking$org_springframework_data_graph_core_NodeBacked$persist(Neo4jNodeBacking.aj:120)
    	at org.mycompany.graph.model.common.Manager.persist(Manager.java:1)
    	at org.springframework.data.graph.neo4j.support.node.Neo4jNodeBacking.ajc$interMethodDispatch1$org_springframework_data_graph_neo4j_support_node_Neo4jNodeBacking$org_springframework_data_graph_core_NodeBacked$persist(Neo4jNodeBacking.aj)
    	at org.mycompany.graph.DomainObjectTests.tests(DomainObjectTests.java:37)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    	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)
    Last edited by jzcfk9; May 3rd, 2011, 07:15 AM.

  • #2
    Has anyone else run into this issue? As a programmer working with POJOs that are NodeEntities, do I need to be aware of persistent state of the underlying Neo4j nodes backing my POJOs?

    I would think SDG is trying to eliminate the need for understanding how POJOs are associated to the underlying Neo4j nodes. I'm thinking all I need to be aware of is that NodeEntities have a persistent state, and that they are either attached or detached.

    In the case of my unit test that I'm running, I can see that the underlying Neo4j Node is removed from the graph, but shouldn't the NodeEntity's corresponding EntityState be cleared once the transaction is rolled back?
    Last edited by jzcfk9; May 4th, 2011, 06:02 AM.

    Comment


    • #3
      I've been slowly trying to debug this test case, and I'm currently seeing that the DefaultEntityState of the NodeEntity doesn't seem to be getting cleared correctly after a transaction rollback. I'm attaching a snapshot of my debugger after a rollback, but before a cascading persist on my Manager NodeEntity. The debugger shows the "dirty" node state for my Person NodeEntity.

      Comment


      • #4
        JIRA DataGraph-87 has been created to investigate the issue.

        Comment


        • #5
          Thanks for investigating and pointing that out, will look into it the next days. You're right that those nodes should be cleared out. Sorry for not getting back earlier, kids are sick and had conference talk this week.

          Cheers

          Michael

          Comment

          Working...
          X