Skip to content

Commit e5c505b

Browse files
committed
Merge pull request #33248 from ngocnhan-tran1996
* pr/33248: Polish "Stop referring to STRUCT and ARRAY as they are deprecated" Stop referring to STRUCT and ARRAY as they are deprecated Closes gh-33248
2 parents b626622 + af8dc44 commit e5c505b

File tree

10 files changed

+286
-130
lines changed

10 files changed

+286
-130
lines changed

framework-docs/antora.yml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ asciidoc:
2020
fold: 'all'
2121
table-stripes: 'odd'
2222
include-java: 'example$docs-src/main/java/org/springframework/docs'
23+
include-kotlin: 'example$docs-src/main/kotlin/org/springframework/docs'
2324
spring-site: 'https://spring.io'
2425
spring-site-blog: '{spring-site}/blog'
2526
spring-site-cve: "{spring-site}/security"

framework-docs/framework-docs.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ repositories {
4343

4444
dependencies {
4545
api(project(":spring-context"))
46+
api(project(":spring-jdbc"))
4647
api(project(":spring-jms"))
4748
api(project(":spring-web"))
49+
50+
api("org.jetbrains.kotlin:kotlin-stdlib")
51+
api("com.oracle.database.jdbc:ojdbc11")
4852
api("jakarta.jms:jakarta.jms-api")
4953
api("jakarta.servlet:jakarta.servlet-api")
5054

framework-docs/modules/ROOT/pages/data-access/jdbc/parameter-handling.adoc

+9-124
Original file line numberDiff line numberDiff line change
@@ -209,141 +209,26 @@ are passed in as a parameter to the stored procedure.
209209

210210
The `SqlReturnType` interface has a single method (named `getTypeValue`) that must be
211211
implemented. This interface is used as part of the declaration of an `SqlOutParameter`.
212-
The following example shows returning the value of an Oracle `STRUCT` object of the user
212+
The following example shows returning the value of a `java.sql.Struct` object of the user
213213
declared type `ITEM_TYPE`:
214214

215-
[tabs]
216-
======
217-
Java::
218-
+
219-
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
220-
----
221-
public class TestItemStoredProcedure extends StoredProcedure {
222-
223-
public TestItemStoredProcedure(DataSource dataSource) {
224-
// ...
225-
declareParameter(new SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE",
226-
(CallableStatement cs, int colIndx, int sqlType, String typeName) -> {
227-
STRUCT struct = (STRUCT) cs.getObject(colIndx);
228-
Object[] attr = struct.getAttributes();
229-
TestItem item = new TestItem();
230-
item.setId(((Number) attr[0]).longValue());
231-
item.setDescription((String) attr[1]);
232-
item.setExpirationDate((java.util.Date) attr[2]);
233-
return item;
234-
}));
235-
// ...
236-
}
237-
----
238-
239-
Kotlin::
240-
+
241-
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
242-
----
243-
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
244-
245-
init {
246-
// ...
247-
declareParameter(SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE") { cs, colIndx, sqlType, typeName ->
248-
val struct = cs.getObject(colIndx) as STRUCT
249-
val attr = struct.getAttributes()
250-
TestItem((attr[0] as Long, attr[1] as String, attr[2] as Date)
251-
})
252-
// ...
253-
}
254-
}
255-
----
256-
======
215+
include-code::./TestItemStoredProcedure[]
257216

258217
You can use `SqlTypeValue` to pass the value of a Java object (such as `TestItem`) to a
259218
stored procedure. The `SqlTypeValue` interface has a single method (named
260219
`createTypeValue`) that you must implement. The active connection is passed in, and you
261-
can use it to create database-specific objects, such as `StructDescriptor` instances
262-
or `ArrayDescriptor` instances. The following example creates a `StructDescriptor` instance:
263-
264-
[tabs]
265-
======
266-
Java::
267-
+
268-
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
269-
----
270-
final TestItem testItem = new TestItem(123L, "A test item",
271-
new SimpleDateFormat("yyyy-M-d").parse("2010-12-31"));
272-
273-
SqlTypeValue value = new AbstractSqlTypeValue() {
274-
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
275-
StructDescriptor itemDescriptor = new StructDescriptor(typeName, conn);
276-
Struct item = new STRUCT(itemDescriptor, conn,
277-
new Object[] {
278-
testItem.getId(),
279-
testItem.getDescription(),
280-
new java.sql.Date(testItem.getExpirationDate().getTime())
281-
});
282-
return item;
283-
}
284-
};
285-
----
220+
can use it to create database-specific objects, such as `java.sql.Struct` instances
221+
or `java.sql.Array` instances. The following example creates a `java.sql.Struct` instance:
286222

