10 Replies Latest reply on Jan 2, 2012 1:28 PM by lexsoto

    Query with Joins produces NPE

    lexsoto

      Hello:

       

      This NPE exception:

       

      java.lang.NullPointerException
        at org.modeshape.graph.query.process.JoinComponent$6.evaluate(JoinComponent.java:359)
        at org.modeshape.graph.query.process.NestedLoopJoinComponent.execute(NestedLoopJoinComponent.java:68)
        at org.modeshape.graph.query.process.ProjectComponent.execute(ProjectComponent.java:48)
        at org.modeshape.graph.query.process.QueryProcessor.execute(QueryProcessor.java:100)
        at org.modeshape.graph.query.QueryEngine.execute(QueryEngine.java:124)
        at org.modeshape.jcr.RepositoryQueryManager$SelfContained.query(RepositoryQueryManager.java:435)
        at org.modeshape.jcr.JcrQueryManager$SessionQueryContext.execute(JcrQueryManager.java:1422)
        at org.modeshape.jcr.query.JcrQuery.execute(JcrQuery.java:103)
        at com.cht.member.MemberAuthorizationServiceBeanTest.testJoinQuery(MemberAuthorizationServiceBeanTest.java:127)
        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: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.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
        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.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
        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)
      

       

      Is thrown by this code: 

       

          final Session session = repository.login(new SimpleCredentials("jsmith", "secret".toCharArray()));
          final NamespaceRegistry registry = session.getWorkspace().getNamespaceRegistry();
          
          final String NAMESPACE_PREFIX = "tt";
          final String NAMESPACE_URI = "http://test.com/tt";
          final String FRIENDLY = "tt:friendly";
          final String FRIEND = "tt:friend";
          
          registry.registerNamespace(NAMESPACE_PREFIX, NAMESPACE_URI);
          
          NodeTypeManager manager = session.getWorkspace().getNodeTypeManager();
          NodeTypeTemplate nodeType = manager.createNodeTypeTemplate();
          nodeType.setMixin(true);
          nodeType.setName(FRIENDLY);
          nodeType.setQueryable(true);
          nodeType.setDeclaredSuperTypeNames(new String[]{"mix:referenceable"});
          
          PropertyDefinitionTemplate propertyDef = manager.createPropertyDefinitionTemplate();
          propertyDef.setName(FRIEND);
          propertyDef.setMultiple(true);
          propertyDef.setRequiredType(PropertyType.REFERENCE);
          propertyDef.setOnParentVersion(OnParentVersionAction.COPY);
          propertyDef.setProtected(false);
          
          nodeType.getPropertyDefinitionTemplates().add(propertyDef);
          manager.registerNodeType(nodeType, true);
        
          final String USER_NAME = "Paul";
          final Node userNode = session.getRootNode().addNode(USER_NAME, "nt:folder");
          userNode.addMixin(FRIENDLY);
          
          session.save();
        
          final QueryManager queryManager = session.getWorkspace().getQueryManager();
          final String expression = "SELECT grantee.* FROM [tt:friendly] as grantor " +
              "INNER JOIN [tt:friendly] as grantee ON grantor.[tt:friend] = grantee.[jcr:uuid] "; 
          
          final QueryResult queryResult = queryManager.createQuery(expression, "JCR-SQL2").execute();
      
      

       

      but not if I comment the line adding the mixin

       

      userNode.addMixin(FRIENDLY);
      

       

      Without adding a node with the "tt:friendly" mixin, the query runs fine.

       

      Any idea?

       

       

      Thanks

        • 1. Re: Query with Joins produces NPE
          rhauch

          The query may run fine, but do you get results back?

           

          The exception is running into a problem when the left side of the join is null, which based upon the join condition is probably because 'grantor.[tt:friend]' is null. And in fact the "userNode" has no "tt:friend" property, which would evaluate to null in the join condition.

           

          It works when commenting out the "userNode.addMixin(FRIENDLY)" line, since that's the line that is effectively causing the userNode to appear in the "tt:friendly" table; without that line, the user node is just an "nt:unstructured" node.

           

          This is clearly a bug in the join logic, since it should be able to handle null values. I'll log a defect and try to fix it this afternoon, since we're planning on pushing out 2.7.0.Final tomorrow.

          • 2. Re: Query with Joins produces NPE
            lexsoto

            The query does not return anything without the mixin, as should be expected.

            I am glad it will be fixed soon.  Thanks!

             

            BTW, this same code works fine with JackRabbit, as I am testing with both JackRabbit and ModeShape.

            • 3. Re: Query with Joins produces NPE
              rhauch

              I should add that if the property on the right-hand-side of the join criteria were mandatory, then you could actually swap the join condition expressions (e.g., moving the left to right side, and the right side to the left side).

               

              This is actually the case for this particular query; the right-hand side is the "jcr:uuid" property, which is a mandatory property for "mix:referenceable". So instead of this query:

               

              SELECT grantee.* FROM [tt:friendly] as grantor
              INNER JOIN [tt:friendly] as grantee

              ON grantor.[tt:friend] = grantee.[jcr:uuid]

               

              you should be able to swap the LHS and RHS expressions in the last line, and I think this will work:

               

              SELECT grantee.* FROM [tt:friendly] as grantor
              INNER JOIN [tt:friendly] as grantee

              ON grantee.[jcr:uuid] = grantor.[tt:friend]

              • 4. Re: Query with Joins produces NPE
                lexsoto

                Randal:

                 

                Just wanted to let you know that I tested with the swapped join expression but the problem persists.

                 

                Thanks for your help.

                • 5. Re: Query with Joins produces NPE
                  rhauch

                  You you get an NPE, and if so it is the same NPE?  If so, then we might be rearranging the join condition to match the order of the join.

                   

                  If you're willing, could you maybe try this query instead, which swaps the LHS and RHS of the whole join:

                   

                  SELECT grantee.* FROM [tt:friendly] as grantee
                  INNER JOIN [tt:friendly] as grantor

                  ON grantee.[jcr:uuid] = grantor.[tt:friend]


                  Again, this is just a (potential) workaround. As I write this, I'm testing a fix for the underlying problem, and this fix should be in 2.7.0.Final.

                  • 6. Re: Query with Joins produces NPE
                    rhauch

                    I just tested the above workaround, and it also does not work. Sorry for the runaround.

                    • 7. Re: Query with Joins produces NPE
                      rhauch

                      The fix for MODE-1359 has been merged into both active branches, and will be in 2.7.0.Final release. Thanks again for reporting this.

                       

                      Best regards

                      • 8. Re: Query with Joins produces NPE
                        lexsoto

                        Thank you Randall.  I'm looking forward for 2.7.Final.

                        • 9. Re: Query with Joins produces NPE
                          rhauch

                          I just announced the availability of 2.7.0.Final. Have a go at it and let us know how the fix works.

                          • 10. Re: Query with Joins produces NPE
                            lexsoto

                            2.7.Final solves this problem; however, there is a new issue that I will post in a separate thread because it manifests differently.

                            Thanks!