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

JdbcJobExecutionDao throws NullPointerException #3990

Open
adrianriley opened this issue Sep 7, 2021 · 2 comments
Open

JdbcJobExecutionDao throws NullPointerException #3990

adrianriley opened this issue Sep 7, 2021 · 2 comments
Labels
status: waiting-for-reporter Issues for which we are waiting for feedback from the reporter type: bug

Comments

@adrianriley
Copy link

adrianriley commented Sep 7, 2021

Bug description
BATCH_JOB_EXECUTION.STATUS may be null. If it is, a NullPointerException is thrown by JdbcJobExecutionDao.JobExecutionRowMapper.mapRow, See this line:

jobExecution.setStatus(BatchStatus.valueOf(rs.getString(4)));

Environment
spring-batch-core 4.2.1.RELEASE. But the bug still appears to be there in 5.0.0-SNAPSHOT

Steps to reproduce
Actually happened calling JdbcJobExecutionDao.findRunningJobExecutions(), but you can see it on the UI.
Pick an instance. Update BATCH_JOB_EXECUTION.STATUS to null. Try to view it on .../dashboard/#/tasks-jobs/task-executions/nnnn

Expected behavior
I'd expect status to be blank. Not a NullPointerException.

Minimal Complete Reproducible example

package uk.co.closemf.collection.support.event.batch;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.batch.core.repository.dao.JdbcJobExecutionDao;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;

import static org.assertj.core.api.Assertions.assertThatCode;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class JdbcJobExecutonDaoTest {
    @InjectMocks
    private JdbcJobExecutionDao jdbcJobExecutionDao;

    @Mock
    private JdbcTemplate jdbcTemplate;

    @Test
    void mapRow() throws SQLException {
        ResultSet rs = mock(ResultSet.class);
        when(rs.next()).thenReturn(true, false);
        when(rs.getLong(1)).thenReturn(1L);
        when(rs.getTimestamp(anyInt())).thenReturn(new Timestamp(System.currentTimeMillis()));
        when(rs.getString(anyInt())).thenAnswer(invocation -> {
            int i = invocation.getArgument(0, Integer.class);
            switch (i) {
                case 3:
                    return "STRING";
                case 4:
                    return null;
                default:
                    return "";
            }
        });
        when(rs.getInt(9)).thenReturn(1);
        lenient().doAnswer(invocation -> {
            RowCallbackHandler rch = invocation.getArgument(2, RowCallbackHandler.class);
            rch.processRow(rs);
            return null;
        }).when(jdbcTemplate)
                .query(anyString(), any(Object[].class), any(RowCallbackHandler.class));

        ;

        assertThatCode(() -> jdbcJobExecutionDao.findRunningJobExecutions("job"))
                .doesNotThrowAnyException();
    }
}
@adrianriley adrianriley added status: waiting-for-triage Issues that we did not analyse yet type: bug labels Sep 7, 2021
@fmbenhassine
Copy link
Contributor

BATCH_JOB_EXECUTION.STATUS should not be null. It starts with STARTING and is updated to other non null values during the job execution. Unless updated manually to null in the database (which is not supposed to be done), I don't see where it could be set to null in the code. So before fixing the bug in any UI, I would like to see the circumstances under which this column ends up being null. Can you please share more details about how/when this happens?

@fmbenhassine fmbenhassine added status: waiting-for-reporter Issues for which we are waiting for feedback from the reporter and removed status: waiting-for-triage Issues that we did not analyse yet labels Sep 8, 2021
@adrianriley
Copy link
Author

Sorry, I can't see how it happened either. I've seen one instance from some months ago, but it's only just come to light by implementing use of findRunningJobExecutions(). Logging of the execution which created the row in the SCDF logs is minimal, so my guess is that it was created by running the application outside of the SCDF server, using the same DB. As you say, the initial creation of the row should have status STARTING and I don't see how it can ever be set to null using code in the spring batch libs.
So maybe it's a non-issue. But the DB column is nullable so defensively perhaps the code shouldn't assume values are not null.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-reporter Issues for which we are waiting for feedback from the reporter type: bug
Projects
None yet
Development

No branches or pull requests

2 participants