1. Introduction

PostgreSQL arrays are a feature that allows us to store multiple values in a single column. However, when retrieving these arrays in Java, we may need to convert them to a more manageable data structure, such as an array of strings. In this tutorial, we’ll explore how to convert a PostgreSQL array from a ResultSet to an array of strings in Java.

2. Understanding PostgreSQL Arrays

In PostgreSQL, arrays are a data type that allows us to store multiple values in a single column. These values can be of any data type, including strings, integers, and dates. For example, a column of type TEXT[] can hold an array of text values such as {‘apple’, ‘banana’, ‘cherry’}.

Additionally, PostgreSQL supports nested arrays, enabling us to store arrays of arrays. *For instance, a column of type TEXT[][] can contain more complex structures like {{‘apple’, ‘banana’}, {‘cherry’, ‘date’}}, where each element is itself an array of text values.*

When retrieving an array column in Java, we may want to convert it to a more familiar data structure, such as an array of strings String[] or String[][]. This conversion process ensures that the data can be handled efficiently within Java applications

3. Set up Dependency and Database Connection

Before diving into the solution for converting PostgreSQL arrays to Java string arrays, we need to set up our project environment. To interact with the PostgreSQL database in Java, we need to include the PostgreSQL JDBC driver in our Maven project. Let’s add the following dependency to the pom.xml file:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.7.3</version>
</dependency>

Next, we need to establish a connection to our PostgreSQL database. This involves specifying the database URL, username, and password. The following method demonstrates how to create a Connection object for interacting with the database:

static Connection connect() throws SQLException {
    String url = "jdbc:postgresql://localhost:5432/database_name";
    String user = "username";
    String password = "password";
    return DriverManager.getConnection(url, user, password);
}

In this code snippet, the connect() method is designed to create and return a Connection object for our PostgreSQL database.

4. Preparing One-Dimensional Test Data

To test our data conversion and handling logic, we need to set up the appropriate database tables and insert sample data. We’ll start by creating a PostgreSQL table named test_table that includes a single array column. This column, test_array, will be of type TEXT[] to store arrays of text values.

Here’s the SQL command to create test_table:

CREATE TABLE test_table (
    id SERIAL PRIMARY KEY,
    test_array TEXT ARRAY
);

Next, we insert some sample data into test_table to represent one-dimensional data:

INSERT INTO test_table (test_array) 
VALUES
  (ARRAY['apple', 'banana', 'orange']),
  (ARRAY['hello', 'world', 'java']),
  (ARRAY['postgresql', 'test', 'example']);

5. Creating a POJO Class

We’ll create a POJO class TestRow to map the data retrieved from the database into Java objects. The TestRow class represents a simple structure for holding data from our test_table. It includes two fields: id and testArray:

public class TestRow {
    private int id;
    private String[] testArray;

    // getters and setters
}

6. Converting One-Dimensional Arrays

In this approach, we convert a PostgreSQL array to a Java String[] array using the getArray() method. This method returns a java.sql.Array object, which can be cast to a String[] array. We use the TestRow POJO to encapsulate each row of data:

List<TestRow> convertAllArraysUsingGetArray() {
    List<TestRow> resultList = new ArrayList<>();
    try (Connection conn = connect(); Statement stmt = conn.createStatement()) {
        ResultSet rs = stmt.executeQuery("SELECT id, test_array FROM test_table");

        while (rs.next()) {
            int id = rs.getInt("id");
            Array array = rs.getArray("test_array");
            String[] testArray = (String[]) array.getArray();
            TestRow row = new TestRow(id, testArray);
            resultList.add(row);
        }
    } catch (SQLException e) {
        // Handle exception
    }
    return resultList;
}

In this method, we first execute a SQL query to retrieve all rows from test_table, including the id and the test_array column. We then iterate through each row in the ResultSet.

For each row, we retrieve the PostgreSQL array using the getArray() method, which returns a java.sql.Array object. Next, we convert this java.sql.Array object into a String[] array by casting it.

Moreover, we create a TestRow object using the row’s id and the converted String[] array. This approach encapsulates the data into a structured object, making it easier to work with. Each TestRow object is added to a List, which is then returned.

The approach is straightforward to implement, requiring minimal code to convert a database array to a Java array. However, using direct casting, we need to ensure that all elements in the PostgreSQL array are of a type that can be represented as strings.

If the elements are of a different type (e.g., INTEGER[]), it results in a ClassCastException. *To address this, we can first convert the PostgreSQL array to an Object[], and then cast each element to the desired type, avoiding potential casting issues.*

Let’s validate our method to ensure it works correctly:

