Google Protobuf handle null values - java

somebody explain me how can handle null values in google protobuf .
i have structure like this :
syntax = "proto3";
import "google/protobuf/wrappers.proto";
message Person {
google.protobuf.DoubleValue age = 4;
}
and java code :
DoubleValue myAge = null;
Person build = Person.newBuilder()
.setAge(myAge) // <- NPE
.build();
this code result null pointer exception on .setAge(myAge) line.
so what is use case of protobuf DoubleValue ? I thought it was used to manage null values . but still receive NullPointerException .
Do you use code like this for handle this problem ?
DoubleValue a = null;
Person.Builder builder = Person.newBuilder();
if (a != null) {
builder.setAge(a);
}
Person build = builder.build();
UPDATE:
this is part of code generated by protoc command :
/**
* <code>.google.protobuf.DoubleValue age = 9;</code>
*/
public Builder setAge(com.google.protobuf.DoubleValue value) {
if (ageBuilder_ == null) {
if (value == null) { //<-- Additional statement
throw new NullPointerException();
}
age_ = value;
onChanged();
} else {
ageBuilder_.setMessage(value);
}
Why set additional if statement in generated code ?
I think this is a bug for google protocol buffer.
finally i wrote this code:
DoubleValue.Builder builder = DoubleValue.newBuilder();
DoubleValue myAge = null;
Person build = Person.newBuilder()
.setAge(myAge != null ? myAge : builder )
.build();

DoubleValue is meant to handle missing values, not necessarily null. Protobuf libraries are intended to never involve nulls - for example, it never returns null, even for missing fields. Also, as you've found out, setters don't accept null. For example, to clear a field you'd use clearField instead of setField(null).
One of the big differences between proto2 and proto3 is that (initially) "hazzers" for primitive fields (e.g. hasField) were removed. That is, if you have a double my_field, there is no way to tell if it was never set, or set explicitly to zero. getMyField() would return 0 in both cases.
Note that messages still have hazzers, so if you want that functionality, you could wrap your primitive field in a message. Which is exactly what DoubleValue is. So if you have a field DoubleValue age = 1, you could use hasAge() to determine if it's set. In newer protobuf version, you could do the same with optional double age = 1.
Note that all of this has no relation with null in the Java generated code. There really is no way a setter would accept a null value.
TL;DR: Your first suggestion is good and very common:
DoubleValue a = null;
Person.Builder builder = Person.newBuilder();
if (a != null) {
builder.setAge(a);
}
Person build = builder.build();
If instead of null you have an Optional, you could use a similar variant:
OptionalDouble a = OptionalDouble.empty();
Person.Builder builder = Person.newBuilder();
a.ifPresent(value-> builder.getAgeBuilder().setValue(value));
Person build = builder.build();

Related

how to tell if the element.get() in a list in java is null or not?

I am trying to write a code to check a if condition for element.get() in arraylist if it is null or not
How can I access it without throwing an error
here is my code
if(EmployeeSalaryPaymentlist.get(j)!=null) {
EmployeeSalaryPaymentlist.get(j).getFromEmployeeBean().setFirst(fromEmployeeSalaryPaymentList.get(j).getFromEmployeeBean().getFirst());
EmployeeSalaryPaymentlist.get(j).getFromEmployeeBean().setLast(fromEmployeeSalaryPaymentList.get(j).getFromEmployeeBean().getLast());
EmployeeSalaryPaymentlist.get(j).getFromEmployeeBean().setEmployeeId(fromEmployeeSalaryPaymentList.get(j).getFromEmployeeBean().getEmployeeId());
}
I would rewrite the code like this to make it clearer and safer by adding a check on both objects.
final Employee employee = EmployeeSalaryPaymentlist.get(j);
final Employee employeeFrom = fromEmployeeSalaryPaymentlist.get(j);
if(employee != null && employeeFrom != null) {
final EmployeeBean to = employee.getFromEmployeeBean();
final EmployeeBean from = employeeFrom.getFromEmployeeBean()
to.setFirst(from.getFirst());
to.setLast(from.getLast());
to.setEmployeeId(from.getEmployeeId());
}
Of course if employee.getFromEmployeeBean might return null as well you need a similar if again.
One better way of doing this check (from Java 8 onwards) is to use Optional
Optional<Employee> optEmployee = Optional.ofNullable(employeeSalaryPaymentlist.get(j));
if( optEmployee.isPresent() )
{
Employee fromEmployee = optEmployee.get();
//rest of the code
}

What is the most elegant way of doing null checks in Java

Giving an example, lets say we have a code like the one below:
String phone = currentCustomer.getMainAddress().getContactInformation().getLandline()
As we know there is no elvis operator in Java and catching NPE like this:
String phone = null;
try {
phone = currentCustomer.getMainAddress().getContactInformation().getLandline()
} catch (NullPointerException npe) {}
Is not something anyone would advise. Using Java 8 Optional is one solution but the code is far from clear to read -> something along these lines:
String phone = Optional.ofNullable(currentCustomer).flatMap(Customer::getMainAddress)
.flatMap(Address::getContactInformation)
.map(ContactInfo::getLandline)
.orElse(null);
So, is there any other robust solution that does not sacrifice readability?
Edit: There were some good ideas already below, but let's assume the model is either auto generated (not convenient to alter each time) or inside a third party jar that would need to be rebuild from source to be modified.
The "heart" of the problem
This pattern currentCustomer.getMainAddress().getContactInformation().getLandline() is called TrainWreck and should be avoided. Had you done that - not only you'd have better encapsulation and less coupled code, as a "side-effect" you wouldn't have to deal with this problem you're currently facing.
How to do it?
Simple, the class of currentCustomer should expose a new method: getPhoneNumber() this way the user can call: currentCustomer.getPhoneNumber() without worrying about the implementation details (which are exposed by the train-wreck).
Does it completely solve my problem?
No. But now you can use Java 8 optional to tweak the last step. Unlike the example in the question, Optionals are used to return from a method when the returned value might be null, lets see how it can be implemented (inside class Customer):
Optional<String> getPhoneNumber() {
Optional<String> phone = Optional.empty();
try {
phone = Optional.of(mainAddress.getContactInformation().getLandline());
} catch (NullPointerException npe) {
// you might want to do something here:
// print to log, report error metric etc
}
return phone;
}
Per Nick's comment below, ideally, the method getLandline() would return an Optional<String>, this way we can skip the bad practice of swallowing up exceptions (and also raising them when we can avoid it), this would also make our code cleaner as well as more concise:
Optional<String> getPhoneNumber() {
Optional<String> phone = mainAddress.getContactInformation().getLandline();
return phone;
}
String s = null;
System.out.println(s == null);
or
String s = null;
if(s == null)System.out.println("Bad Input, please try again");
If your question was with the object being null, you should have made that clear in your question...
PhoneObject po = null;
if(po==null) System.out.println("This object is null");
If your problem is with checking whether all the parts of the line are null, then you should have also made that clear...
if(phone == null) return -1;
Customer c = phone.currentCustomer();
if(c == null)return -1;
MainAddress ma = c.getMainAddress();
if(ma == null) return -1;
ContactInfo ci = ma.getContactInformation();
if(ci == null)return -1;
LandLine ll = ci.getLandline();
if(ll == null)return -1;
else return ll.toNumber()//or whatever method
Honestly, code that's well written shouldn't have this many opportunities to return null.

Java MessagePack null check

I am trying to get familar with Messagepack for Java.
I get the data via Mqtt. If the variable is not null everything is fine but the variable can also be null and in this case I will get this Exception: Expected Int, but got Nil (c0)
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(m.getPayload());
int someInt = unpacker.unpackInt();
String someString = unpacker.unpackString();
So far I was not able to figure out how to get NULL back
I want to avoid to use TRY/CATCH so currently I am using this way
int someInt = unpacker.getNextFormat().equals("NIL") ? unpacker.unpackInt() : null;
Is there a better way ?
I looked the javadoc of MessageUnpacker and it doesn't seem provide a better way.
The example code is very close of your way :
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(...);
while(unpacker.hasNext()) {
MessageFormat f = unpacker.getNextFormat();
switch(f) {
case MessageFormat.POSFIXINT:
case MessageFormat.INT8:
case MessageFormat.UINT8: {
int v = unpacker.unpackInt();
break;
}
case MessageFormat.STRING: {
String v = unpacker.unpackString();
break;
}
// ...
}
}
So I think that you are in the good path.
But if you repeat this retrieval multiple times(and it is very likely), you could introduce utility methods that does the job for you.
For example for unpackInt() :
public Integer unpackIntOrNull (MessageUnpacker unpacker){
return unpacker.getNextFormat() == MessageFormat.INT8 ?
unpacker.unpackInt() : null;
}
And now, it is very straight to unpack elements :
Integer einInt = unpackIntOrNull(unpacker);
Integer einAndereInt = unpackIntOrNull(unpacker);
...
MessageUnpacker has a method named tryUnpackNil. If the next byte is a nil value, this method reads it and returns true, otherwise reads nothing and returns false.
This can be used to skip over nil values, and unpack non-nil values with e.g.:
final MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(data);
final Integer value = unpacker.tryUnpackNil() ? null : unpacker.unpackInt();

Java null checks on Javabean nested attributes

I'm working with BigDecimal calculations and read it's better to check for null than to surround with try catch. For example:
private BigDecimal computeSpringRateBoltWasher() {
if (boltWasher.getMaterial().getElastic_modulus() != null) {
BigDecimal term1 = boltWasher.getMaterial().getElastic_modulus().multiply(BigDecimal.TEN);
// other equations
return results;
}
return null;
}
But here I get a nullPointerException because the bolt washer's material is null. How do I cleanly check for null on the Material then on the Elastic Modulus?
Does it boil down to something like this? I'll have a few other attributes in this method that I'll need to check and it could get messy.
private BigDecimal computeSpringRateBoltWasher() {
if (boltWasher.getMaterial() != null) {
if (boltWasher.getMaterial().getElastic_modulus() != null) {
Simplify your code, (extract boltWasher.getMaterial() to a new variable, do your code more readable).
If you are writing an API or an application provide validations, Apache commons comes in handy. I would do this, see the comments in the code:
import org.apache.commons.lang3.Validate;
import java.math.BigDecimal;
/**
* Any
*/
public class Any {
private BigDecimal anything;
public void setAnything(BigDecimal anything){
this.anything = anything;
}
/**
* computeSpringRateBoltWasher. Explain what this method is intended to do.
*
* #return the result of the calculation
* #throws NullPointerException when anything is null, explain what other fields could cause an exception
*/
public BigDecimal computeSpringRateBoltWasher() {
Validate.notNull(this.anything, "Anything must not be null");
//Validate.notNull(somethingElse, "Something else must not be null");
BigDecimal term1 = this.anything.multiply(BigDecimal.TEN);
//Do more things with term1 and return a result
return term1;
}
public static void main(String[] args){
Any any = new Any();
any.setAnything(new BigDecimal(10));
BigDecimal result = any.computeSpringRateBoltWasher();
System.out.println(result);
any.setAnything(null);
result = any.computeSpringRateBoltWasher();
System.out.println(result);
}
}
This will produce the following ouput (you decide to catch the Runtime exception)
Exception in thread "main" java.lang.NullPointerException: Anything must not be null
at org.apache.commons.lang3.Validate.notNull(Validate.java:222)
at Any.computeSpringRateBoltWasher(Any.java:20)
at Any.main(Any.java:36)
If you're using java 7 or 8, you could check for nulls with Objects.requireNonNull() method:
private BigDecimal computeSpringRateBoltWasher() {
// Perform non-null validations
// These will throw NullPointerException in case the argument is null
Objects.requireNonNull(
boltWasher.getMaterial(),
"Material cannot be null");
Objects.requireNonNull(
boltWasher.getMaterial().getElastic_modulus(),
"Elastic modulus cannot be null");
BigDecimal term1 =
boltWasher.getMaterial().getElastic_modulus().multiply(BigDecimal.TEN);
// other equations
return results;
}
Depending on the contract of your operations, you shouldn't return null when an argument is null, because in this case you'd be hiding the error. If it's not valid for a material or an elastic modulus to be null, then throw NullPointerException by using Objects.requireNonNull().
On the other hand, if it's valid for a material or an elastic modulus to be null, then you should handle this case carefully. For this, you could use either multiple if statements, or some validation library.
With Java 8 Optional, the nested null check can be done in a more elegant and readable way:
Optional.ofNullable(boltWasher)
.map(bolt -> bolt.getMaterial())
.map(mat -> mat.getElastic_modulus)
.orElse(null)

NullPointerException, logical shortcut

Here is a simple code snippet and I cannot figure out why does it throw a NullPointerException.
String lastGroup = "";
menuTevekenysegekGrouped = new ArrayList<MenuElem>();
for(MenuElem me : menuA) {
// double checked that me objects are never null
// double checked that menuA is never null
if(me.getGroup() != null && !me.getGroup().equals(lastGroup)) { /* NPE!!! */
lastGroup = me.getGroup();
MenuElem separ = new MenuElem();
separ.setCaption(lastGroup);
separ.setGroupHead(true);
menuTevekenysegekGrouped.add(separ);
menuTevekenysegekGrouped.add(me);
} else {
menuTevekenysegekGrouped.add(me);
}
}
In the first iteration the me.getGroup() returns null. So the first operand of the && is false and second operand should not evaluate according to the JLS, as far as I know. However when I debug the code I get NPE from the marked line. I'd like to know why. (Using JRockit 1.6.0_05 if it matters..)
Are you sure that me itself is not, in fact, null?
From your code (without the stacktrace I have to guess), the following may be null and be the cause: menuA or me or menuTevekenysegekGrouped. And some of the values returned from the methods/or used in the methods may also be null, but it's hard to know...
If me is not null, then the only other object that can be null in the above snippet is menuTevekenysegekGrouped. Add a check before first using it to ensure that it's not null.
The repeated calls to me.getGroup() would bug me enough to pull them out into a local variable:
String lastGroup = "";
for(MenuElem me : menuA) {
String thisGroup = me.getGroup();
if(thisGroup != null && !thisGroup.equals(lastGroup)) {
lastGroup = thisGroup;
MenuElem separ = new MenuElem();
separ.setCaption(lastGroup);
separ.setGroupHead(true);
menuTevekenysegekGrouped.add(separ);
menuTevekenysegekGrouped.add(me);
} else {
menuTevekenysegekGrouped.add(me);
}
}
This is only going to fix your problem if in fact me.getGroup() returns different values (sometimes null) on multiple calls with the same me, but it might make it easier to debug, and certainly makes it easier to read.

Categories

Resources