How to mock JdbcTemplace with RowMapper - spring-boot

I have a EmployeeDaoImpl class wish to mock JdbcTemplate and Rowmapper and set the dummy data to ResultSet. Given small snipper code below. Could you help me out on this.
public List<EmployeeTask> getDetails(String sql,String countryCode, int departmentNumber, Status status,
int sectionNumber,int aisle, String zone ){
if(status!=null) {
return jdbcTemplate.query(sql, new Object[] { countryCode,departmentNumber, Status.OK,sectionNumber,sectionId,zone},
(ResultSet rs, int rowNum) -> {
EmployeeTask employeeTask = new EmployeeTask();
employeeTask.setDepatmentNumber(rs.getInt("dept_number"));
employeeTask.setRemartks(rs.getString("remarks"));
return employeeTask;
});
} else {
return jdbcTemplate.query(sql, new Object[] { countryCode,departmentNumber, Status.OK,sectionNumber,sectionId,zone},
(ResultSet rs, int rowNum) -> {
EmployeeTask employeeTask = new EmployeeTask();
employeeTask.setDepatmentNumber(rs.getInt("dept_number"));
employeeTask.setRemartks(rs.getString("remarks"));
return employeeTask;
});
}
}

Unfortunately, neither your question nor the code snippet explains details about the context in which this Dao is implemented and used.
In general, I would recommend you to read the following article:
https://www.baeldung.com/spring-jdbctemplate-testing
It shows some ways how to test code based on a JdbcTemplate.

Related

Replacing RowMapper object with java 8 lambda expression

I am using Spring JdbcTemplate class in my project.I have the following code:
List<PersonDTO> personList = jdbcTemplate.query(query, new RowMapper<PersonDTO>() {
#Override
public PersonDTO mapRow(ResultSet rs, int rowNumber) throws SQLException {
PersonDTO personDTO = new PersonDTO ();
personDTO.setPerId(rs.getString("COL_ONE"));
personDTO.setIdTypeCd(rs.getString("COL_TWO"));
return personDTO;
}
});
Now I want to replace the anonymous class RowMapper with java8 lambda expression something like this:
Runnable r1 = () -> {
System.out.println("My Runnable");
};
Is it possible?
AFAIK RowMapper is a functional interface, so this would work. lambda expression can't declare checked exceptions, so you will need to wrap that...
jdbcTemplate.query(query, (ResultSet rs, int rowNumber) -> {
PersonDTO personDTO = new PersonDTO ();
personDTO.setPerId(rs.getString("COL_ONE"));
personDTO.setIdTypeCd(rs.getString("COL_TWO"));
return personDTO;
});
The comments are spot on: since that functional interface already declares to throw the exception, there is no need to catch it.
try this
List<PersonDTO> personList = jdbcTemplate.query(query, (rs,rowNumber) -> {
try
{PersonDTO personDTO = new PersonDTO ();
personDTO.setPerId(rs.getString("COL_ONE"));
personDTO.setIdTypeCd(rs.getString("COL_TWO"));
return personDTO;
}catch(SQLException e){
throw new RuntimeException("your error message",e) // or other unchecked exception here
}
});

jdbcTemplate.batchUpdate for list of inserts doesn't work

I'm out of nerves cells and I really need your help guys.
For some reason I can't get list of answers inserted to database
I use jdbcTemplate to do that and my code looks like this
public void insertVastaukset(List<Vastaus> vastaukset) {
final String sql = "insert into vastaus (kysymysID, vastausteksti) values(?,?)";
getJdbcTemplate().batchUpdate(sql,
new BatchPreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps, int i)
throws SQLException {
Vastaus vastaus = vastaukset.get(i);
ps.setInt(1, vastaus.getKysymysID());
ps.setString(2, vastaus.getVastausteksti());
}
#Override
public int getBatchSize() {
return vastaukset.size();
}
});}
And for some reason the program gives no error! When i tried it couple days ago it gave me null pointer, but now its fixed but still no inserts are created into database. Help me please, Thank you very much!
Use the below catch block to examine the exceptions
int[] updateCounts;
try {
updateCounts = getJdbcTemplate().batchUpdate("insert into test123 (id, value) values (?,?)",
new BatchPreparedStatementSetter() {
//// YOUR CODE HERE
});
}
catch (Exception sqle) {
Throwable s2 = sqle;
System.out.println("=============v"+s2.getClass().getName()+"=====================");
while (s2!=null) {
s2.printStackTrace();
s2 = s2.getCause();
if(s2 instanceof java.sql.BatchUpdateException) {
System.out.println("======================^^^^^^======================");
((java.sql.BatchUpdateException) s2).getNextException().printStackTrace();
}
}
throw sqle;
}

