When we try to fetch data with Null values
field(TABLE_NAME.COLUMN_NAME.in(null))
with IN clause
getting null pointer exception.
Maybe because of this.
#Override
public final Condition in(Collection<?> values) {
Field<?>[] fields = new Field[values.size()];
Iterator<?> it = values.iterator();
for (int i = 0; it.hasNext(); i++)
fields[i] = Tools.field(it.next(), this);
return in(fields);
}
In the database, we can provide null in IN clause.
There is an existing "won't fix" issue in jooq https://github.com/jOOQ/jOOQ/issues/3867
There are some alternatives:
check null before IN(Cant do in my case its a really big select statement)
So if I want to make this possible is there any other workaround.
PS: On a similar note "eq" works perfectly fine:
#Override
public final Condition equal(Field<T> field) {
return compare(EQUALS, nullSafe(field, getDataType()));
}
Edit: 'field(TABLE_NAME.COLUMN_NAME.in(null))' here null is a collection.
Your example code doesn't compile:
TABLE_NAME.COLUMN_NAME.in(null)
There are 5 overloads of this in() method in jOOQ 3.14, and as such, you cannot pass the null literal to the in() method. Your real client code may be using a local variable like this:
Collection<?> collection = null;
TABLE_NAME.COLUMN_NAME.in(collection)
There might be a case for when this should behave the same as passing an empty collection, such as Collections.emptyList(), but this isn't what you seem to want. You probably want to pass actual null values inside of that collection, which you can do:
TABLE_NAME.COLUMN_NAME.in(1, null, 2)
But why would you do it? SQL implements three valued logic, meaning that NULL values have no effect in IN predicates, while they have an unintuitive, hardly desired effect in NOT IN predicates (the entire predicate becomes NULL)
Related
I have a section of code that used to utilize Optional<Department>, but due to some errors I worked out I am now converting it to List<Department>. Obviously this means I now have to change the return types and other method calls. Here are my questions:
I changed my returns to "new LinkedList<>()" (indicated in the code below) but is that correct?
There is a red error under ".isPresent" (indicated in the code below) with error message "The method isPresent() is undefined for the type List<Department>". What should I be changing that to?
Below is the updated code with comments indicating where errors are now occurring. Any help and explanations would be GREATLY appreciated!
public List<Department> delete(String department_ID) {
if ((department_ID == null) || (department_ID.isEmpty())) {
return new LinkedList<>(); //<<<<<<<<<<<<<<< used to be "return Optional.empty();"
}
List<Department> existing = get(department_ID);
if (existing.isPresent()) { //<<<<<<<<<<< red error under ".isPresent()"
String sql = "DELETE employee.*, department.* " + "FROM employee, department "
+ "WHERE employee.department_ID = :department_ID AND department.department_ID = :department_ID;";
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("department_ID", department_ID);
int rows = jdbcTemplate.update(sql, parameters);
if (rows > 0) {
return existing;
}
}
return new LinkedList<>(); //<<<<<<<<<<<<<<< used to be "return Optional.empty();"
}
I changed my returns to "new LinkedList<>()" (indicated in the code below) but is that correct?
I have googled the error message for my ".isPresent" error and cant find any explanations that fit
tl;dr
Change:
if (existing.isPresent()) { …
… to:
if ( ! list.isEmpty() ) { …
Details
You said:
red error under ".isPresent" (indicated in the code below) with error message "The method isPresent() is undefined for the type List".
The variable existing holds a reference to a List object. If you look at the Javadoc for List, you find no method named isPresent. So of course trying to call a non-existent method generates an error from the compiler.
That isPresent method was from the Optional class. The method checks to see if the optional holds a payload or if the optional is empty.
You seem to be switching to a style where you always expect a List, even if the list is empty (no elements).
If you want to be defensive, you can check that the list object exists.
if ( Objects.nonNull( existing ) ) { … }
But you can omit that null check if you are confident that such a condition cannot exist.
You may want to check if the list is empty, to avoid a needless call to your database. If so, change that code to:
if ( ! list.isEmpty() ) // Perform database work only if list has some elements.
You have other issues. Among them:
Generally the convention in Java is to avoid underscores in names. And generally best to avoid ALL-CAPS. So departmentId, not department_ID.
When returning lists, generally best to return an unmodifiable list. If the calling programmer needs a modifiable list, they can easily make from the returned unmodifiable list.
To get an unmodifiable list, use List.of rather than new LinkedList<>().
I cannot understand why your delete method would return a list. You may believe that you are reporting rows that got deleted, but technically you are not.
By the way, a tip: Text blocks can help with embedded SQL.
Instead of returning new LinkedList<>() you could return List.emptyList().
isPresent() is a method of Optional, but you assign the outcome of method get(department_ID) to an instance of List. You can check the List using
if(!(existing == null || existing.isEmpty())) {
I am refactoring the code to Java 8 and I want to replace null checks with Optional.
public Employee findEmployeeById(String id) {
List<Employee> empList = .. //some db query
return (empList.isEmpty() ? null : empList.get(0));
}
Optional.ofNullable(empList.get(0)) won't work as when it will throw IndexOutofBoundException
Or should I ideally replace null with Optional.empty()?
As #Jesper already mentioned in the comments, you have to check whether the list is empty and then return an empty Optional.
public Optional<Employee> findEmployeeById(String id) {
List<Employee> empList = .. //some db query
return empList.isEmpty() ? Optional.empty() : Optional.of(empList.get(0));
}
An Optional is a wrapper around a potentially null value that allows you to avoid explicitly checking for null when you use it.
Have a look at the Optional documentation to see what functionality it provides.
For example you can get an employee's name or "unknown" if it's absent, without checking for null:
Optional<Employee> emp = findEmployeeById(id);
String name = emp.map(Employee::getName).orElse("unknown");
You may read this post about Uses for Optional to see if it makes sense for you to use Optional.
To me the natural solution would be to keep your ? : construct as in Floern’s answer. If, however, you want to get rid of that, there is also an elegant solution without it:
public Optional<Employee> findEmployeeById(String id) {
List<Employee> empList = .. //some db query
return empList.stream().findFirst();
}
This gives you what you want because findFirst() returns an Optional. If you don’t care which element you get — or you know there’s never more than one — you may alternatively use findAny(), it too returns an Optional.
Why don't you simply replace your method with:
public Optional<Employee> findEmployeeById(String id) {
List<Employee> empList = .. //some db query
return (empList.isEmpty() ? Optional.empty() :
Optional.ofNullable(empList.get(0)));
}
I suggest you wrap the empList.get(0) in a Optional.ofNullable in case it might still be null.
As far as why that is better: think about the caller of the method. Whomever is now calling your method has to think what to actually do when the result is empty.
Besides you are now forced into writing code like:
Optional<Employee> emp = findEmployeeById("12");
if (emp.isPresent()) {
} else {
....
}
You can also chain this to become more fluent like:
emp.orElseThrow(RuntimeException::new)
Or other Optional methods.
That is simply not the case when you return an Employee. You are not even thinking (usually) to check if the reference is null.
That makes your code less error-prone and easier to understand.
Another possibility would be to do it as follows:
return Optional.of(empList).filter(list -> !list.isEmpty()).map(list -> list.get(0));
This will automatically return an empty Optional in case the list is empty or empList.get(0) returns null.
If empList can be null, consider using Optional.ofNullable(empList) instead of Optional(empList).
I'm looking for a solution to check that each items in a collection have the field expectedNullField null.
The following doesn't work:
assertThat(aCollection).extracting("expectedNullField").isNull();
Note that the following works as expected:
assertThat(aCollection).extracting("expectedNotNullField").isNotNull();
Anybody to help me ?
Thanks.
If you know the size (let's say it is 3) you can use
assertThat(aCollection).extracting("expectedNullField")
.containsOnly(null, null, null);
or if you are only interested in checking that there is a null value
assertThat(aCollection).extracting("expectedNullField")
.containsNull();
Note that you can't use:
assertThat(aCollection).extracting("expectedNullField")
.containsOnly(null);
because it is ambiguous (containsOnly specifying a varargs params).
I might consider adding containsOnlyNullElements() in AssertJ to overcome the compiler error above.
You can use a Condition
Condition<YourClass> nullField = new Condition<>("expecting field to be null") {
#Override
public boolean matches(YourClass value) {
return value.getField() == null;
}
};
assertThat(aCollection).have(nullField);
which might be easier to read than the other solution
assertThat(aCollection).filteredOn("expectedNullField", not(null)).isEmpty();
I want to know if HQL expressions are null-safe or not?
For example, consider this named query
SELECT a
FROM A a
where a.f=:f
in which f is a field of type String, Double, Date, etc.
Then I use it like:
session.getNamedQuery("myNamedQuery").setString("f", myFValue).uniqueResult();
If both a.f and myFValue are null I want the condition to be true and if just one of them is null I want it to be false.
If it is not null-safe, how can I handle that?
Regards
No, they aren't null-safe. They're translated directly to SQL, and obey the same rules. So if yo want to test for null, you must use is [not] null.
So if the f parameter can be null, you'll have to use two different HQL queries, or build it dynamically, or use a Criteria query to build a dynamic query.
They are not. Try these scenarios out to handle your specific case:
select a from A a where ((:f is null and a.f is null) or a.f = :f) and ...
If your parameter String is null then the query will check if the row's status is null as well. Otherwise it will resort to compare with the equals sign.
If you needed to skip the :status where_clause altogether; you can code like so:
select a from A a where (:f is null or a.f = :f) and ...
This second query is equivalent to:
if(status != null){
sql.append(" a.f = :f and ");
}
You should use is null or is not null.
See HQL "is null" And "!= null" on an Oracle column
They are not null safe.
HQL translates your HQL query to SQL and then it substitute your parameters.SO it won't rewrite query from param = ? to param is null.
Go for Criteria API and use Restrictions.isNull("f");
They are not null safe. Using criteria this would do the trick
public static void addNullSafeEqualsRestriction(Criteria criteria, String propertyName, Object object) {
if (object == null) {
criteria.add(Restrictions.isNull(propertyName));
} else {
criteria.add(Restrictions.eq(propertyName,object));
}
}
I need to bind at maximum 8 variables. Each one of them could be null.
Is there any recommended way to achieve this? I know that I could simply check for null, but this seems tedious.
Additional details:
I'm going to call this sql from java code. It may be written using JPA 2.0 Criteria API, but most likely it's going to be a native query. The database is Oracle 10g, so I think I could make use of PL/SQL as well.
Edit1:
Maybe the title is a bit misleading, so I'll try to elaborate.
The resulting SQL would be something like:
...
WHERE var1 = :var1
AND var2 = :var2
...
AND var = :var8
Now I need to bind parameters from java code in the way like:
nativeQuery.setParameter("var1", var1)
...
nativeQuery.setParameter("var8", var8)
Some parameters could be null, so there is no need to bind them. But I see no way I can omit them in SQL.
Edit2:
I'm expecting to see SQL or PL/SQL procedure in your answers (if it's ever possible without null checking).
In fact, all of these variables are of the same type. I think it's not possible to find a solution using ANSI SQL, but maybe there are some PL/SQL procedures which allow to work with varargs?
The use of a criteria query is appropriate in this case, because if I understood correctly, you need to construct the SQL query dynamically. If all the variables except var1 are null, the where clause would be
where var1 = :var1
and if all variables except var2 and var5 are non null you would have
where var2 = :var2 and var5 = :var5
Is that right?
If so, then do what you plan to do, and construct the query dynamically using a criteria query. Something like this must be done:
CriteriaBuilder builder = em.getCriteriaBuilder();
Predicate conjunction = builder.conjunction();
if (var1 != null) {
conjunction = builder.and(conjunction,
builder.equal(root.get(MyEntity_.var1),
var1));
}
if (var2 != null) {
conjunction = builder.and(conjunction,
builder.equal(root.get(MyEntity_.var2),
var2));
}
...
criteria.where(conjunction);
You don't specify the type of the objects you want to pass. So in this example I'm considering you will pass Object.
#Test(expected=IllegalArgumentException.class)
public void testMyMethod() {
List<Object> testList = new ArrayList<Object>();
testList.add("1");
testList.add("2");
testList.add(3);
myMethod(testList);
}
public void myMethod(List<Object> limitedList) {
final int MAX_SIZE = 2;
if (limitedList.size() > MAX_SIZE) {
throw new IllegalArgumentException("Size exceeded");
}
//my logic
}
In this example I'm passing the arguments as a List of Objects but you could use array (varargs) or another type of collection if you need to. If the client sends me more than the expected objects it will throw an IllegalArgumentException.
Also if you don't want to throw an exception you could just continue and iterate the list to bind the parameters but using the list size or MAX_SIZE as your limit. For example:
public void myMethod2(List<Object> limitedList) {
final int MAX_SIZE = 2;
int size = MAX_SIZE;
if (limitedList.size() < MAX_SIZE) {
size = limitedList.size();
}
//Iterate through the list
for (int i = 0; i < size; i++) {
Object obj = limitedList.get(i);
//Logic to bind the obj to the criteria.
}
}