Can I check in a criteriabuilder chain if value is empty? - java

I have a criteria builder chain of gets, but they can be null which means they will fail.
example:
predicates.add(cb.equal(house.get("adressInfo").get("streetname"),value)
If for example house.get(adressInfo) is empty I still want it returned with an empty list or just null values for everything is fine.
I only need to filter out for as an example houses with street name "A" but must also include all houses that have an empty adressInfo.
Now I get a null.streetname invalid access error because a house has an adressInfo of null

You could maybe work around this by introducing helper methods like this:
private String getStreet(House house) {
AddressInfo addressInfo = (AdressInfo) house.get("adressInfo");
return addressInfo == null ? null : addressInfo.get("streetname");
}
And then you can do:
predicates.add(cb.equal(getStreet(house), value)

Related

Perfoming null-checks while collecting with Collectors.groupingBy

I have the following piece of code which groups the given entries (activities, which is Iterable<activity>) based on IDs.
For the final result, I want it to return a Map of ID to Iterables of the entries grouped by that ID.
For example: Map<String, Iterables<activity>>.
Right now, it returns a Map<String, List<activity>>.
stream(activities)
.collect(
groupingBy(
activity -> {
if (activity.getID()) {
return activity.getID();
} else {
return activity.getName();
}
}));
I am unable to figure out a way to do this.
There's no such notion in Java as truthy values, which exists in languages like javascript. I.e. String can't be resolved into boolean automatically (what your code attempts to do).
There are multiple ways of how you can check whether the given value is null and provide an alternative value.
If name attribute is guaranteed to be non-null you can use static method requireNonNullElse() of the Objects utility class:
.collect(Collectors.groupingBy(act -> Objects.requireNonNullElse(act.getID(), act.getName()));
If name attribute is nullable, then you have to provide a default value that will be used in case if both id and name equal to null. Because null key is not allowed with Collectors.groupingBy() and will result in NullPointerException at runtime.
For the case when both field could be null I suggest extracting the logic for obtaining the key into a separate method.
public static String getKey(Action action) {
return action.getID() != null ? action.getID() :
action.getName() != null ? action.getName() : "defaultKey";
}
Which can be used inside the collector like that:
.collect(Collectors.groupingBy(act -> getKey(act)); // or as a method reference MyClass::getKey
Sidenote: by convention, names of classes in Java should start with a capital letter: Student, Employee, Activity.

Criteria Api: Use another parameter in multiselect, if the first one is null

I have a POJO class person which has two field. Lets assume only one of them holds a value and the other one is always null
public class Person {
private String music;
private String sports;
...
}
I want to fill either the one or the other into a List of DTOs via Criteria Api.
Here is a snippet of my (incomplete) Dao Code:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<PersonDTO> query = cb.createQuery(PersonDTO.class);
Root<Person> root= query.from(Person.class);
Path<String> musicPath = root.get(Person_.music);
Path<String> sportsPath= root.get(Person_.sports);
query.multiselect(/** TODO */);
List<PersonDTO> results = em.createQuery(query).getResultList();
Is there a way to use either music oder sports for the multiselect, depending on which of them is NOT null for the current record.
Or do i have to define a subquery to achieve this behavior?
You are looking for the COALESCE expression (see Ch. "Query Language", paragraph "Case Expressions" in the specification).
Create an expression that returns null if all its arguments evaluate to null, and the value of the first non-null argument otherwise.
The corresponding criteria API are the CriteriaBuilder.coalesce() set of methods. Selecting a single string is something as simple as:
query.select(cb.coalesce(musicPath, sportsPath));
If you want a PersonDTO of course, you will have to make use of the CriteriaBuilder.construct() method and an appropriate constructor:
query.select(cb.construct(PersonDTO.class, cb.coalesce(musicPath, sportsPath), ...));

Jackson include null set by user?

I am serializing a POJO using jackosn, and I want that all the values for which the user sets some value irrespective whether it's null or not must be included in the serialization.
So currently:
POJO:
public class YourItem {
public String key;
public String item;
}
Currently when user does:
YourItem item = new YourItem();
item.setKey("abc");
The serialization gives:
{
"key" : "abc"
}
as I configured ObjectMapper as objectMapper.setInclude(Include.NON_NULL)
However now if the user specifically calls the setter and sets the value as null, then I want that item in my serialized string.
So if user does
YourItem item = new YourItem();
item.setKey("abc");
item.setItem(null);
I want in serialzation both key and item values are present like:
{
"key" : "abc",
"item" : null
}
How do I differentiate between the user set null and the default null.
Is there a configuration in ObjectMapper ??
Some people consider using null to be bad practice (The book Clean Code, for instance)
Disregarding that, you cannot differentiate between the default initialization null and a user-set null by language-design
You need some sort of state that tracks if a field has been accessed by a setter. If it hasn't been accessed by a setter and is null, ignore it.
One way to do this is Jackson Filters, which allows you to define various conditions for serializing a field during runtime (your condition being that your setter-access-state indicates that the field was set by a user)
http://www.baeldung.com/jackson-serialize-field-custom-criteria

How to check if all non-primitive elements in object is null

Is there any shortcut for checking if an objects all elements(and also their elements) are null. For example I want to check If a country object(and its city and its street) is null or not? I don't want to check them one by one like;
country == null || country.city == null || country.city.street == null
public class Country{
City city;
....
}
public class City{
Street street;
....
}
public class Street{
....
}
There is no shortcut: you have to browse recursively your instances and check their fields. You could use a custom version of the browser shown in How to list all properties exposed by a Java class and its ancestors in Eclipse?. Anyway that approach would make sense if you are working with esoteric legacy code, whereas if you are writing new classes is better enforce all not-nulls in constructor of factory methods.

Handling null values in protobuffers

I am working on something which fetches data from database and constructs protobuff message. Given the possibility that null values can be fetched from the database for certain fields , I will get Null-pointer exception while trying to construct the protobuff message. Getting to know that null is not supported in protobuffs from the thread http://code.google.com/p/protobuf/issues/detail?id=57, I am wondering whether the only other way to handle NPE getting thrown is to insert manual checks into the java file corresponding to the proto like below!
message ProtoPerson{
optional string firstName = 1;
optional string lastName = 2;
optional string address1 = 3;
}
ProtoPerson.Builder builder = ProtoPerson.Builder.newBuilder();
if (p.getFirstName() != null) builder.setFirstName(p.getFirstName());
if (p.getLastName() != null) builder.setLastName(p.getLastName());
if (p.getAddress1() != null) builder.setAddress1(p.getAddress1());
...
So can someone please clarify whether there is any other possible efficient way to handle the null values during protobuff construction??
Disclaimer: Answer from a Googler using protobufs on a daily basis. I'm by no means representing Google in any way.
Name your proto Person instead of PersonProto or ProtoPerson. Compiled protobufs are just class definitions specified by the language you are using, with some improvements. Adding "Proto" is extra verbosity.
Use YourMessage.hasYourField() instead of YourMessage.getYourField() != null. Default value for protobuf string is an empty string, which does NOT equal to null. Whereas, no matter whether your field is unset or cleared or empty string, .hasYourField() always returns false. See default values for common protobuf field types.
You've probably known, but I wanna say explicitly: Don't programmatically set a protobuf field to null. Even for outside of protobuf, null causes all sorts of problems. Use .clearYourField() instead.
Person.Builder class does NOT have a .newBuilder() method. Person class does. Understand the Builder Pattern like this: You create a new builder only if you do not have it yet.
A rewrite of your protobuf:
message Person {
optional string first_name = 1;
optional string last_name = 2;
optional string address_1 = 3;
}
A rewrite of your logic:
Person thatPerson = Person.newBuilder()
.setFirstName("Aaa")
.setLastName("Bbb")
.setAddress1("Ccc")
.build();
Person.Builder thisPersonBuilder = Person.newBuilder()
if (thatPerson.hasFirstName()) {
thisPersonBuilder.setFirstName(thatPerson.getFirstName());
}
if (thatPerson.hasLastName()) {
thisPersonBuilder.setLastName(thatPerson.getLastName());
}
if (thatPerson.hasAddress1()) {
thisPersonBuilder.setAddress1(thatPerson.getAddress1());
}
Person thisPerson = thisPersonBuilder.build();
And if thatPerson is a person object that you created that has attribute values that could be an empty string, empty spaces or null, then I'd recommend using Guava's Strings library:
import static com.google.common.base.Strings.nullToEmpty;
Person.Builder thisPersonBuilder = Person.newBuilder()
if (!nullToEmpty(thatPerson.getFirstName()).trim().isEmpty()) {
thisPersonBuilder.setFirstName(thatPerson.getFirstName());
}
if (!nullToEmpty(thatPerson.hasLastName()).trim().isEmpty()) {
thisPersonBuilder.setLastName(thatPerson.getLastName());
}
if (!nullToEmpty(thatPerson.hasAddress1()).trim().isEmpty()) {
thisPersonBuilder.setAddress1(thatPerson.getAddress1());
}
Person thisPerson = thisPersonBuilder.build();
Proto 3
wrappers.proto supports nullable values:
string(StringValue),
int(Int32Value),
bool(BoolValue)
and etc
Example
syntax = "proto3";
import "google/protobuf/wrappers.proto";
message ProtoPerson {
google.protobuf.StringValue firstName = 1;
google.protobuf.StringValue lastName = 2;
google.protobuf.StringValue address1 = 3;
google.protobuf.Int32Value age = 4;
}
There's no easy solution to this. I'd recommend just dealing with the null checks. But if you really want to get rid of them, here are a couple ideas:
You could write a code generator plugin which adds setOrClearFoo() methods to each Java class. The Java code generator provides insertion points for this (see the end of that page).
You could use Java reflection to iterate over the get*() methods of p, call each one, check for null, and then call the set*() method of builder if non-null. This will have the added advantage that you won't have to update your copy code every time you add a new field, but it will be much slower than writing code that copies each field explicitly.

Categories

Resources