Returning a null array string in java - java

I am having a java class where I am executing a query and assigning the query result to an string array, finally return the array.
Everything works fine. But I want to return "no data" if the db values are empty (not the whole array). what can I do for this?
Code:
query="select `t1`,`t2`,`t3` from test";
PreparedStatement pre = conn.prepareStatement(query);
ResultSet res = pre.executeQuery();
String val[][] = new String[res.getRow()][3];
while (res.next()) {
val[i][0] = res.getString(1);
val[i][1] = res.getString(2);
val[i][2] = res.getString(3);
i++;
}
res.close();
conn.close();
pre.close();
return (val);
(Where I want the val[1][1] to be "No Data" if res.getString(2) is null).

No Data seems to be a value you display more than a logical value.
So you should decide of a special value and display it in a special way. We usually call this a sentry value.
This value could be null or a string that can't be in your db. (maybe it doesn't apply here as everything is often possible in a db).
Also note that it could be attractive to use an exception instead of this special value but it is actually a very poor use of exceptions, mostly for performance issues and hence it is a design to avoid if possible except if this value can lead to problems for your clients classes.

try this way
val[i][0] = (res.getString(1)!=null & !res.getString(1).equals(""))?res.getString(1).equals(""):"No Data";
val[i][1] = (res.getString(1)!=null & !res.getString(2).equals(""))?res.getString(3).equals(""):"No Data";
val[i][2] = (res.getString(1)!=null & !res.getString(3).equals(""))?res.getString(3).equals(""):"No Data";
use the only one "&" what happen when you check the condition with && first it will check for the first i.e. rs.getString(1)!=null if this is null or not it will check for the another condition i.e. rs.getString(1).equal("") so if you check and it will null then in second condition it will cause the error for NullPointerException.
while if you use only one & then it will check first condition if that was true then only it go for check the another condition otherwise not.

Add small helper methods like this:
public static String getValue(String value) {
return getValue(value, "No Data");
}
public static String getValue(String value, String default) {
return value == null ? default : value;
}
Use it like this:
val[i][0] = getValue(res.getString(1)); // standard
val[i][0] = getValue(res.getString(1), "NULL"); // with custom default message

Related

Why the retrieved result set string doesn't work with the .equals()

I'm retrieving some information from a database and I want to check if the value is null. Although the string retrieved from the database is "null" the equals() returns false.
I tried trim(), just in case there were any spaces in the retrieved string
String code = product.retrieveCode();
System.out.println("the code is :"+ code);
if (code.equals("null")==true){
// do this
}
else{
// do that
}
Please let it be noted that the database doesn't have any data stored.
As pointed out by 'Eran', the value in code is probably a null reference. Do,
if (code == null)
instead of
if (code.equals("null")==true)
This likely occurs because the rs object returns null when you call it's getString() method. ResultSet will return null when the column value is SQL NULL. (Reference)
your logic and syntax is correct.In this case here your database value is probably assigning null value to code and you are checking whether a string of "null" is equal to code. This will give error as it is null reference. Make sure that you are getting a "null" else if its empty just check equals case withe whitespace
It prints Yes. so I don't think java doing anything wrong
String code = "null";
if (code.equals("null")){
System.out.println("Yes");
} else{
// do that
}
I think it is a null reference. Please do the below code.
if (code==null){
System.out.println("Yes");
} else{
// do that
}

Getting No data when accessing SAP table with jCo(3.x))

