Uploaded image for project: 'Cassandra'
  1. Cassandra
  2. CASSANDRA-15896

NullPointerException in SELECT JSON statement when a UUID field contains an empty string

    XMLWordPrintableJSON

Details

    Description

      It seems that Cassandra accept empty strings "" ( FROM JSON string ) for UUID fields but crash when asking for JSON serialization of those fields.

       

      Cassandra version 3.6.11.6 running in docker from official Dockerhub image.

      Java driver:

      <!-- https://mvnrepository.com/artifact/com.datastax.oss/java-driver-core -->
      <dependency>
          <groupId>com.datastax.oss</groupId>
          <artifactId>java-driver-core</artifactId>
          <version>4.7.0</version>
      </dependency>
      

      The attached code is to allow bug reproducibility:

      package com.foo.bar;
      import com.datastax.oss.driver.api.core.CqlSession;
      import com.datastax.oss.driver.api.core.CqlSessionBuilder;
      import com.datastax.oss.driver.api.core.cql.PreparedStatement;
      import com.datastax.oss.driver.api.core.cql.ResultSet;
      import com.datastax.oss.driver.api.core.cql.Row;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import org.junit.After;
      import org.junit.Before;
      import org.junit.Test;
      
      import java.net.InetSocketAddress;
      import java.net.URI;
      import java.util.*;
      
      import static org.junit.Assert.assertFalse;
      import static org.junit.Assert.assertNotNull;
      
      /**
       * @author Domenico Lupinetti <ostico@gmail.com> - 23/06/2020
       */
      public class NullPointerExceptionTest {
      
          protected String uuid;
          protected CqlSession cqlSession;
      
          @Before
          public void setUp() throws Exception {
      
              URI node = new URI( "tcp://localhost:9042" );
              final CqlSessionBuilder builder = CqlSession.builder();
      
              cqlSession = builder.addContactPoint( new InetSocketAddress(
                      node.getHost(),
                      node.getPort()
              ) ).withLocalDatacenter( "datacenter1" ).build();
      
              cqlSession.execute( "CREATE KEYSPACE IF NOT EXISTS test_suite WITH replication = {'class':'SimpleStrategy','replication_factor':1};" );
      
              String sb = "CREATE TABLE IF NOT EXISTS test_suite.test ( id uuid PRIMARY KEY, another_id uuid, subject text );";
      
              cqlSession.execute( sb );
              PreparedStatement stm = cqlSession.prepare( "INSERT INTO test_suite.test JSON :payload" );
      
              this.uuid = UUID.randomUUID().toString();
      
              HashMap<String, String> payload = new HashMap<>();
              payload.put( "id", this.uuid );
      
              // ******* This exception do not happens if the field is set as NULL
              payload.put( "another_id", "" );  //<------ EMPTY STRING AS UUID
              payload.put( "subject", "Alighieri, Dante. Divina Commedia" );
      
              ObjectMapper objM = new ObjectMapper();
              cqlSession.execute(
                      stm.bind().setString( "payload", objM.writeValueAsString( payload ) )
              );  //<------ serialize as JSON
      
          }
      
          @After
          public void tearDown() throws Exception {
              cqlSession.execute( "DROP TABLE IF EXISTS test_suite.test;" );
              cqlSession.execute( "DROP KEYSPACE test_suite;" );
              cqlSession.close();
          }
      
          @Test
          public void testNullPointer() {
      
              PreparedStatement stmt       = cqlSession.prepare( "SELECT JSON id, another_id FROM test_suite.test where id = :id;" );
              ResultSet         resultSet  = cqlSession.execute( stmt.bind().setUuid( "id", UUID.fromString( this.uuid ) ) ); // <------ EXCEPTION
              Row               r          = resultSet.one();
      
              assertNotNull( r );
              assertNotNull( r.getString( "[json]" ) );
              assertFalse( Objects.requireNonNull( r.getString( "[json]" ) ).isEmpty() );
      
          }
      
      }
      
      
      

      Client stack Trace:

      com.datastax.oss.driver.api.core.servererrors.ServerError: java.lang.NullPointerExceptioncom.datastax.oss.driver.api.core.servererrors.ServerError: java.lang.NullPointerException
       at com.datastax.oss.driver.api.core.servererrors.ServerError.copy(ServerError.java:54) at com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures.getUninterruptibly(CompletableFutures.java:149) at com.datastax.oss.driver.internal.core.cql.CqlRequestSyncProcessor.process(CqlRequestSyncProcessor.java:53) at com.datastax.oss.driver.internal.core.cql.CqlRequestSyncProcessor.process(CqlRequestSyncProcessor.java:30) at com.datastax.oss.driver.internal.core.session.DefaultSession.execute(DefaultSession.java:230) at com.datastax.oss.driver.api.core.cql.SyncCqlSession.execute(SyncCqlSession.java:53) at com.foo.bar.NullPointerExceptionTest.testNullPointer(NullPointerExceptionTest.java:74) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.ParentRunner.run(ParentRunner.java:413) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
      

      Cassandra stack Trace:

       

      ERROR [Native-Transport-Requests-1] 2020-06-23 09:57:48,074 ErrorMessage.java:384 - Unexpected exception during requestERROR [Native-Transport-Requests-1] 2020-06-23 09:57:48,074 ErrorMessage.java:384 - Unexpected exception during requestjava.lang.NullPointerException: null at org.apache.cassandra.db.marshal.AbstractType.toJSONString(AbstractType.java:156) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.selection.Selection.rowToJson(Selection.java:343) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.selection.Selection$ResultSetBuilder.getOutputRow(Selection.java:494) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.selection.Selection$ResultSetBuilder.build(Selection.java:477) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.statements.SelectStatement.process(SelectStatement.java:794) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.statements.SelectStatement.processResults(SelectStatement.java:438) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.statements.SelectStatement.execute(SelectStatement.java:416) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.statements.SelectStatement.execute(SelectStatement.java:289) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.statements.SelectStatement.execute(SelectStatement.java:117) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.QueryProcessor.processStatement(QueryProcessor.java:225) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.QueryProcessor.processPrepared(QueryProcessor.java:532) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.cql3.QueryProcessor.processPrepared(QueryProcessor.java:509) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.transport.messages.ExecuteMessage.execute(ExecuteMessage.java:146) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.transport.Message$Dispatcher.processRequest(Message.java:686) [apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.transport.Message$Dispatcher.lambda$channelRead0$0(Message.java:592) [apache-cassandra-3.11.6.jar:3.11.6] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_252] at org.apache.cassandra.concurrent.AbstractLocalAwareExecutorService$FutureTask.run(AbstractLocalAwareExecutorService.java:165) ~[apache-cassandra-3.11.6.jar:3.11.6] at org.apache.cassandra.concurrent.SEPWorker.run(SEPWorker.java:113) ~[apache-cassandra-3.11.6.jar:3.11.6] at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_252]
      

      Attachments

        Issue Links

          Activity

            People

              bereng Berenguer Blasi
              Ostico Ostico
              Berenguer Blasi
              Brandon Williams
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 1h
                  1h