Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid NPE for anonymous SqlParameter in CallMetaDataContext [SPR-13628] #18206

Closed
spring-issuemaster opened this issue Nov 1, 2015 · 2 comments

Comments

@spring-issuemaster
Copy link
Collaborator

commented Nov 1, 2015

Luke Woodward opened SPR-13628 and commented

The following code uses a StoredProcedureItemReader to connect to an Oracle database and call a stored procedure that returns a ref cursor in a parameter:

package springitemreadertest;

import java.util.Map;
import javax.sql.DataSource;
import oracle.jdbc.OracleTypes;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.database.StoredProcedureItemReader;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.SqlParameter;

public class SpringItemReaderTest {
    public static void main(String[] args) throws Exception {
        DataSource dataSource = new MyDataSource();
        StoredProcedureItemReader<Map<String, Object>> storedProcedureItemReader = new StoredProcedureItemReader<>();
        storedProcedureItemReader.setDataSource(dataSource);
        storedProcedureItemReader.setProcedureName("PROC");
        storedProcedureItemReader.setParameters(new SqlParameter[] { new SqlParameter(/*"p_out",*/ OracleTypes.CURSOR) });
        storedProcedureItemReader.setRefCursorPosition(1);
        storedProcedureItemReader.setRowMapper(new ColumnMapRowMapper());
        storedProcedureItemReader.open(new ExecutionContext());
        storedProcedureItemReader.read();
    }
}

The stored procedure PROC doesn't do anything useful. Here's its definition:

procedure PROC (p_out OUT SYS_REFCURSOR)
is
begin
  open p_out for select * from dual;
end;

The class MyDataSource isn't particularly interesting either. It implements javax.sql.DataSource but has default implementations for all methods other than getConnection(). Any DataSource that connects to an Oracle database can be used instead of it.

When I run this code I get the following stacktrace:

Exception in thread "main" org.springframework.batch.item.ItemStreamException: Failed to initialize the reader
	at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:147)
	at springitemreadertest.SpringItemReaderTest.main(SpringItemReaderTest.java:20)
Caused by: java.lang.NullPointerException
	at org.springframework.jdbc.core.metadata.CallMetaDataContext.reconcileParameters(CallMetaDataContext.java:319)
	at org.springframework.jdbc.core.metadata.CallMetaDataContext.processParameters(CallMetaDataContext.java:293)
	at org.springframework.batch.item.database.StoredProcedureItemReader.openCursor(StoredProcedureItemReader.java:168)
	at org.springframework.batch.item.database.AbstractCursorItemReader.doOpen(AbstractCursorItemReader.java:406)
	at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:144)
	... 1 more

Of course, to fix the code, uncomment the parameter name I deliberately commented out. However, if I have unintentionally missed out the parameter name, or specified the parameter name and type the wrong way around (hence setting the type name instead of the parameter name), it would have been nice to have got an exception with a message that told me I needed to set a name for the SqlParameter.

Incidentally, issue #9490, which I found while seeing if this has already been reported, contains the following comment:

CallMetaDataContext reconcileParameters should check that a name exists for parameter to avoid NPE


Affects: 3.2.15, 4.1.8, 4.2.2

Referenced from: commits d1f5ee2, 6685c78, 2ea69c3

Backported to: 4.1.9, 3.2.16

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Nov 2, 2015

Juergen Hoeller commented

AbstractJdbcCall checks registered SqlParameter instances for specified names upfront. I guess the Spring Batch StoredProcedureItemReader could do the same name. Nevertheless, it's certainly worth making CallMetaDataContext itself more defensive there.

Juergen

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Nov 2, 2015

Juergen Hoeller commented

We're explicitly checking for an anonymous SqlParameter in CallMetaDataContext.reconcileParameters now, throwing a corresponding IllegalArgumentException. We'll also backport this since it's an easy one to include there.

Juergen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.