void givenArray_whenUsingConvertArrays_thenReturnStringArray() throws SQLException {
    List<TestRow> result = convertAllArraysUsingGetArray();

    String[][] expectedArrays = {
        new String[]{"apple", "banana", "orange"},
        new String[]{"hello", "world", "java"},
        new String[]{"postgresql", "test", "example"}
    };
    
    List<TestRow> expected = Arrays.asList(
        new TestRow(1, expectedArrays[0]),
        new TestRow(2, expectedArrays[1]),
        new TestRow(3, expectedArrays[2])
    );

    // Compare each TestRow's array with the expected array
    for (int i = 0; i < result.size(); i++) {
        assertArrayEquals(expected.get(i).getTestArray(), result.get(i).getTestArray());
    }
}

In this test, we validate that the convertAllArraysUsingGetArray() method correctly converts the PostgreSQL arrays to Java String[] arrays. We compare the results with expected values to ensure accuracy.

7. Preparing Two-Dimensional Test Data

For handling two-dimensional arrays, we’ll create another PostgreSQL table named nested_array_table. *This table includes a column named nested_array of type TEXT[][], which can store arrays of arrays.*

Here’s the SQL command to create nested_array_table:

CREATE TABLE nested_array_table (
    id SERIAL PRIMARY KEY,
    nested_array TEXT[][]
);

Next, we insert sample data into nested_array_table to represent nested arrays:

INSERT INTO nested_array_table (nested_array) 
VALUES 
  (ARRAY[ARRAY['apple', 'banana'], ARRAY['cherry', 'date']]),
  (ARRAY[ARRAY['hello', 'world'], ARRAY['java', 'programming']]);

In this example, nested_array_table contains rows with two-dimensional arrays.

8. Creating a POJO Class for Two-Dimensional Arrays

Next, we’ll create a NestedTestRow class to represent rows from nested_array_table. In this case, the nestedArray is a two-dimensional array of strings, represented by String[][]:

public class NestedTestRow {
    private int id;
    private String[][] nestedArray;

    // getters and setters
}

9. Handling Nested Arrays

When working with PostgreSQL, it’s common to encounter nested arrays, which can be challenging to handle in Java. The following method demonstrates how to convert a nested PostgreSQL array to a flat String[] array:

List<NestedTestRow> convertNestedArraysToStringArray() {
    List<NestedTestRow> resultList = new ArrayList<>();
    try (Connection conn = connect(); Statement stmt = conn.createStatement()) {
        ResultSet rs = stmt.executeQuery("SELECT id, nested_array FROM nested_array_table");

        while (rs.next()) {
            int id = rs.getInt("id");
            Array array = rs.getArray("nested_array");
            Object[][] nestedArray = (Object[][]) array.getArray();
            String[][] stringNestedArray = Arrays.stream(nestedArray)
              .map(subArray -> Arrays.stream(subArray)
                .map(Object::toString)
                  .toArray(String[]::new))
              .toArray(String[][]::new);
            NestedTestRow row = new NestedTestRow(id, stringNestedArray);
            resultList.add(row);
        }
    } catch (SQLException e) {
        // Handle exception
    }
    return resultList;
}

In this method, we retrieve a nested PostgreSQL array as an Object[][]. *We then use Java Streams to transform this Object[][] into a String[][].* Each element of the nested array is converted to its string representation with Object::toString.

This conversion is done in a nested mapping operation, where each sub-array is processed independently before being aggregated into the final String[][] array. We then create a NestedTestRow object for each row and add it to our result list.

Let’s create a test method to validate the two-dimensional conversion:

@Test
void givenNestedArray_whenUsingConvertNestedArrays_thenReturnStringNestedArray() throws SQLException {
    List<NestedTestRow> result = convertNestedArraysToStringArray();

    String[][][] expectedNestedArrays = {
        {
            { "apple", "banana" },
            { "cherry", "date" }
        },
        {
            { "hello", "world" },
            { "java", "programming" }
        }
    };

    List<NestedTestRow> expected = Arrays.asList(
        new NestedTestRow(1, expectedNestedArrays[0]),
        new NestedTestRow(2, expectedNestedArrays[1])
    );

    // Compare each NestedTestRow's array with the expected array
    for (int i = 0; i < result.size(); i++) {
        assertArrayEquals(expected.get(i).getNestedArray(), result.get(i).getNestedArray());
    }
}

In this test, we validate that the convertNestedArraysToStringArray() method correctly converts PostgreSQL two-dimensional arrays into Java String[][] arrays. We compare the results with the expected values to confirm the accuracy of the conversion.

10. Conclusion

In this article, we learned how to use the getArray() method to convert a PostgreSQL array to a String[] array using direct casting. In addition, we also explored how Java Streams can be utilized to flatten and process two-dimensional arrays.

As always, the source code for the examples is available over on GitHub.