I have a method for batch updating a table.
Problem is when i try to call below block of code it is giving class cast exception,
when(session.doWork(any())).thenAnswer(invocation -> {
Consumer<Connection> consumer = invocation.getArgument(0);
consumer.accept(mockConnection);
return null;
});
java.lang.ClassCastException: com.paypal.compliance.data.process.eftns.dao.impl.EFTReportsDAO$$Lambda$9/170106909 cannot be cast to java.util.function.Consumer
on debugging in intellij i found that invocation
has 2 arguments arg$1
and arg$2
, arg$1
is the SQL statement and arg$2
is a list of EFTReportsDO , how to extract these individually ?
Below are the method and test case
@Transactional(value = "test", propagation = Propagation.REQUIRES_NEW)
public void mergeAllEftReports(List<EFTReportsDO> instanceList) {
String updateSql = "UPDATE EFT_XYZ " +
"SET " +
"COMMENTS=?, " +
"PP_BATCH_SOURCE=?, " +
"WHERE " +
"PP_BATCH_ID=? " +
"AND REPORT_ID=?";
try {
Session session = entityManager.unwrap(Session.class);
session.doWork(connection -> {
try (PreparedStatement preparedStatement = connection.prepareStatement(updateSql)) {
for (EFTReportsDO entity : instanceList) {
preparedStatement.setString(1, entity.getComments());
preparedStatement.setString(2, entity.getPpBatchSource());
preparedStatement.setString(3, entity.getId().getPpBatchId());
preparedStatement.setString(4, entity.getId().getReportId());
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
}
});
} finally {
entityManager.flush();
entityManager.close();
}
}
@Test
public void testMergeAllEftReports() throws SQLException {
// Arrange
List<EFTReportsDO> instanceList = new ArrayList<>();
EFTReportsDO eftReportsDO = new EFTReportsDO(); // create an instance of EFTReportsDO
instanceList.add(eftReportsDO);
when(entityManager.unwrap(Session.class)).thenReturn(session);
Connection connection = mock(Connection.class);
PreparedStatement preparedStatement = mock(PreparedStatement.class);
when(connection.prepareStatement(anyString())).thenReturn(preparedStatement);
// Act & Assert
when(session.doWork(any())).thenAnswer(invocation -> {
Consumer<Connection> consumer = invocation.getArgument(0);
consumer.accept(mockConnection);
return null;
});
// Call the method under test
eftReportsDAO.mergeAllEftReports(instanceList);
verify(preparedStatement, times(1)).executeBatch();
// Verify that flush and close methods are called on the entityManager
verify(entityManager, times(1)).flush();
verify(entityManager, times(1)).close();
}
Your lambda cannot be cast to Consumer<Connection>
, it must match the type of SAM type expected by Session.doWork
, namely Work
doAnswer((invocation) -> {
Work jdbcWork = invocation.getArgument(0);
jdbcWork.execute(connection);
return null;
}).when(session).doWork(any());
Note: session.doWork
returns void, so I used doAnswer - when, instead of when - thenAnswer
In general, you cannot cast between 2 different SAM interfaces, even if their structure is identical:
interface StringConsumer1 {
void execute(String s1);
}
interface StringConsumer2 {
void execute(String s1);
}
@Test
void testLambdaConversionFails() {
Throwable thrown = catchThrowable(() -> {
StringConsumer1 l1 = (aaa) -> System.out.println(aaa);
StringConsumer2 l2 = (StringConsumer2) l1;
});
assertThat(thrown).isInstanceOf(ClassCastException.class);
}
In your case Consumer<Connection>
is not identical to Work
(method name and checked exceptions differ)