Here is my sample code.In this example has only elementary types,no structure types has to set.But in the output no data exists in the table.
When I check the records in SAP it contains multiple records for this particular id.Can someone explain this to me?
public void invokeRFC(JCoDestination destination) {
JCoFunction function=null;
try
{
JCoFunctionTemplate functionTemplate = destination.getRepository().getFunctionTemplate("RFC_METHOD");
if (functionTemplate != null) {
function = functionTemplate.getFunction();
}
if (function == null)
throw new RuntimeException("Not found in SAP.");
//to fill elementary types and structures
configureImportParameters(function,"xxx", "abc");
//to fill table type parameters
configureTableParameters(function, "tblName",1,"100");
function.execute(destination);
} catch (JCoException e)
{
e.printStackTrace();
}
}
public void configureTableParameters(JCoFunction function, String table_name, int index, String id) {
JCoTable table = function.getTableParameterList().getTable("table_name");
table.appendRow();
table.setRow(index);
table.setValue("Partner", "100");
}
private void exportTable(JCoFunction jCoFunction, String tblName) {
JCoTable resultTable = jCoFunction.getTableParameterList().getTable(tblName);
int value = resultTable.getNumRows();
System.out.println(value);
}
private void configureImportParameters(JCoFunction function, String param1, String param2) {
JCoParameterList parameterList =
function.getImportParameterList();
parameterList.setValue("field1", param1);
parameterList.setValue("field2", param2);
}
UPDATED the code.
multiple problem can cause this.
if you setting "" or " " to fields. (when you set values better set if those has some values
if it says partner does not exist and if you sure its exist this mean your data does not pass properly. add debug points to where you set the data and make sure you pass correct name and correct values.
also you do not need to add(index) you can just table.appendRow(); // but this will not impact on your case
also when you setValue make sure its int filed. (normally not) in your given example its int
eg:
private void configureTableParameters(JCoParameterList tableParameters){
JCoTable jCoTable=tableParameters.getTable(key);
jCoTable.appendRow();
if(value!=null)
jCoTable.setValue(fieldKey,String.valueOf(value));
}
this is just psuda code and will not work
Test your ABAP remote function module with an SAP GUI via transaction code SE37 first.
If this test is successful and you get a different result if called from JCo with using the same parameter values, then I recommend to study SAP note 206068 for possible reasons.
Also check your method configureTableParameters. I guess, index shall be a field index and not a row count. Your implementation will create far too many unnecessary rows. I assume you wanted to call table.appendRow(); instead of table.appendRows(index);. Moreover, you maybe intended to fill the first field in the row with the value "100", for which you would have to pass the index value 0 instead of 1 in this case.

Database doesn't like reading values from a loop

I have a java database successfully connected to my java code. Thats all fine as it works and all.
When I store a result from the database into a variable ... it works perfectly.
Now as I have to do this 8 times I used a loop and a array however by using a try catch tool it gives out a error of, Error is: java.lang.NullPointerException
Futher investigation shows that it seems to not like the loop strangely.
public String Title []; //in class but out of any methods
public void gettinginfo ()
{
try
{
int AB = 0; //array base starts from 0
//ID in database starts from 1
for (int i = 1; i<=8; i++)
{
String query = "SELECT * FROM students WHERE ID = " + i;
Rs = St.executeQuery(query);
while (Rs.next())
{
Title[AB] = Rs.getString("StudentName");
AB++;
}
}
}
catch (Exception ex)
{
System.out.println("Error is: " + ex);
}
}
What line is your NullPointerException occurring on? Likely your Title array has not been initialized. If you know how many rows the query will return, you can say:
Title = new String[numRows];
But if you don't, you'll need to either run a SELECT count(*) ... query or use an ArrayList or other resizable list, instead of an array.
Your code is also very poorly structured, which is no small part of why you're having trouble debugging this. I've cleaned up your code below, with comments explaining my changes:
public class YourClass
{
private static final int MAX_ID = 8; // or however you want to set the size
private String[] title; // [] after the type is easier to read, lower case variables
private Connection conn; // I'm assuming the class will be provided a DB connection
// Note the Statement and ResultSet objects are not defined in the class, to
// minimize their scope.
public void queryInfo() // name suggests a query (potentially expensive) will be run
{
title = new String[MAX_ID]; // **initialize title**
// We use a try-with-resources block to ensure the statement is safely closed
// even better would be to use a PreparedStatement here
try(Statement st = conn.statement())
{
// You're executing 8 separate queries here, where one will do
String query = "SELECT * FROM students WHERE ID >= 1 AND ID <= "+MAX_ID;
// Again, we need to close the result set when we're done
try(ResultSet rs = st.executeQuery(query))
{
int i = 0;
while (rs.next())
{
title[i++] = rs.getString("StudentName");
}
} // close our ResultSet
} // close our Statement
}
// provide a separate getter method, rather than making the array public
public String[] getTitles()
{
return title;
}
}
There's still more that could be improved - using an array seems like a poor design, as does calling a method which populates a class variable rather than simply having queryInfo() return a new array. You can also look into using PreparedStatement. Hopefully these suggestions help.
Make sure that Title array and Statement St objects are and not null. These are the only two reasons that I suspect. Give FULL stacktrace if it doesn't work.
Title array is NULL. "new" this array to the size equal to number of rows. If you don't know the rows, fire a count(*) query first, find out the no of rows and then intantiate Title array or use ArrayList<String> instead of String array.
I am assuming that you have not initialized your Title array, you have to set it equal to something or it will just be null which will cause a nullPointerException, but as others have stated there is no way to be sure since your haven't given us a full stack trace or even the line number of the exception. In this case the exception should be handled as such:
try{
//your code here
}catch(Exception ex){
ex.printStackTrace();
}
This code will give you the full stack trace making it much easier to track down the issue.
Also you may want to consider using an ArrayList instead of an array:
List<String> Title = new ArrayList<String>();
Then to add to it:
Title.add(Rs.getString("StudentName"));
If you need it as an array later then:
String[] title = Title.toArray(new String[Title.size()]);
You can read more about ArrayLists here.

How to not return anything for a method with return type int

public static int logIn(Statement stmt){
int id;
String pw;
String select;
boolean match;
System.out.print("userID: ");
id = input.nextInt();
input.nextLine();
System.out.print("password: ");
pw = input.next();
input.nextLine();
select = "SELECT user_id, password FROM login WHERE user_id = " + id;
try{
ResultSet rs = stmt.executeQuery(select);
while(rs.next()){
if(id == rs.getInt(1) && pw.equals(rs.getString(2))){
match = true;
}
}
}
catch(SQLException logfail){
logfail.printStackTrace();
System.out.println("could not print password");
}
if(match == true)
return id;
else break;
}
In my program, the user will input their login info. Then they will be faced with a menu in which they select options 1-7. Options 1-7 are just various queries that will be run on their own data.
My login function is to verify that they are who they are, as to give them access to their own data. If the verification passes, I return the id number in which they entered so that I may pass it into the other functions (1-7).
In my if-else statement, I want it to return the id number if the passwords matched and to return null if it failed.
I know that int can't be null but my return type for this method is int so what can I do?
For the sake of timely completion of my assignment, I'm going to return a value of 0 if things don't match to indicate that the login failed. But, more important to me is becoming a good Java programmer so I want to know:
Is there a better way to do this? and
Since there is, what can I do and how?
Thanks!
The easiest change you can make is to return Integer and return null. Integer is an object, that's why you can do this.
Alternatively, you could throw an exception if it is an error to not be able to login. It probably isn't an exceptional case, so this may not be the best way.
Probably the best thing you could do is to not return an int/Integer. Instead, have a class that represents the thing to do next.
Returning zero, or a negative value like -1 is one possibility. You can also create a checked exception LoginException which is thrown in case of invalid login credentials. The pro of this approach is that you have a nice way to log fault login attempts within the LoginException.
Any time you declare a function with a primitive type it must return a value or throw an exception. You can use the wrapper types: Boolean,Integer,Long,etc to return null because these are "real" objects in Java.
If you've declared a method of an int type, it must return an int. Simply declare/define an invalid_return variable which will be returned in case no match is found, simple as that.
When a method has a return type of int, then you must return an int. To indicate that an error occurred, you can either return an value which is otherwise invalid or throw an Exception.
The best way to not return from a method is to throw an exception instead. Returning error values like null or zero leads to buggy code when people forget to check for them. An exception is unambiguous and can't be ignored.
Really to be sensible you should separate your return numbers from you query by placing the two in different methods.
To return null, you need to return a class such as an ADT(Abstract Data type) from a method.
However that may be over-complicated when you can simply flag 0 zero as null with a variable of class Integer that you reset to null before each use, so if it is zero returned you only need put in an if-else to test the "Integer" variable as null or contains resetting to a number returned as int from the method.

How to protect against SQL injection when the WHERE clause is built dynamically from search form?

I know that the only really correct way to protect SQL queries against SQL injection in Java is using PreparedStatements.
However, such a statement requires that the basic structure (selected attributes, joined tables, the structure of the WHERE condition) will not vary.
I have here a JSP application that contains a search form with about a dozen fields. But the user does not have to fill in all of them - just the one he needs. Thus my WHERE condition is different every time.
What should I do to still prevent SQL injection?
Escape the user-supplied values? Write a wrapper class that builds a PreparedStatement each time? Or something else?
The database is PostgreSQL 8.4, but I would prefer a general solution.
Thanks a lot in advance.
Have you seen the JDBC NamedParameterJDBCTemplate ?
The NamedParameterJdbcTemplate class
adds support for programming JDBC
statements using named parameters (as
opposed to programming JDBC statements
using only classic placeholder ('?')
arguments.
You can do stuff like:
String sql = "select count(0) from T_ACTOR where first_name = :first_name";
SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);
return namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
and build your query string dynamically, and then build your SqlParameterSource similarly.
I think that fundamentally, this question is the same as the other questions that I referred to in my comment above, but I do see why you disagree — you're changing what's in your where clause based on what the user supplied.
That still isn't the same as using user-supplied data in the SQL query, though, which you definitely want to use PreparedStatement for. It's actually very similar to the standard problem of needing to use an in statement with PreparedStatement (e.g., where fieldName in (?, ?, ?) but you don't know in advance how many ? you'll need). You just need to build the query dynamically, and add the parameters dynamically, based on information the user supplied (but not directly including that information in the query).
Here's an example of what I mean:
// You'd have just the one instance of this map somewhere:
Map<String,String> fieldNameToColumnName = new HashMap<String,String>();
// You'd actually load these from configuration somewhere rather than hard-coding them
fieldNameToColumnName.put("title", "TITLE");
fieldNameToColumnName.put("firstname", "FNAME");
fieldNameToColumnName.put("lastname", "LNAME");
// ...etc.
// Then in a class somewhere that's used by the JSP, have the code that
// processes requests from users:
public AppropriateResultBean[] doSearch(Map<String,String> parameters)
throws SQLException, IllegalArgumentException
{
StringBuilder sql;
String columnName;
List<String> paramValues;
AppropriateResultBean[] rv;
// Start the SQL statement; again you'd probably load the prefix SQL
// from configuration somewhere rather than hard-coding it here.
sql = new StringBuilder(2000);
sql.append("select appropriate,fields from mytable where ");
// Loop through the given parameters.
// This loop assumes you don't need to preserve some sort of order
// in the params, but is easily adjusted if you do.
paramValues = new ArrayList<String>(parameters.size());
for (Map.Entry<String,String> entry : parameters.entrySet())
{
// Only process fields that aren't blank.
if (entry.getValue().length() > 0)
{
// Get the DB column name that corresponds to this form
// field name.
columnName = fieldNameToColumnName.get(entry.getKey());
// ^-- You'll probably need to prefix this with something, it's not likely to be part of this instance
if (columnName == null)
{
// Somehow, the user got an unknown field into the request
// and that got past the code calling us (perhaps the code
// calling us just used `request.getParameterMap` directly).
// We don't allow unknown fields.
throw new IllegalArgumentException(/* ... */);
}
if (paramValues.size() > 0)
{
sql.append("and ");
}
sql.append(columnName);
sql.append(" = ? ");
paramValues.add(entry.getValue());
}
}
// I'll assume no parameters is an invalid case, but you can adjust the
// below if that's not correct.
if (paramValues.size() == 0)
{
// My read of the problem being solved suggests this is not an
// exceptional condition (users frequently forget to fill things
// in), and so I'd use a flag value (null) for this case. But you
// might go with an exception (you'd know best), either way.
rv = null;
}
else
{
// Do the DB work (below)
rv = this.buildBeansFor(sql.toString(), paramValues);
}
// Done
return rv;
}
private AppropriateResultBean[] buildBeansFor(
String sql,
List<String> paramValues
)
throws SQLException
{
PreparedStatement ps = null;
Connection con = null;
int index;
AppropriateResultBean[] rv;
assert sql != null && sql.length() > 0);
assert paramValues != null && paramValues.size() > 0;
try
{
// Get a connection
con = /* ...however you get connections, whether it's JNDI or some conn pool or ... */;
// Prepare the statement
ps = con.prepareStatement(sql);
// Fill in the values
index = 0;
for (String value : paramValues)
{
ps.setString(++index, value);
}
// Execute the query
rs = ps.executeQuery();
/* ...loop through results, creating AppropriateResultBean instances
* and filling in your array/list/whatever...
*/
rv = /* ...convert the result to what we'll return */;
// Close the DB resources (you probably have utility code for this)
rs.close();
rs = null;
ps.close();
ps = null;
con.close(); // ...assuming pool overrides `close` and expects it to mean "release back to pool", most good pools do
con = null;
// Done
return rv;
}
finally
{
/* If `rs`, `ps`, or `con` is !null, we're processing an exception.
* Clean up the DB resources *without* allowing any exception to be
* thrown, as we don't want to hide the original exception.
*/
}
}
Note how we use information the user supplied us (the fields they filled in), but we didn't ever put anything they actually supplied directly in the SQL we executed, we always ran it through PreparedStatement.
The best solution is to use a middle that does data validation and binding and acts as an intermediary between the JSP and the database.
There might be a list of column names, but it's finite and countable. Let the JSP worry about making the user's selection known to the middle tier; let the middle tier bind and validate before sending it on to the database.
Here is a useful technique for this particular case, where you have a number of clauses in your WHERE but you don't know in advance which ones you need to apply.
Will your user search by title?
select id, title, author from book where title = :title
Or by author?
select id, title, author from book where author = :author
Or both?
select id, title, author from book where title = :title and author = :author
Bad enough with only 2 fields. The number of combinations (and therefore of distinct PreparedStatements) goes up exponentially with the number of conditions. True, chances are you have enough room in your PreparedStatement pool for all those combinations, and to build the clauses programatically in Java, you just need one if branch per condition. Still, it's not that pretty.
You can fix this in a neat way by simply composing a SELECT that looks the same regardless of whether each individual condition is needed.
I hardly need mention that you use a PreparedStatement as suggested by the other answers, and a NamedParameterJdbcTemplate is nice if you're using Spring.
Here it is:
select id, title, author
from book
where coalesce(:title, title) = title
and coalesce(:author, author) = author
Then you supply NULL for each unused condition. coalesce() is a function that returns its first non-null argument. Thus if you pass NULL for :title, the first clause is where coalesce(NULL, title) = title which evaluates to where title = title which, being always true, has no effect on the results.
Depending on how the optimiser handles such queries, you may take a performance hit. But probably not in a modern database.
(Though similar, this problem is not the same as the IN (?, ?, ?) clause problem where you don't know the number of values in the list, since here you do have a fixed number of possible clauses and you just need to activate/disactivate them individually.)
I'm not confident if there is a quote() method, which was widely used in PHP's PDO. This would allow you a more flexible query building approach.
Also, one of the possible ideas could be creating special class, which would process filter criterias and would save into a stack all placeholders and their values.

Categories

Resources