ASMX Web Service, Stored Procedures and MVC Models

I am developing a web application using MVC 3. This application connects to an SQL Server database through ASMX Web Services. Each Web Method calls a Stored Procedure and returns a DataTable.
This is the code I'm using to call the Stored Procedure:
public static DataTable ExecSP(string StoredProcedureName, List<string> ParameterNames, List<Object> ParameterValues)
{
SqlConnection Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLServer"].ConnectionString);
SqlDataReader Reader = null;
DataTable SPResult = null;
try
{
Connection.Open();
SqlCommand Command = new SqlCommand("dbo." + StoredProcedureName, Connection);
Command.CommandType = CommandType.StoredProcedure;
if (ParameterNames != null)
{
for (int i = 0; i < ParameterNames.Count; i++)
{
SqlParameter Parameter = new SqlParameter(ParameterNames[i], ParameterValues[i]);
if (Parameter.SqlDbType.Equals(SqlDbType.NVarChar))
{
Parameter.SqlDbType = SqlDbType.VarChar;
}
if (Parameter.SqlValue == null)
{
Parameter.SqlValue = DBNull.Value;
}
Command.Parameters.Add(Parameter);
}
}
Reader = Command.ExecuteReader();
SPResult = new DataTable();
SPResult.Load(Reader);
}
catch (Exception ex)
{
throw;
}
finally
{
Connection.Close();
if (Reader != null)
{
Reader.Close();
}
}
return SPResult;
}
I would like to know if there is a straight-forward way to convert this DataTable into a Model that can then be passed to a View (like, for example, the model binding that happens in an AJAX post) and, if there isn't, what are the alternatives. I know that using LINQ would probably solve this problem, but I can't use it.
Thanks in advance.
Best regards.
Found a solution.
I built a generic method that translates any DataTable into a List of whatever class I specify:
public static List<T> Translate<T>(DataTable SPResult, Func<object[],T> del)
{
List<T> GenericList = new List<T>();
foreach (DataRow Row in SPResult.Rows)
{
GenericList.Add(del(Row.ItemArray));
}
return GenericList;
}
where del is a delegate. When calling this method, del should be the constructor of the specified class. Then, in all Model classes, I built a constructor that receives an object[] RowFromTable
public class MyClass
{
public int ID { get; set; }
public string Description { get; set; }
public FormaProcesso(object[] RowFromTable)
{
this.ID = (int)RowFromTable[0];
this.Description = RowFromTable[1].ToString();
}
}
Finally, to put it all together, this is what happens when I call the Web Method:
public List<MyClass> GetAll()
{
DataTable SPResult = MyWebService.GetAll().Table;
return Translate<MyClass>(SPResult, l => new MyClass(l));
}
Got the idea from here

JavaFX Table Cell Formatting

TableColumn<Event,Date> releaseTime = new TableColumn<>("Release Time");
releaseTime.setCellValueFactory(
new PropertyValueFactory<Event,Date>("releaseTime")
);
How can I change the format of releaseTime? At the moment it calls a simple toString on the Date object.
If you want to preserve the sorting capabilities of your TableColumn, none of the solutions above is valid: if you convert your Date to a String and show it that way in your TableView; the table will sort it as such (so incorrectly).
The solution I found was subclassing the Date class in order to override the toString() method. There is a caveat here though: the TableView uses java.sql.Date instead of java.util.Date; so you need to subclass the former.
import java.text.SimpleDateFormat;
public class CustomDate extends java.sql.Date {
public CustomDate(long date) {
super(date);
}
#Override
public String toString() {
return new SimpleDateFormat("dd/MM/yyyy").format(this);
}
}
The table will call that method in order to print the date.
Of course, you need to change too your Date class in the TableColumn declaration to the new subclass:
#FXML
TableColumn<MyObject, CustomDate> myDateColumn;
Same thing when you attach your object attribute to the column of your table:
myDateColumn.setCellValueFactory(new PropertyValueFactory< MyObject, CustomDate>("myDateAttr"));
And finally, for the shake of clarity this is how you declare the getter in your object class:
public CustomDate getMyDateAttr() {
return new CustomDate(myDateAttr.getTime()); //myDateAttr is a java.util.Date
}
It took me a while to figure out this due to the fact that it uses java.sql.Date behind the scenes; so hopefully this will save other people some time!
Update for Java FX8:
(I'm not sure it is the good place for that answer, but I get the problem in JavaFX8 and some things have changed, like java.time package)
Some differences with the previous answers:
I keep the date type on the column, so I need to use both cellValueFactory and cellFactory.
I Make a generic reusable method to generate the cellFactory for all date columns.
I use java 8 date for java.time package! But the method could be easily reimplemented for java.util.date.
#FXML
private TableColumn<MyBeanUi, ZonedDateTime> dateColumn;
#FXML
public void initialize () {
// The normal binding to column
dateColumn.setCellValueFactory(cellData -> cellData.getValue().getCreationDate());
//.. All the table initialisation and then
DateTimeFormatter format = DateTimeFormatter .ofLocalizedDate(FormatStyle.SHORT);
dateColumn.setCellFactory (getDateCell(format));
}
public static <ROW,T extends Temporal> Callback<TableColumn<ROW, T>, TableCell<ROW, T>> getDateCell (DateTimeFormatter format) {
return column -> {
return new TableCell<ROW, T> () {
#Override
protected void updateItem (T item, boolean empty) {
super.updateItem (item, empty);
if (item == null || empty) {
setText (null);
}
else {
setText (format.format (item));
}
}
};
};
}
The advantages are that:
The column is typed with a "java8 Date" to avoid the sort problem evoqued by #Jordan
The method "getDateCell" is generic and can be used as an util function for all Java8 Time types (Local Zoned etc.)
I'd recommend using Java generics to create re-usable column formatter that takes any java.text.Format. This cuts down on the amount of boilerplate code...
private class ColumnFormatter<S, T> implements Callback<TableColumn<S, T>, TableCell<S, T>> {
private Format format;
public ColumnFormatter(Format format) {
super();
this.format = format;
}
#Override
public TableCell<S, T> call(TableColumn<S, T> arg0) {
return new TableCell<S, T>() {
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
setGraphic(new Label(format.format(item)));
}
}
};
}
}
Examples of usage
birthday.setCellFactory(new ColumnFormatter<Person, Date>(new SimpleDateFormat("dd MMM YYYY")));
amplitude.setCellFactory(new ColumnFormatter<Levels, Double>(new DecimalFormat("0.0dB")));
I needed to do this recently -
dateAddedColumn.setCellValueFactory(
new Callback<TableColumn.CellDataFeatures<Film, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Film, String> film) {
SimpleStringProperty property = new SimpleStringProperty();
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
property.setValue(dateFormat.format(film.getValue().getCreatedDate()));
return property;
}
});
However - it is a lot easier in Java 8 using Lamba Expressions:
dateAddedColumn.setCellValueFactory(
film -> {
SimpleStringProperty property = new SimpleStringProperty();
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
property.setValue(dateFormat.format(film.getValue().getCreatedDate()));
return property;
});
Hurry up with that Java 8 release oracle!
You can accomplish that through Cell Factories. See
https://stackoverflow.com/a/10149050/682495
https://stackoverflow.com/a/10700642/682495
Although the 2nd link is about ListCell, the same logic is totally applicable to TableCells too.
P.S. Still if you need some sample code, kindly will attach here.
An universal solution could be as simple as that:
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
public interface AbstractConvertCellFactory<E, T> extends Callback<TableColumn<E, T>, TableCell<E, T>> {
#Override
default TableCell<E, T> call(TableColumn<E, T> param) {
return new TableCell<E, T>() {
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
setText(convert(item));
}
}
};
}
String convert(T value);
}
And its sample usage:
TableColumn<Person, Timestamp> dateCol = new TableColumn<>("employment date");
dateCol.setCellValueFactory(new PropertyValueFactory<>("emploumentDateTime"));
dateCol.setCellFactory((AbstractConvertCellFactory<Person, Timestamp>) value -> new SimpleDateFormat("dd-MM-yyyy").format(value));
This is what i did and i worked perfectly.
tbColDataMovt.setCellFactory((TableColumn<Auditoria, Timestamp> column) -> {
return new TableCell<Auditoria, Timestamp>() {
#Override
protected void updateItem(Timestamp item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
setText(item.toLocalDateTime().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
}
}
};
});
You can easily pipe Properties of different type and put a formatter or converter in between.
//from my model
ObjectProperty<Date> valutaProperty;
//from my view
TableColumn<Posting, String> valutaColumn;
valutaColumn.setCellValueFactory(
cellData -> {
SimpleStringProperty property = new SimpleStringProperty();
property.bindBidirectional(cellData.getValue().valutaProperty, new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN));
return property;
});
The StringConverter classes are another mechanism.
TextFieldTableCell has a constructor as follows: public TextFieldTableCell(StringConverter<T> converter).
... and StringConverters consist of subclasses such as LocalDateStringConverter. A default implementation would then be:
new TextFieldTableCell( new LocalDateStringConverter() );
... this is not bad, but the parameter-less LocalDateStringConverter uses dates of the format 'dd/mm/yyyy' both for parsing (fromString() method) and toString(). But there are other constructors where you can pass a FormatStyle or DateTimeFormatter.
From my experiments, however, StringConverters are slightly problematic in that it is difficult to catch the DateTimeParseException thrown by fromString() with an invalid date.
This can be remedied by creating your own StringConverter class, e.g.:
class ValidatingLocalDateStringConverter extends LocalDateStringConverter {
boolean valid;
#Override
LocalDate fromString(String value) {
valid = true;
if (value.isBlank()) return null;
try {
// NB wants ISO
return LocalDate.parse( value );
} catch ( DateTimeParseException e) {
valid = false;
}
return null;
}
#Override
String toString( LocalDate date ){
// NB returns ISO or the String "null" with null date value (!)
String s = date.toString();
return s.equals( 'null' )? '' : s;
}
}
Using this StringConverter solution will mean that dates are sorted according to chronological order, regardless of the String representation.

Incorrect number of arguments for PROCEDURE; expected 1, got 0. Cant determine the error from code

//set input parameters
Map<String,Object> inParams = new HashMap<String,Object>();
inParams.put("Sig",resourceHistoryBean.getId());
List<ResourceHistoryBean> resourceHistoryList= new ArrayList<ResourceHistoryBean>();
// define stored procedure
try{
SimpleJdbcCall readResult = new SimpleJdbcCall(getDataSource())
.useInParameterNames("Sig")
.declareParameters(new SqlParameter("Sig", Types.VARCHAR))
.withProcedureName("SP_ResourceAllocationDtls")
.withSchemaName("hrms")
.returningResultSet("ResourceHistory", new ParameterizedRowMapper<ResourceHistoryBean>() {
public ResourceHistoryBean mapRow(ResultSet rs, int rowNum)
throws SQLException {
ResourceHistoryBean bean = new ResourceHistoryBean();
resourceHistoryBean.setProjectName(rs.getString(RH_PROJECT_NAME));
return bean;
}
});
readResult.compile();
// execute stored procedure
Map<String, Object> out = readResult.execute(inParams);
resourceHistoryList = (List<ResourceHistoryBean>) out.get("ResourceHistory");
Looks like I was able to find an alternative solution to above problem (Parameter passing to stored procedure and use a mapping class as well ):
public List<ResourceHistoryBean> getResourceHistory(final ResourceHistoryBean resourceHistoryBean)throws Exception{
try {
// call stored procedure and pass parameter to it
List resourceHistoryList = getJdbcTemplate().query(
"call hrms.SP_ResourceAllocationDtls(?)",
new Object[] {resourceHistoryBean.getId()}, new HistoryMapper());
return resourceHistoryList;
} catch (Exception e) {
throw e;
} finally {
closeTemplate();
}
}
// mapper class
class HistoryMapper implements RowMapper, IDatabaseConstants {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
ResourceHistoryBean resourceHistoryBean = new ResourceHistoryBean();
resourceHistoryBean.setProjectName(rs.getString(RH_PROJECT_NAME));
return resourceHistoryBean;
}
}

Resources