4040import java .util .Calendar ;
4141import java .util .GregorianCalendar ;
4242
43- @ SuppressWarnings ({"RedundantThrows" , "checkstyle:OverloadMethodsDeclarationOrder" })
4443public class CachedResultSet implements ResultSet {
4544
4645 public static class CachedRow {
@@ -65,8 +64,10 @@ public Object get(final String columnName) {
6564
6665 protected ArrayList <CachedRow > rows ;
6766 protected int currentRow ;
67+ protected boolean wasNullFlag ;
6868 protected ResultSetMetaData metadata ;
6969 protected static ObjectMapper mapper = new ObjectMapper ();
70+ protected static boolean mapperInitialized = false ;
7071 protected static final TimeZone defaultTimeZone = TimeZone .getDefault ();
7172 private static final Calendar calendarWithUserTz = new GregorianCalendar ();
7273
@@ -83,34 +84,45 @@ public CachedResultSet(final ResultSet resultSet) throws SQLException {
8384 rows .add (row );
8485 }
8586 currentRow = -1 ;
87+ initializeObjectMapper ();
8688 }
8789
8890 public CachedResultSet (final List <Map <String , Object >> resultList ) {
8991 rows = new ArrayList <>();
90- CachedResultSetMetaData .Field [] fields = new CachedResultSetMetaData .Field [resultList .get (0 ).size ()];
91- boolean fieldsInitialized = false ;
92- for (Map <String , Object > rowMap : resultList ) {
93- final CachedRow row = new CachedRow ();
94- int i = 0 ;
95- for (Map .Entry <String , Object > entry : rowMap .entrySet ()) {
96- String columnName = entry .getKey ();
97- if (!fieldsInitialized ) {
98- fields [i ] = new CachedResultSetMetaData .Field (columnName , columnName );
92+ int numFields = resultList .isEmpty () ? 0 : resultList .get (0 ).size ();
93+ CachedResultSetMetaData .Field [] fields = new CachedResultSetMetaData .Field [numFields ];
94+ if (!resultList .isEmpty ()) {
95+ boolean fieldsInitialized = false ;
96+ for (Map <String , Object > rowMap : resultList ) {
97+ final CachedRow row = new CachedRow ();
98+ int i = 0 ;
99+ for (Map .Entry <String , Object > entry : rowMap .entrySet ()) {
100+ String columnName = entry .getKey ();
101+ if (!fieldsInitialized ) {
102+ fields [i ] = new CachedResultSetMetaData .Field (columnName , columnName );
103+ }
104+ row .put (++i , columnName , entry .getValue ());
99105 }
100- row .put (++i , columnName , entry .getValue ());
106+ rows .add (row );
107+ fieldsInitialized = true ;
101108 }
102- rows .add (row );
103- fieldsInitialized = true ;
104109 }
105110 currentRow = -1 ;
106111 metadata = new CachedResultSetMetaData (fields );
112+ initializeObjectMapper ();
107113 }
108114
109- public String serializeIntoJsonString () throws SQLException {
115+ // Helper method to initialize the object mapper for serialization of objects
116+ private void initializeObjectMapper () {
117+ if (mapperInitialized ) return ;
118+ // For serialization of Date/LocalDateTime etc, set up the time module,
119+ // and use standard string format (i.e. ISO)
110120 mapper .registerModule (new JavaTimeModule ());
111- // Serialize Date/LocalDateTime etc. into standard string format (i.e. ISO)
112121 mapper .disable (SerializationFeature .WRITE_DATES_AS_TIMESTAMPS );
122+ mapperInitialized = true ;
123+ }
113124
125+ public String serializeIntoJsonString () throws SQLException {
114126 List <Map <String , Object >> resultList = new ArrayList <>();
115127 ResultSetMetaData metaData = this .getMetaData ();
116128 int columns = metaData .getColumnCount ();
@@ -156,7 +168,10 @@ public void close() throws SQLException {
156168
157169 @ Override
158170 public boolean wasNull () throws SQLException {
159- throw new UnsupportedOperationException ();
171+ if (isClosed ()) {
172+ throw new SQLException ("This result set is closed" );
173+ }
174+ return this .wasNullFlag ;
160175 }
161176
162177 // TODO: implement all the getXXX APIs.
@@ -476,12 +491,12 @@ public InputStream getBinaryStream(final String columnLabel) throws SQLException
476491
477492 @ Override
478493 public SQLWarning getWarnings () throws SQLException {
479- throw new UnsupportedOperationException () ;
494+ return null ;
480495 }
481496
482497 @ Override
483498 public void clearWarnings () throws SQLException {
484- throw new UnsupportedOperationException ();
499+ // no-op
485500 }
486501
487502 @ Override
@@ -494,28 +509,34 @@ public ResultSetMetaData getMetaData() throws SQLException {
494509 return metadata ;
495510 }
496511
497- @ Override
498- public Object getObject (final int columnIndex ) throws SQLException {
512+ private void checkCurrentRow () throws SQLException {
499513 if (this .currentRow < 0 || this .currentRow >= this .rows .size ()) {
500- return null ; // out of boundaries
514+ throw new SQLException ( "The current row index " + this . currentRow + " is out of range." );
501515 }
516+ }
517+
518+ @ Override
519+ public Object getObject (final int columnIndex ) throws SQLException {
520+ checkCurrentRow ();
502521 final CachedRow row = this .rows .get (this .currentRow );
503522 if (!row .columnByIndex .containsKey (columnIndex )) {
504- return null ; // column index out of boundaries
523+ throw new SQLException ( "The column index: " + columnIndex + " is out of range, number of columns: " + row . columnByIndex . size ());
505524 }
506- return row .columnByIndex .get (columnIndex );
525+ Object obj = row .columnByIndex .get (columnIndex );
526+ this .wasNullFlag = (obj == null );
527+ return obj ;
507528 }
508529
509530 @ Override
510531 public Object getObject (final String columnLabel ) throws SQLException {
511- if (this .currentRow < 0 || this .currentRow >= this .rows .size ()) {
512- return null ; // out of boundaries
513- }
532+ checkCurrentRow ();
514533 final CachedRow row = this .rows .get (this .currentRow );
515534 if (!row .columnByName .containsKey (columnLabel )) {
516- return null ; // column name not found
535+ throw new SQLException ( "The column label: " + columnLabel + " is not found" );
517536 }
518- return row .columnByName .get (columnLabel );
537+ Object obj = row .columnByName .get (columnLabel );
538+ this .wasNullFlag = (obj == null );
539+ return obj ;
519540 }
520541
521542 @ Override
@@ -559,12 +580,12 @@ public boolean isAfterLast() throws SQLException {
559580
560581 @ Override
561582 public boolean isFirst () throws SQLException {
562- return this .currentRow == 0 && this .rows .size () > 0 ;
583+ return this .currentRow == 0 && ! this .rows .isEmpty () ;
563584 }
564585
565586 @ Override
566587 public boolean isLast () throws SQLException {
567- return this .currentRow == (this .rows .size () - 1 ) && this .rows .size () > 0 ;
588+ return this .currentRow == (this .rows .size () - 1 ) && ! this .rows .isEmpty () ;
568589 }
569590
570591 @ Override
@@ -596,24 +617,49 @@ public int getRow() throws SQLException {
596617
597618 @ Override
598619 public boolean absolute (final int row ) throws SQLException {
599- if (row > 0 ) {
600- this .currentRow = row - 1 ;
620+ if (row == 0 ) {
621+ this .beforeFirst ();
622+ return false ;
601623 } else {
602- this .currentRow = this .rows .size () + row ;
624+ int rowsSize = this .rows .size ();
625+ if (row < 0 ) {
626+ if (row < -rowsSize ) {
627+ this .beforeFirst ();
628+ return false ;
629+ }
630+ this .currentRow = rowsSize + row ;
631+ } else { // row > 0
632+ if (row > rowsSize ) {
633+ this .afterLast ();
634+ return false ;
635+ }
636+ this .currentRow = row - 1 ;
637+ }
603638 }
604- return this . currentRow >= 0 && this . currentRow < this . rows . size () ;
639+ return true ;
605640 }
606641
607642 @ Override
608643 public boolean relative (final int rows ) throws SQLException {
609644 this .currentRow += rows ;
610- return this .currentRow >= 0 && this .currentRow < this .rows .size ();
645+ if (this .currentRow < 0 ) {
646+ this .beforeFirst ();
647+ return false ;
648+ } else if (this .currentRow >= this .rows .size ()) {
649+ this .afterLast ();
650+ return false ;
651+ }
652+ return true ;
611653 }
612654
613655 @ Override
614656 public boolean previous () throws SQLException {
657+ if (this .currentRow < 1 ) {
658+ this .beforeFirst ();
659+ return false ;
660+ }
615661 this .currentRow --;
616- return this . currentRow >= 0 && this . currentRow < this . rows . size () ;
662+ return true ;
617663 }
618664
619665 @ Override
@@ -1054,7 +1100,7 @@ public int getHoldability() throws SQLException {
10541100
10551101 @ Override
10561102 public boolean isClosed () throws SQLException {
1057- return false ;
1103+ return this . rows == null ;
10581104 }
10591105
10601106 @ Override
0 commit comments