-
Notifications
You must be signed in to change notification settings - Fork 185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Weird null behaviour #51
Comments
Since the API specification says
So I think the behavior you observe is correct. If you know that members can be the JSON literal |
It's a pity though to provide such a handy (clean) default function and then have to wrap it with an isNull? To which spec are you referring to? Json spec doesn't seem to mention java. I've added a pull request, just in case. |
I meant to refer to the API specification, but the issue you point out is even more subtle than that. The more obvious problem with replacing the JSON literal |
Would you agree this sound like implementing Undefined in java? |
Maybe you can convince Ralf to change the API specification slightly such that |
As it has been pointed out already, there is a difference between As for @sbandara's suggestion to let the getter functions with a default return that default also in case of null, this sounds reasonable to me at a first glance. However, what should happen in case of |
Yes that sounds reasonable (default to null when eg. getString('foo','n/a') is being called). As for the invalid entries I would deal with them the same way. The whole idea of having a default is to have a fallback in case something is wrong (type or value) |
Wouldn't it be unexpected when |
Not really as it's a default. If one would want a fallback you can put a wrapping try catch block around it without the default. |
Did you really get a
That's expected with the current contract, but a NFE would be a bug. |
I want to express my opinion about this. I know I don't need to update my dependencies, but this proposal is just wrong.
No. It is a default, not a fallback. If it is not present, give me the default, if I find an elephant when expecting a maple tree, please let me know. A default value is not supposed to be the if-anything-wrong-happens-give-me-this, if a system wrote a string to a value that should be an integer I want an exception. The current API has a simple and straightforward contract (never surprised me at least) and I don't want to change it without reason.
WHAT?! This snippet could be used in your scenario, which would be much better than changing a dependency that multiple projects rely on. private static long safeGetLong(JsonObject jsonObject, String name, long fallback) {
JsonValue value = jsonObject.get(name);
if (value != null) {
if (value.isNumber()) {
try {
return value.asLong();
} catch (NumberFormatException exception) {
// You will most certainly want to (at least) log this.
// Maybe throw an AssertionError.
// Or, even, get the string and pass it to the BigInteger constructor.
}
} else {
// Not a number, should also do something about it.
}
}
return fallback;
} |
While I agree that having a default is not necessarily the same as a fallback. It all comes down to what you're going to do with it. The code sample you gave above is a very simple example of what you could do if you want to handle every tiny little variation of the value given. In practice you'd want to avoid it since it'll make your code pretty much unreadable let alone maintainable (if you go away from the basic hello world). As a simple example suppose I'd given "123" as a value. It's not a number perse, but still I'd be able to parse it as a string and convert it into a number. Raising an error (aka flow by exception) can't be a good way of designing something as basic as a json lib. Maybe a simple fix as in adding asString in the "JsonNumber" object not blowing up with a UnsupportedOperationException would already be an improvement. K. |
You can call |
Prove your claim. That function could be placed in a top-level class and shared project-wide, maybe even system-wide.
You are implying that a JSON library is something simple and here we are discussing API contracts. There is this little thing called design by contract which is how most serious APIs are written. You are suggesting defensive programming, which is not OK for a library that is not doing something trivial in most scenarios. |
Thanks @mafagafogigante for your insights, the distinction between a default and a fallback really nails it. I've been pondering with this issue, and I see the point of providing convenient APIs. However, the suggested behavior of returning the default value also in case of an unexpected type doesn't seem right to me. It would require to swallow exceptions, which is dangerous, as it has the potential of shadowing issues in your code. For example, when you're not aware that certain values in the parsed JSON have a different type (e.g. an array of numbers instead of a number), the suggested API would silently fall back, and you wouldn't ever notice. |
Still there is a case that concerns me: String string = null;
jsonObject.set("foo", string); will accept OTOH, |
I beg to differ. Application code should check if foo is there by using From the Javadoc
JSON Just for the record, Google suggests here: Empty/Null Property ValuesConsider removing empty or null values. If a property is optional or has an empty or null value, consider dropping the property from the JSON, unless there's a strong semantic reason for its existence. |
It might be late to comment on this rather long conversation but I was having a problem working with JSON generated by other libraries because it would do something like the following: return value != null ? value.asString() : defaultValue; and making it this return value != null ? (value.isNull() ? null : value.asString()) : defaultValue; Basically two null checks. One for a null that should not happen and another one for one that could and does happen. |
I'm pretty late to the party, anyway FYI here is the above @Gyannea solution using Java 8 Optional class: return Optional.of(value) // Optional<JsonValue>
.map(JsonValue::asString) // Optional<String>
.orElse(defaultValue); // JsonString Or using Functional Java (available also for Java 7-, although you'd have to use anonymous classes since method references are not available): return Option.fromNull(value).map(JsonValue::asString).orSome(defaultValue); I also agree that:
Are very different cases. If in some contexts some of those cases are conflated, it may be totally fine but IMHO it's part of a specific protocol and should not be encouraged by being implemented in a generic JSON library. As @ralfstx said, TL;DR: the current contract of minimal-json IMHO is perfectly fine here. |
This is an existing and used library. Deployed code relies on it and on its interface. There might be legitimate reasons for changing parts of it, but "it is a minor inconvenience to me" is not one. Your argument for the change is
which makes no sense. You want a default value if it is null, so write your own wrapper around the library. This library already exists and works this way, it should not be changed because someone has some expectations of how it should work. Not having "x" and having it set to null are two different things and need not to be handled the same way. |
When parsing {"abc":null}
jsonObject.getLong("abc",0);
throws a NumberFormatException because the value is somehow converted to "null"
Unsure if we're supposed to use jsonObject.get().isNull() or if we could enhance the method below to do the null checking instead.
The text was updated successfully, but these errors were encountered: