Here I am getting Error at the List<Data> dataList = jdbcTemplate.query location.
Checkmarx says:
AppServices/src/main/java/com/mbusa/app/dao/impl/AppRequestDAOImpl.java
gets data from the database, for the query element. This element’s
value then flows through the code without being properly filtered or
encoded and is eventually displayed to the user in method
getRequestDetail at line 117 of
AppWeb/src/main/java/com/mbusa/app/controllers/AppRequestController.java.
This may enable a Stored Cross-Site-Scripting attack.
List<Data> dataList = jdbcTemplate.query(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
PreparedStatement pstmt = conn.prepareStatement(fSQL);
int index = 1;
for(Object param: effParams) {
pstmt.setString(index, (String) param);
index++;
}
return pstmt;
}
}, new RequestMapper());
public class RequestMapper implements RowMapper<Data> {
#Override
public Data mapRow(ResultSet rs, int rowNum) throws SQLException {
Data data = new Data();
data.setName(rs.getString("name"));
return data ;
}
}
I have added PreparedStatement here to resolve this issue and also tried adding HtmlUtil.htmlEscape upon output data, but still could not resolve this issue.
Can anyone help with this issue?
Related
I'am writing a method to retrieve an element of a DB giving a Long id parameter.
This id is unique, so the method should just return one element, and I want to create a class instance with this element retrived.
I've made the following method that works perfectly fine:
#Override
public ElementEntity getElement(final long id)
{
final MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValue("element_id", id);
final List<ElementEntity > listOfElements =
namedParameterJdbcOperations.query(SQL_RETURN_ELEMENT_BY_ID, paramSource, ROW_MAPPER_ELEMENT);
return !listOfElements .isEmpty() ? listOfElements.get(0) : null;
}
The ROW_MAPPER is implemented this way:
private static final RowMapper<ElementEntity > ROW_MAPPER_INSTALLER =
(rs, RowNum) ->
new ElementEntityBuilder().setElement(rs.getBytes("ELEMENT")).build();
The element is a byte array. I repeat, works perfectly. But I would like to avoid using a list and retrieving the first position and, instead, create directly the ElementEntity. So I tried the following approach:
#Override
public ElementEntity getElement(final long id)
{
final MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValue("element_id", id);
return namedParameterJdbcOperations.query(SQL_RETURN_ELEMENT_BY_ID, paramSource, (ResultSet rs) -> new DesktopAppInstallerEntity(rs.getBytes("ELEMENT")));
}
Althought I have't made any more changes, it gives me the following error:org.h2.jdbc.JdbcSQLNonTransientException: No data is available.
That's the full error (I changed some words to avoid showing the real SQL query):
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [SELECT SOMETHING FROM SOMEWHERE WHERE id = ?]; No data is available [2000-200]; nested exception is org.h2.jdbc.JdbcSQLNonTransientException: No data is available [2000-200]
I'm pretty new to all this JDBC, but it seems to me that the paramSource is not working properly when I apply this changes and I don't have the foggiest idea why is happening because I'm just changing the result extractor.
Well, I figured it out myself. I will share my answer to help the community. I used NamedParameterJdbcOperations.queryForObject instead of namedParameterJdbcOperations.query and used the same ROW_MAPPER:
#Override
public ElementEntity getElement(final long id)
{
final MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValue("id", id);
try
{
return namedParameterJdbcOperations.queryForObject(SQL_RETURN_ELEMENT, paramSource, ROW_MAPPER_ELEMENT);
}
catch (EmptyResultDataAccessException e)
{
return null;
}
}
In my particular case I'm interested to catch when the SQL Query attempt to find an Element that doesn't exist in the DB. For this purpose I catch and handle the EmptyResultDataAccessException thrown.
More info could be found here: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.html#queryForObject-java.lang.String-org.springframework.jdbc.core.namedparam.SqlParameterSource-org.springframework.jdbc.core.RowMapper-
I am trying to implement code which will have resultset using simpljdbccall or jdbccall or namedtemplatejdbc
Code will use my stored procedure which is database proc having input parameter and an REF cursor.
I did not found any code which will help me to extract cursor as output to have all multiple rows details in in my resultset using JDBC
DATABASE PROCEDURE
BOOKING_PG.get_infant_info_pr(
c_booking_id IN T_BOOKED_INFANT_INFO.BOOKING_ID%TYPE,
c_booked_infant_details OUT booked_infant_details
)
OPEN c_booked_infant_details FOR
SELECT
BOOKING_ID c_booking_id,
BOOKED_INFANT_INFO_ID c_booked_infant_info_id,
BOOKED_ADULT_PAX_INFO_ID c_booked_adult_pax_info_id,
FROM T_BOOKED_INFANT_INFO T
WHERE T.BOOKING_ID = c_booking_id
and T.STATUS_ID = 1;
JAVA Code
SimpleJdbcCall call = new SimpleJdbcCall(dataSource2)
.withCatalogName("BOOKING_PG")
.withProcedureName("get_infant_info_pr")
.withoutProcedureColumnMetaDataAccess()
.returningResultSet("rs1", new ParameterizedRowMapper() {
#Override
public Object[] mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Object[]{rowNum, rs.getLong("c_booking_id"), rs.getLong(c_booked_infant_info_id) , rs.getLong(c_booked_adult_pax_info_id)};
}
});
SqlParameterSource in = new MapSqlParameterSource()
.addValue(C_BOOKING_ID, bookingId);
Map<String, Object> res = call.execute(in);
List<Object[]> l1 = (List<Object[]>)res.get("rs1");
It is throwing SQL error
org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{call EURONOVA.BOOKING_PG.GET_INFANT_INFO_PR(?)}]; nested exception is java.sql.SQLException: ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'GET_INFANT_INFO_PR'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
I am not sure if there is something wrong in the code or we have to follow some different way to get resultset in simplejdbc call
Can someone please help me in this topic?
First create a class having similar data type and names which your cursor returns.
In your case create a class named BookedInfantDetails.java
public class BookedInfantDetails{
private int bookingId;
private int bookedInfantinfoId;
private int bookedadultpaxinfoid;
public int getBookingId() {
return bookingId;
}
public void setBookingId(int bookingId) {
this.bookingId = bookingId;
}
public int getBookedInfantinfoId() {
return bookedInfantinfoId;
}
public void setBookedInfantinfoId(int bookedInfantinfoId) {
this.bookedInfantinfoId = bookedInfantinfoId;
}
public int getBookedadultpaxinfoid() {
return bookedadultpaxinfoid;
}
public void setBookedadultpaxinfoid(int bookedadultpaxinfoid) {
this.bookedadultpaxinfoid = bookedadultpaxinfoid;
}
}
Now declare in and out parameters in the jdbccall and map the ref cursor to the class using beanproperty rowmapper.
SimpleJdbcCall call = new SimpleJdbcCall(dataSource2)
.withCatalogName("BOOKING_PG")
.withProcedureName("get_infant_info_pr")
.withoutProcedureColumnMetaDataAccess()
.declareParameters(new SqlParameter("c_booking_id", OracleTypes.Integer),
new SqlParameter("c_booked_infant_details", OracleTypes.CURSOR),
.returningResultSet("c_booked_infant_details",
BeanPropertyRowMapper.newInstance(BookedInfantDetails.class));
SqlParameterSource in = new MapSqlParameterSource()
.addValue(C_BOOKING_ID, bookingId);
Map<String, Object> res = call.execute(in);
List<BookedInfantDetails> l1=
(List<BookedInfantDetails>)res.get("c_booked_infant_details");
Find Our more details on spring docs....
https://docs.spring.io/spring-data/jdbc/old-docs/1.2.1.RELEASE/reference/html/orcl.datatypes.html#orcl.datatypes.ref_cur
I have a webapp where I need to retrieve data from DB via JDBC and display it front end. Its a static data and it wont be changed. So I just need the data to be retrieved just once and store in a static variable and so I can use that data every time instead of querying the database. Below is the sample code:
public class SampleClass(){
static Map<String, BigDecimal> productMap = null;
public Map<String, BigDecimal> getDatafromDB(Connection conn, PreparedStatement stmt, ResultSet rs) throws SQLException{
if(productMap == null){
productMap = getProductID(conn, stmt, rs);
}
return productMap;
}
public Map<String, BigDecimal> getProductID(Connection conn, PreparedStatement stmt, ResultSet rs) throws SQLException {
logger.debug("retrieving product ID's from product table..");
Map<String, BigDecimal> productMap = new HashMap<String, BigDecimal>();
stmt = conn.prepareStatement("Select * from PRODUCTTABLE");
rs = stmt.executeQuery();
logger.debug("Product ID's retrieved");
while(rs.next()){
productMap.put(rs.getString("PRODUCT_NAME"),rs.getBigDecimal("PRODUCT_ID"));
}
if (stmt != null) {
stmt.close();
}
if (rs != null) {
rs.close();
}
return productMap;
}
}
I am calling this method from UI through a http servlet request. For the first time when I run it, since the map is null it queries the data base and gets the data and sends it to UI. When I hit the servlet again for the second time with the new request the product map is null and again its querying the database and getting the data. Since its a static variable it should be only initialized once rite so why is it still null for the second request. Can someone please correct my code ?
Thanks in advance
The root cause of your problem is that a servlet is memoryless. So a static variable will not help. What you need is a session attribute instead.
I suggest adding your variable as a session attribute. In the first place you need to create an encapsulating class that implements Serializable:
public class SampleResult implements Serializable {
private Map<String, String> productMap;
public void setProductMap(Map<String, String> productMap) {
this.productMap = productMap;
}
public Map<String, String> getProductMap() {
return productMap;
}
}
Now in your servlet:
HttpSesssion session = request.getSession();
Map<String, String> productMap;
SampleResult result;
if (session.getAttribute("productMap") == null) {
productMap = retrievedatafromDB();
result = new SampleResult();
sampleResult.setProductMap(productMap);
session.setAttribute("productMap", result);// session attribute created
} else {
result = session.getAttribute("productMap");// retrieve session attribute
productMap = result.getProductMap();
}
Can someone please tell me why do i sql get exception that "Invalid object #EMP_TEMP" even if i am running both queries under same transaction?
#Transactional
public Map<String, EventType> findEventsByDateRange(final Date startTimestamp, final Date endTimestamp) throws Exception {
log.debug("Fetching Events Data");
String EVENT_QUERY = "Select ID, Name, Status, JoinDate into #EMP_TEMP from EMPLOYEE where JoinDate >= ? and JoinDate < ?";
this.jt.execute(EVENT_QUERY, new PreparedStatementCallback<Boolean>() {
#Override
public Boolean doInPreparedStatement(PreparedStatement preparedStatement) throws SQLException, DataAccessException {
preparedStatement.setTimestamp(1, new java.sql.Timestamp(startTimestamp.getTime()));
preparedStatement.setTimestamp(2, new java.sql.Timestamp(endTimestamp.getTime()));
return preparedStatement.execute();
}
});
//this.jt.execute(EVENT_QUERY);
return this.jt.query("SELECT * from #EMP_TEMP "
, DataExtractor.eventDataExtractor);
}
However if i change code as below then it doesn't complaint. but problem in this approach is that i cannot pass any parameters into first query:
#Transactional
public Map<String, EventType> findEventsByDateRange(final Date startTimestamp, final Date endTimestamp) throws Exception {
log.debug("Fetching Events Data");
String EVENT_QUERY = "Select ID, Name, Status, JoinDate into #EMP_TEMP from EMPLOYEE where JoinDate >= '2015-07-13 00:00:00.000' and JoinDate < '2015-07-14 00:00:00.000'";
/*this.jt.execute(EVENT_QUERY, new PreparedStatementCallback<Boolean>() {
#Override
public Boolean doInPreparedStatement(PreparedStatement preparedStatement) throws SQLException, DataAccessException {
preparedStatement.setTimestamp(1, new java.sql.Timestamp(startTimestamp.getTime()));
preparedStatement.setTimestamp(2, new java.sql.Timestamp(endTimestamp.getTime()));
return preparedStatement.execute();
}
});*/
this.jt.execute(EVENT_QUERY);
return this.jt.query("SELECT * from #EMP_TEMP "
, DataExtractor.eventDataExtractor);
}
Finally i found out that root cause of the problem is not spring but sql server.
In SQL Server 2005, SQL Server 2000, and SQL Server 7.0, the prepared statements cannot be used to create temporary objects and cannot reference system stored procedures that create temporary objects, such as temporary tables. These procedures must be executed directly.
Since i was trying to create the temp table by jdbcTemplate method execute(String sql, PreparedStatementCallback action) which uses prepared statement therefore it was not working.
Instead of that when i created temp table using execute(String sql) it is working.
Recently I was looking at the frequent hangs of the tomcat server and came across some exceptions thrown frequently in some part of the code.
When I examined the code, this what it looked like
public static String doSomething() {
String returnVakue = "default value";
try {
ResultSet rs = getMyResultSet();
rs.first();
returnValue = rs.getString("my_field"); // Note that Exception happens at times when the ResultSet is empty
} catch (Exception e) {
throw new Exception(e);
} finally {
return returnValue;
}
}
While I am aware that it is perfectly OK to have both throws exception and return, wondering if this can cause any kind of leaks in tomcat. And Is there any potential risk with performance. ? Hoowever my caller function stops the execution at this point. Any views on this? Does it affect the GC?
EDIT : NOTE : I Know how to correct this code. Please share your views whether this can potentially cause tomcat hanging.
First check if returned ResultSet is empty.
while( rs.next() ) {
// ResultSet processing here
// Result set is not empty
}
In my opinion throwing exception is your decision, but in finally you should be doing clean up e.g. closing Connections.
Open Connections if not closed will cause tomcat to hang because new requests coming to server will be waiting for connections to become available.
Any object in Java which is referenced is not garabage collected, in your case if Connections are not closing then these objects will not be garbage collected.
Cheers !!
If a query takes a long time, not a question of JDBC. The database is responsible. Of course, if JDBC is used properly. In another hand, if you use simple JDBC, it is best that you add a layer DAO in your application.
public class UserDAO extends DAO {
private static final String FIND_BY_PK_SQL =
"SELECT mail, password " +
" FROM user WHERE mail = ?";
public User findByPk(final String mail) throws DAOException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = getConnection();
ps = conn.prepareStatement(FIND_BY_PK_SQL);
ps.setString(1, mail);
rs = ps.executeQuery();
if (rs.next()) {
return fill(rs);
}
return null;
} catch (final SQLException e) {
throw new DAOException(e);
} finally {
DbUtils.closeQuietly(conn, ps, rs);
}
}
private User fill(final ResultSet rs) throws SQLException {
final User user = new User();
user.setMail(rs.getString("mail"));
user.setPassword(rs.getString("password"));
return user;
}
}