Related
In Java I'm trying to test for a null value, from a ResultSet, where the column is being cast to a primitive int type.
int iVal;
ResultSet rs = magicallyAppearingStmt.executeQuery(query);
if (rs.next()) {
if (rs.getObject("ID_PARENT") != null && !rs.wasNull()) {
iVal = rs.getInt("ID_PARENT");
}
}
From the code fragment above, is there a better way to do this, and I assume that the second wasNull() test is redundant?
Educate us, and Thanks
The default for ResultSet.getInt when the field value is NULL is to return 0, which is also the default value for your iVal declaration. In which case your test is completely redundant.
If you actually want to do something different if the field value is NULL, I suggest:
int iVal = 0;
ResultSet rs = magicallyAppearingStmt.executeQuery(query);
if (rs.next()) {
iVal = rs.getInt("ID_PARENT");
if (rs.wasNull()) {
// handle NULL field value
}
}
(Edited as #martin comments below; the OP code as written would not compile because iVal is not initialised)
Another solution:
public class DaoTools {
static public Integer getInteger(ResultSet rs, String strColName) throws SQLException {
int nValue = rs.getInt(strColName);
return rs.wasNull() ? null : nValue;
}
}
Just check if the field is null or not using ResultSet#getObject(). Substitute -1 with whatever null-case value you want.
int foo = resultSet.getObject("foo") != null ? resultSet.getInt("foo") : -1;
Or, if you can guarantee that you use the right DB column type so that ResultSet#getObject() really returns an Integer (and thus not Long, Short or Byte), then you can also just typecast it to an Integer.
Integer foo = (Integer) resultSet.getObject("foo");
I think, it is redundant. rs.getObject("ID_PARENT") should return an Integer object or null, if the column value actually was NULL. So it should even be possible to do something like:
if (rs.next()) {
Integer idParent = (Integer) rs.getObject("ID_PARENT");
if (idParent != null) {
iVal = idParent; // works for Java 1.5+
} else {
// handle this case
}
}
AFAIK you can simply use
iVal = rs.getInt("ID_PARENT");
if (rs.wasNull()) {
// do somthing interesting to handle this situation
}
even if it is NULL.
Just an update with Java Generics.
You could create an utility method to retrieve an optional value of any Java type from a given ResultSet, previously casted.
Unfortunately, getObject(columnName, Class) does not return null, but the default value for given Java type, so 2 calls are required
public <T> T getOptionalValue(final ResultSet rs, final String columnName, final Class<T> clazz) throws SQLException {
final T value = rs.getObject(columnName, clazz);
return rs.wasNull() ? null : value;
}
In this example, your code could look like below:
final Integer columnValue = getOptionalValue(rs, Integer.class);
if (columnValue == null) {
//null handling
} else {
//use int value of columnValue with autoboxing
}
Happy to get feedback
You can call this method using the resultSet and the column name having Number type. It will either return the Integer value, or null. There will be no zeros returned for empty value in the database
private Integer getIntWithNullCheck(ResultSet rset, String columnName) {
try {
Integer value = rset.getInt(columnName);
return rset.wasNull() ? null : value;
} catch (Exception e) {
return null;
}
}
For convenience, you can create a wrapper class around ResultSet that returns null values when ResultSet ordinarily would not.
public final class ResultSetWrapper {
private final ResultSet rs;
public ResultSetWrapper(ResultSet rs) {
this.rs = rs;
}
public ResultSet getResultSet() {
return rs;
}
public Boolean getBoolean(String label) throws SQLException {
final boolean b = rs.getBoolean(label);
if (rs.wasNull()) {
return null;
}
return b;
}
public Byte getByte(String label) throws SQLException {
final byte b = rs.getByte(label);
if (rs.wasNull()) {
return null;
}
return b;
}
// ...
}
Just in case someone comes here while programming in Kotlin (as I did), the answer suggested by BalusC works fine. Just be aware that Short and Float are instantiated as Integer and Double (respectively) inside ResultSet, and we should cast them to the correct type after calling getObject(). In my case the final code was:
when {
propKClass.isSubclassOf(Int::class) -> rs.getObject(colName) as Int?
propKClass.isSubclassOf(Short::class) -> (rs.getObject(colName) as Int?)?.toShort()
propKClass.isSubclassOf(Long::class) -> rs.getObject(colName) as Long?
propKClass.isSubclassOf(Boolean::class) -> rs.getObject(colName) as Boolean?
propKClass.isSubclassOf(Double::class) -> rs.getObject(colName) as Double?
propKClass.isSubclassOf(Float::class) -> (rs.getObject(colName) as Double?)?.toFloat()
else -> rs.getString(colName)
}
With java 8 you can do this:
Long nVal = Optional.ofNullable(resultSet.getBigDecimal("col_name"))
.map(BigDecimal::longValue).orElse(null));
In that case you ensure that the nVal will be null (and not zero) if the SQL value is NULL
If you want an alternative to calling ResultSet.wasNull() you can use getObject() and cast to the correct type.
Long val = (Long)rs.getObject(pos++);
You can also set null values in a Statement with setObject().
pstmt.setObject(pos++, null);
In Kotlin I would just solve it once and be done with the issue forever with this:
fun <K : Any> ResultSet.getNullable(columnLabel: String, type: KClass<K>): K? =
this.getObject(columnLabel, type.java)
So later you can just do this:
rs.getNullable("ID_PARENT", Int::class)
I guess if you want you could also do this too
fun <K> ResultSet.getNullable(columnLabel: String, type: Class<K>): K? =
this.getObject(columnLabel, type)
So you can just do this:
rs.getNullable("ID_PARENT", Int::class.java)
Or better still make both methods available if you happen to be dealing with developers that can't agree on even the simplest of things.
fun <K : Any> ResultSet.getNullable(columnLabel: String, type: KClass<K>): K? =
this.getNullable(columnLabel, type.java)
fun <K> ResultSet.getNullable(columnLabel: String, type: Class<K>): K? =
this.getObject(columnLabel, type)
Edit: if the library is still being fussy you can finally do something like:
rs.getNullable("ID_PARENT", String::class)?.let {FOO.valueOf(it) }
Another nice way of checking, if you have control the SQL, is to add a default value in the query itself for your int column. Then just check for that value.
e.g for an Oracle database, use NVL
SELECT NVL(ID_PARENT, -999) FROM TABLE_NAME;
then check
if (rs.getInt('ID_PARENT') != -999)
{
}
Of course this also is under the assumption that there is a value that wouldn't normally be found in the column.
I am parsing input JSON. For a field, there are 3 possibilities:
the field is absent;
the value is set to null;
the value is set to something valid.
Different behavior is implemented: for an absent value in the JSON, the default value is inserted into the database; for a null value in the JSON, a null value is inserted into the database.
I thought about Optional to model this:
public class Data {
private Optional<String> field;
}
Which of the following two options make most sense?
If field is null, the field was absent in the JSON. If field is Optional.empty, the field is null in the JSON.
If field is null, the field was null in the JSON. If field is Optional.empty, the field is absent in the JSON.
FWIW, I am using Jackson with module jackson-datatype-jdk8 to parse the input JSON.
I think you shouldn't use Optional for this scenario. As #dkatzel has mentioned in his answer, it's meant to be used as an API return value more than as a field.
Despite this academic discussion, you can accomplish what you want simply by initializing fields in your Data class to their default values:
public class Data {
private String field = DEFAULT_VALUE;
}
And then let Jackson do the rest.
EDIT as per OP's comment:
When your JSON comes with a null value for the field, Jackson will set it to null, and that's what will be stored in the database.
When your JSON does not contain the field, the DEFAULT_VALUE will be automatically loaded in your Data instance.
And when your JSON does actually contain a value for the field, Jackson will set it, and that value will reach the database.
EDIT 2, considering OP's requirement to find out if the field was either filled in, set to null or was absent in the input JSON, after parsing the JSON input:
If, after parsing the input JSON, you need to know whether the field was either filled in, set to null or was absent, then consider this example, which shows the approach I'd take:
public class Data {
private String field1 = "hello";
private Integer field2 = 10;
private Double field3 = 3.75;
private static final Data DEFAULTS = new Data(); // defaults will be kept here
public String getField1() {
return this.field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
public Integer getField2() {
return this.field2;
}
public void setField2(Integer field2) {
this.field2 = field2;
}
public Double getField3() {
return this.field3;
}
public void setField3(Double field3) {
this.field3 = field3;
}
#Override
public String toString() {
return "Data [field1=" + this.field1 +
", field2=" + this.field2 +
", field3=" + this.field3 + "]";
}
public boolean isDefault(Function<Data, Object> getter) {
Object defaultProperty = getter.apply(DEFAULTS);
Object actualProperty = getter.apply(this);
return defaultProperty != null // needed to support fields with no default value
&& defaultProperty.equals(actualProperty);
}
public boolean isNull(Function<Data, Object> getter) {
return getter.apply(this) == null;
}
public boolean isSet(Function<Data, Object> getter) {
return !this.isNull(getter) && !this.isDefault(getter);
}
}
Here I've used a private static attribute to hold your Data's default values and 3 methods to query any field state (default, null or set). In order to determine which field to query, these methods receive a Function<Data, Object>, which are given a Data instance and return an Object that is supposed to be the desired field. (If you stop to think it, getters can be seen as functions that take the instance as input and return a specific field of the instance).
So later, when you need to know how a certain field arrived in your JSON input, just use those 3 query methods to find out:
ObjectMapper m = new ObjectMapper();
String json = "{\"field1\":null,\"field2\":20}";
Data data = m.readValue(json, Data.class);
System.out.println(data); // Data [field1=null, field2=20, field3=3.75]
System.out.println("field1 default ? " + data.isDefault(Data::getField1)); // false
System.out.println("field1 null ? " + data.isNull(Data::getField1)); // true
System.out.println("field1 set ? " + data.isSet(Data::getField1)); // false
System.out.println("field2 default ? " + data.isDefault(Data::getField2)); // false
System.out.println("field2 null ? " + data.isNull(Data::getField2)); // false
System.out.println("field2 set ? " + data.isSet(Data::getField2)); // true
System.out.println("field3 default ? " + data.isDefault(Data::getField3)); // true
System.out.println("field3 null ? " + data.isNull(Data::getField3)); // false
System.out.println("field3 set ? " + data.isSet(Data::getField3)); // false
I would say that the first option makes the most semantic sense. It also potentially allows for easier computation.
Where a field in java is null, it is implied that a value is missing, which matches the first option.
I suggest that you store these fields in a hash-map where the key is the JSON field name and the value is the JSON field's value. I also suggest you don't use an optional here (as it can add an unnecessary layer of complexity), and instead use either a null or non-null object in the hashmap.
HashMap<String, Value> jsonFields = new HashMap<String, Value>();
boolean hasField1 = false;
Value field1Value = null;
if(jsonFields.contains("field1"){ // It is present in the JSON file
field1Value = jsonFields.get("field1"); // "null" here would mean that the JSON field was set to "null"
hasField1 = true;
}
The second choice makes more sense to me. null means null and empty means not present.
However, Optional shouldn't really be used as a field. It's supposed to be used as an API return value.
Could you instead store the data in a Map that allows null values? And if the key (your field) isn't present in the map, then return Optional.empty ?
Neither? I would annotate my POJO fields with #DefaultValue(). Then your possibilities are a null value or a non-null value specified in JSON, or the default if the field was omitted from JSON. And you can then just persist the POJO without any special per-field analysis.
If you are dealing with Object instead of String, here's a solution I find elegant:
use Optional.empty(); if there is no value
use Optional.of(value) if there is a value
use Optional.of(specialValue) if the value is null
where specialValue is a static singleton you can easily test, for instance: ObjectUtils.NULL (from commons.lang).
Then you can easily test your optional:
if (optional.isPresent()) {
if (ObjectUtils.NULL.equals(optional.get())) {
// value is there and null
} else {
// value is there and not null
}
} else {
// value is not there
}
I am currently working on a project that involves creating an array of objects(in this case, hardware tools from a created ToolItem class), and then creating a class file manipulate this data. The class I am creating now, named HardwareStore, has methods to search, insert and delete private data members for items in my array. Using a method named assign() from the previously mentioned ToolItem class, I call the set methods for each data member and assign them to a spot in the array. Assign looks like:
public void assign(int quality, String name, int id, int numInStock, double price)
{
setQuality(quality);
setToolName(name);
setID(id);
setNumberInStock(numInStock);
setPrice(price);
}
My insert method currently looks like:
public int insert(int quality, String name, int id, int numInStock, double price)
{
//testing the unique ID passed by the user,
//making sure there isn't an object in the
//array with the same ID
testArray = searchArray(id);
//array holds a max of 10 objects
if (numberOfItems == 10)
{
System.out.println("Array is full");
return 0;
}
//-1 is sentinel value from search method,
//telling me there isn't an object with the
//same specified ID
else if (testArray == -1)
{
for (index = 0; index < toolArray.length; index++)
{
if (toolArray[index].getToolID() == 0)
{
toolArray[index].assign(quality, name, id, numInStock, price);
numberOfItems++; //counter for array
return 1;
}
}//end for loop
}
return -1; //sentinel value telling me there was a dupe ID
}//end insert
I am supposed to validate the toolArray[index].assign(quality, name, id, numInStock, price); using a boolean variable in this manner, though:
boolean oK = toolArray[index].assign(quality, id, numInStock, price);
If oK == true, I then increment the number of items in the array. In order for this to work, I would need assign() to have a return type of boolean. This is how it was explained to me:
Yes you will want an Assign method. All that goes into it are calls to "set" values to there appointed places.
The assign method will return a value depending on whether or not the value was assigned/inserted. You will need to check the value of oK to make sure it is true or false.
My issue is, I do not know how to change the assign() return type to boolean and make the method work properly. My first thought was something like:
if (setQuality(quality) == true)
{
return true;
}
else if (setToolName(name) == true)
{
return true;
}
else
return false;
but this obviously doesn't work and results in several compiler errors :/ I just don't understand the logic behind this kind of data checking. If someone understands this and could help me, I would greatly appreciate it!
Well, considering that your assign method only contains setter methods that assign primitive values or Strings to inner fields, there isn't much that can go wrong with that so the simplest way to achieve what you want is just to return true at the end of assign():
public boolean assign(int quality, String name, int id, int numInStock, double price)
{
setQuality(quality);
setToolName(name);
setID(id);
setNumberInStock(numInStock);
setPrice(price);
return true;
}
Now if you have specific values that are illegal for your parameters, for example a negative integer for id, or null for the name, you can add a check inside each of your setter methods for the illegal values. If those values get passed you can throw an Exception such as IllegalArgumentException or you can make a custom exception even if you'd like. Here's how it would look for the setID() method:
void setID(int id) throws IllegalArgumentException {
if(id < 0) {
throw new IllegalArgumentException();
} else {
this.id = id;
}
}
Then, assuming all of your setters throw the same exception, you can add a try/catch block to the assign() method and return false if any the setter methods received the illegal values. Code would look like:
public boolean assign(int quality, String name, int id, int numInStock, double price)
{
try {
setQuality(quality);
setToolName(name);
setID(id);
setNumberInStock(numInStock);
setPrice(price);
} catch (IllegalArgumentException iae) {
return false;
}
return true;
}
If your methods need to throw different exceptions for some reason, then you can separate exception in the catch block like:
catch (ExceptionOne e1 | ExceptionTwo e2 ....) {
return false;
}
Using Exceptions is ok in this case since having one of these values be invalid is a systematic logic failure and should be noted. An illegal id or name corrupts your system logic and therefore should be handled with a proper exception. Also, this will probably never happen or happen very rarely so it would literally be an "exception" to the logic of your program.
However, if for example, you had a function that asks the user for the name of a tool they want and the user gives you an invalid tool name, you don't need to throw an exception there because that doesn't make your system have an error, that's just user not knowing how to use the system or just not knowing his tool names. In that case you can just return an error value like null or false.
Notice that I changed the return type... from void to boolean
public boolean assign(int quality, String name, int id, int numInStock, double price)
{
return
(setQuality(quality) &&
setToolName(name) &&
setID(id) &&
setNumberInStock(numInStock) &&
setPrice(price))
}
Then, notice that I changed the sentences with a condition. If I say return A && B it means that it will return true if both A and B are true, so, following that logic, you construct the entire return sentence and save yourself lots of Ifs..
Using exceptions as flow control structure is a bad practice and antipattern.
I have a method :
public void dbQuery(String query, String what) {
try {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
if(what.equals("temp_table")) {
String temporary_table = rs.getString("table_name_temp");
System.out.println(temporary_table);
return;
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
}
}
String query = "EXEC temptables.dbo.create_temp_cdr 'SIP'";
String temporary_table = db.dbQuery(query,"temp_table");
How do I get the return of a void to use it in another db.dbQuery() ?
PS : I need a value from dbQuery() so I can construct another query to call dbQuery() again
How do I get the return of a void to use it in another db.dbQuery() ?
What do you mean by "the return of a void"? If you mean "the return value" then there isn't one - that's the point of the method being declared as void.
If you want to return a value, then don't make it a void method... given this:
String temporary_table = db.dbQuery(query,"temp_table");
it looks like you just want to change dbQuery to return String. Note that you'll need to work out what to return if what isn't temp_table. (You should also fix your exception handling - just printing out the stack trace to stdout and then continuing regardless is almost never the right approach.)
You can either have your method not be void, and have a return type, then you can have the line
return temporary_table;
which would return the temporary_table variable.
Another way would be to pass by reference to the method. For example, you can pass a StringBuilder object to the method. Any changes to this object in the method will then also apply after the method has returned.
public void addToString(StringBuilder query, String toAdd) {
query.append(toAdd);
}
A call to this method of
StringBuilder query = new StringBuilder("start");
System.out.println(query.toString());
addToString(query, "end");
System.out.println(query.toString());
would have the output of:
start
startend
You can't return a value from a method that is defined as void - by definition this means it doesn't return any value.
If you see a return; statement in a void method, it basically means that this will end the current method and return processing back to the caller.
I'd make your method string instead of bool. Void won't return anything ever.
A void method is something that does not return anything.
But, your requirement seems like you have to use value generated in this method in the previous layer.
One obvious solution for this is to change it's return type from void to String.
But, if you don't want to do this , simply pass one more string parameter to your method. String is an object, so when you are passing it to a method, you are actually passing reference of that object to it. Simply set your generated value in this string and you will be able to access it in previous layer with that string variable(It's sort of similar to Pass by Reference in C).
I hope this workaround will solve your problem.
Please correct me if I am wrong.
In fact he wants to have something similar like functions in VB or so.
First, create your void as usual.
private Void getheightoflistview(ListView nameOfListView){
//do whatever you want to do
int numberOfItems = nameOfListView.getCount();
//You want to return the numberOfItems
}
So if you want to return an Integer value, just replace the Void with Integer
private Integer getheightoflistview(ListView nameOfListView){
//do whatever you want to do
int numberOfItems = nameOfListView.getCount();
//You want to return the numberOfItems
return numberOfItems; //this is the Integer you want to return
}
and add the return value
I'm relatively new to Java and am used to generics in C# so have struggled a bit with this code. Basically I want a generic method for getting a stored Android preference by key and this code, albeit ugly, works for a Boolean but not an Integer, when it blows up with a ClassCastException. Can anyone tell me why this is wrong and maybe help me improve the whole routine (using wildcards?)?
public static <T> T getPreference(Class<T> argType, String prefKey, T defaultValue,
SharedPreferences sharedPreferences) {
...
try {
if (argType == Boolean.class) {
Boolean def = (Boolean) defaultValue;
return argType.cast(sharedPreferences.getBoolean(prefKey, def));
} else if (argType == Integer.class) {
Integer def = (Integer) defaultValue;
return argType.cast(new Integer(sharedPreferences.getInt(prefKey, def)));
} else {
AppGlobal.logWarning("getPreference: Unknown type '%s' for preference '%s'. Returning default value.",
argType.getName(), prefKey);
return defaultValue;
}
} catch (ClassCastException e) {
AppGlobal.logError("Cast exception when reading pref %s. Using default value.", prefKey);
return defaultValue;
}
}
My calling code is:
mAccuracy = GlobalPreferences.getPreference(Integer.class, prefKey, mAccuracy, sharedPreferences);
Here is the Android code for getInt():
public int getInt(String key, int defValue) {
synchronized (this) {
Integer v = (Integer)mMap.get(key);
return v != null ? v : defValue;
}
}
I've tried various ways - using the native int, casting to an Integer, but nothing works.
May I suggest:
Integer i = new Integer(42);
It turns out the preference I'm trying to read is stored as a string so the cast exception is coming from inside the Android code not mine. Thanks for your help. But as I am a Java-newbie, if you think there is anything generally wrong with my routine, please teach me a better way.
Try defining a bunch of functions with the same name that take a different type for the default, and let the compiler figure it out. Java really ties your hands when working with types, especially primitive types.
public function int getPreference( String key , int missing ) { return sharedPreferences.getInt( key , missing ); }
public function boolean getPreference( String key , boolean missing ) { return sharedPreferences.getBoolean( key , missing ); }
public function String getPreference( String key , String missing ) { return sharedPreferences.getString( key , missing ); }
Edit:
If you are trying to get an object (not primitive) regardless of the type, you can use:
public function Object getPreference( String key , Object missing ) { return sharedpreferences.contains( key ) ? sharedPreferences.getAll().get( key ) : missing; }
If you are trying to get a specific type like int regardless of what is stored, you can use:
public function int getPreference( String key , int missing ) {
int result = missing;
Object value = sharedpreferences.contains( key ) ? sharedPreferences.getAll().get( key ) : null;
if ( value instanceof Integer ) result = ((Integer)value).intValue();
if ( value instanceof Boolean ) result = ((Boolean)value).booleanValue() ? 1 : 0;
// repeat for every other primitive wrapper type you care about
return result;
}
If you are trying to get a result only if it is a certain type, you can use something like:
public function Object getPreference( Class inRequire , String key , Object missing ) {
Object value = sharedpreferences.contains( key ) ? sharedPreferences.getAll().get( key ) : null;
if ( !( value instanceof inRequire ) ) {
value = null;
}
return ( value == null ) ? missing : value;
}