287-
Kotlin::
288-
+
289-
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
290-
----
291-
val (id, description, expirationDate) = TestItem(123L, "A test item",
292-
SimpleDateFormat("yyyy-M-d").parse("2010-12-31"))
293-
294-
val value = object : AbstractSqlTypeValue() {
295-
override fun createTypeValue(conn: Connection, sqlType: Int, typeName: String?): Any {
296-
val itemDescriptor = StructDescriptor(typeName, conn)
297-
return STRUCT(itemDescriptor, conn,
298-
arrayOf(id, description, java.sql.Date(expirationDate.time)))
299-
}
300-
}
301-
----
302-
======
223+
include-code::./SqlTypeValueFactory[tag=struct,indent=0]
303224

304225
You can now add this `SqlTypeValue` to the `Map` that contains the input parameters for the
305226
`execute` call of the stored procedure.
306227

307228
Another use for the `SqlTypeValue` is passing in an array of values to an Oracle stored
308-
procedure. Oracle has its own internal `ARRAY` class that must be used in this case, and
309-
you can use the `SqlTypeValue` to create an instance of the Oracle `ARRAY` and populate
310-
it with values from the Java `ARRAY`, as the following example shows:
311-
312-
[tabs]
313-
======
314-
Java::
315-
+
316-
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
317-
----
318-
final Long[] ids = new Long[] {1L, 2L};
319-
320-
SqlTypeValue value = new AbstractSqlTypeValue() {
321-
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
322-
ArrayDescriptor arrayDescriptor = new ArrayDescriptor(typeName, conn);
323-
ARRAY idArray = new ARRAY(arrayDescriptor, conn, ids);
324-
return idArray;
325-
}
326-
};
327-
----
328-
329-
Kotlin::
330-
+
331-
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
332-
----
333-
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
334-
335-
init {
336-
val ids = arrayOf(1L, 2L)
337-
val value = object : AbstractSqlTypeValue() {
338-
override fun createTypeValue(conn: Connection, sqlType: Int, typeName: String?): Any {
339-
val arrayDescriptor = ArrayDescriptor(typeName, conn)
340-
return ARRAY(arrayDescriptor, conn, ids)
341-
}
342-
}
343-
}
344-
}
345-
----
346-
======
347-
229+
procedure. Oracle has an `createOracleArray` method on `OracleConnection` that you can
230+
access by unwrapping it. You can use the `SqlTypeValue` to create an array and populate
231+
it with values from the Java `java.sql.Array`, as the following example shows:
348232

233+
include-code::./SqlTypeValueFactory[tag=oracle-array,indent=0]
349234

framework-docs/modules/ROOT/pages/data-access/jdbc/simple.adoc

+6-6
Original file line numberDiff line numberDiff line change
@@ -323,12 +323,12 @@ use these alternative input classes.
323323

324324
The `SimpleJdbcCall` class uses metadata in the database to look up names of `in`
325325
and `out` parameters so that you do not have to explicitly declare them. You can
326-
declare parameters if you prefer to do that or if you have parameters (such as `ARRAY`
327-
or `STRUCT`) that do not have an automatic mapping to a Java class. The first example
328-
shows a simple procedure that returns only scalar values in `VARCHAR` and `DATE` format
329-
from a MySQL database. The example procedure reads a specified actor entry and returns
330-
`first_name`, `last_name`, and `birth_date` columns in the form of `out` parameters.
331-
The following listing shows the first example:
326+
declare parameters if you prefer to do that or if you have parameters that do not
327+
have an automatic mapping to a Java class. The first example shows a simple procedure
328+
that returns only scalar values in `VARCHAR` and `DATE` format from a MySQL database.
329+
The example procedure reads a specified actor entry and returns `first_name`,
330+
`last_name`, and `birth_date` columns in the form of `out` parameters. The following
331+
listing shows the first example:
332332

333333
[source,sql,indent=0,subs="verbatim,quotes"]
334334
----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.docs.dataaccess.jdbc.jdbccomplextypes;
18+
19+
import java.sql.Connection;
20+
import java.sql.SQLException;
21+
import java.text.ParseException;
22+
import java.text.SimpleDateFormat;
23+
24+
import oracle.jdbc.driver.OracleConnection;
25+
26+
import org.springframework.jdbc.core.SqlTypeValue;
27+
import org.springframework.jdbc.core.support.AbstractSqlTypeValue;
28+
29+
@SuppressWarnings("unused")
30+
class SqlTypeValueFactory {
31+
32+
void createStructSample() throws ParseException {
33+
// tag::struct[]
34+
TestItem testItem = new TestItem(123L, "A test item",
35+
new SimpleDateFormat("yyyy-M-d").parse("2010-12-31"));
36+
37+
SqlTypeValue value = new AbstractSqlTypeValue() {
38+
protected Object createTypeValue(Connection connection, int sqlType, String typeName) throws SQLException {
39+
Object[] item = new Object[] { testItem.getId(), testItem.getDescription(),
40+
new java.sql.Date(testItem.getExpirationDate().getTime()) };
41+
return connection.createStruct(typeName, item);
42+
}
43+
};
44+
// end::struct[]
45+
}
46+
47+
void createOracleArray() {
48+
// tag::oracle-array[]
49+
Long[] ids = new Long[] {1L, 2L};
50+
51+
SqlTypeValue value = new AbstractSqlTypeValue() {
52+
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
53+
return conn.unwrap(OracleConnection.class).createOracleArray(typeName, ids);
54+
}
55+
};
56+
// end::oracle-array[]
57+
}
58+
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.docs.dataaccess.jdbc.jdbccomplextypes;
18+
19+
import java.util.Date;
20+
21+
class TestItem {
22+
23+
private Long id;
24+
25+
private String description;
26+
27+
private Date expirationDate;
28+
29+
public TestItem() {
30+
}
31+
32+
public TestItem(Long id, String description, Date expirationDate) {
33+
this.id = id;
34+
this.description = description;
35+
this.expirationDate = expirationDate;
36+
}
37+
38+
public Long getId() {
39+
return this.id;
40+
}
41+
42+
public void setId(Long id) {
43+
this.id = id;
44+
}
45+
46+
public String getDescription() {
47+
return this.description;
48+
}
49+
50+
public void setDescription(String description) {
51+
this.description = description;
52+
}
53+
54+
public Date getExpirationDate() {
55+
return this.expirationDate;
56+
}
57+
58+
public void setExpirationDate(Date expirationDate) {
59+
this.expirationDate = expirationDate;
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.docs.dataaccess.jdbc.jdbccomplextypes;
18+
19+
import java.sql.CallableStatement;
20+
import java.sql.Struct;
21+
import java.sql.Types;
22+
23+
import javax.sql.DataSource;
24+
25+
import org.springframework.jdbc.core.SqlOutParameter;
26+
import org.springframework.jdbc.object.StoredProcedure;
27+
28+
@SuppressWarnings("unused")
29+
public class TestItemStoredProcedure extends StoredProcedure {
30+
31+
public TestItemStoredProcedure(DataSource dataSource) {
32+
super(dataSource, "get_item");
33+
declareParameter(new SqlOutParameter("item", Types.STRUCT, "ITEM_TYPE",
34+
(CallableStatement cs, int colIndx, int sqlType, String typeName) -> {
35+
Struct struct = (Struct) cs.getObject(colIndx);
36+
Object[] attr = struct.getAttributes();
37+
TestItem item = new TestItem();
38+
item.setId(((Number) attr[0]).longValue());
39+
item.setDescription((String) attr[1]);
40+
item.setExpirationDate((java.util.Date) attr[2]);
41+
return item;
42+
}));
43+
// ...
44+
}
45+
46+
}

0 commit comments

Comments
 (0)