Gson Type Adapter with both custom and default deserialization logic - kotlin

I have a gson model class which contains a variable named duration which is an integer. The problem is that when this variable has no value the server instead of returning me null it returns "".
This is also the case with lists, when I am expecting a List<String>? and there is no value in them I get "" instead of null. Unfortunately the server can not change.
I have fixed the problem with a custom double deserializer but I need something more generic because the "" is the default server approach. Here is my progress so far but on the else branch I do not know how to tell it to continue with the default deserializer.
internal class BadDeserializer : JsonDeserializer<Any> {
#Throws(JsonParseException::class)
override fun deserialize(
json: JsonElement,
type: Type,
context: JsonDeserializationContext): Any? {
return try {
val json = json.asString
if (json.isBlank()) {
null
} else {
//Do nothing and call default behavior (?)
}
} catch (e: Exception) {
throw JsonParseException(e)
}
}
}

That's an unfortunate response getting an empty string.
AFAIK you can't register a type adapter for primitive types with GSON, though perhaps its possible to register one for their boxed types (not sure how this may work with Kotlin).
If you can use the boxed types, then you could use something like the following:
public class DoubleAdapter implements JsonDeserializer<Double> {
#Override
public Double deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext ctx) throws JsonParseException {
if (!json.isJsonPrimitive()) {
throw new JsonParseException("primitive expected");
}
final JsonPrimitive primitive = json.getAsJsonPrimitive();
if (primitive.isString()) {
final String value = primitive.getAsString();
if ("".equals(value)) return null;
throw new JsonParseException("double expected, not string");
}
if (!primitive.isNumber()) {
throw new JsonParseException("double expected");
}
return primitive.getAsNumber().doubleValue();
}
}
Though it might be cleaner (and I usually do for everything) to write an adapter for whatever structure you have.

Related

Undetected throw declaration (Kotlin)

Let's have a function which just computes something in try-catch and returns the result:
private fun compute(): String {
return try {
// do some computation
// ...
"result"
} catch(t: Throwable) {
throw RuntimeException("Uups") // <-- GOAL: extract this to a dedicated method
}
}
I would like to extract the throw declaration to a separate function (which contains the my boilerplate code).
However, I'm unable to compile such setup in Kotlin.
A simplistic (and still uncompilable) version of the described problem:
private fun compute(): String {
return try {
// do some computation
// ...
"result"
} catch(t: Throwable) {
justThrow() // <-- NOT COMPILABLE, STRING EXPECTED
}
}
#Throws(RuntimeException::class)
private fun justThrow() {
// some boilerplate code
// ...
throw RuntimeException("Uups")
}
How write justThrow() method in Kotlin so that the whole code is compilable?
In Java this case would be detected by a compiler (I suppose).
Kotlin version: 1.4.21
You can declare the return type of your method as Nothing. This type can be used for any method that does not return normally. That might be because it will always throw an exception, or simply never returns at all, for instance because it contains an infinite loop.
private fun justThrow(): Nothing {
// some boilerplate code
// ...
throw RuntimeException("Uups")
}

Kotlin 1.3.11 has broken null-safety?

fun handle() : String {
null?.let { return "Ololo"}
}
val result = handle()
result.trim() // kotlin.TypeCastException: null cannot be cast to non-null type kotlin.CharSequence
Any ideas why null-safe Kotlin function return null?
It's a bug caused by introducing contracts for the standard functions let, run, apply, also in Kotlin 1.3.
The fix is targeted to the version 1.3.20. See KT-28061 for details.
It looks like the Kotlin compiler is adding in a null return in case let doesn't execute. This is probably a bug, since it shouldn't compile, and doesn't in previous versions of Kotlin.
If we just compile your example, we get this:
#NotNull
public final String handle() {
return null;
}
I think that's just a compiler optimization, since null?.let() will never execute.
Using an actual variable yields:
#NotNull
public final String handle() {
return someNullableVariable != null ? "Ololo" : null;
}
In other words, let() doesn't execute if its reference is null. However, since this function needs to return something, the compiler just tells it to return null, since there's nothing else it could return.
Since the function is marked #NotNull, Kotlin will perform a null-check on anything referencing the function:
fun someOtherMethod() {
handle().trim()
}
Becomes
public final void someOtherMethod() {
String handle = handle();
if (handle != null) {
StringsKt__StringsKt.trim(handle).toString();
return;
}
throw new Exception("null cannot be cast to non-null type kotlin.CharSequence");
}
There are two ways to handle this. You could change the return type on handle() to String?:
fun handle(): String? {
someNullableVariable?.let { return "Ololo" }
}
Or you could return something else in case the variable is null:
fun handle(): String {
someNullableVariable?.let { return "Ololo" }
return "someNullableVariable was null"
}
It has to be a bug, because:
a return statement (or better: expression) is missing, since the lambda passed to let won't be invoked
a function with String as return type should never return null.
Interestingly, in Kotlin 1.2.x this does not even compile:
fun handle() : String {
null?.let { return "Ololo"}
}
Error:(6, 0) A 'return' expression required in a function with a block body ('{...}')
In Kotlin 1.3.11 it does.
In any case:
let won't be invoked, because the safe-call operator ? evaluates to null (in this case).

Infinite recursion in Getter in Kotlin

I am familiar with Java, but I am having difficulty working with Kotlin.
To illustrate my question, here is some Java Code. If the getter finds the field to be NULL, it initializes the field, before returning the field.
package test;
public class InitFieldJava {
private final static String SECRET = "secret";
private String mySecret;
public String getMySecret() {
if(mySecret == null) initMySecret();
return mySecret;
}
private void initMySecret() {
System.out.println("Initializing Secret ....");
mySecret = SECRET;
}
public static void main(String[] args) {
InitFieldJava field = new InitFieldJava();
System.out.println(field.getMySecret());
}
}
Can I do something like the above in Kotlin. My attempt in Kotlin looks like this:
package test
class InitFieldKotlin {
private val SECRET = "secret"
private var mySecret: String? = null
get() {
if (mySecret == null) initMySecret() //Infinite Recursion!!!
return mySecret
}
private fun initMySecret() {
println("Initializing Secret ....")
mySecret = SECRET
}
companion object {
#JvmStatic
fun main(args: Array<String>) {
val field = InitFieldKotlin()
println(field.mySecret)
}
}
}
My problem is that this results in infinite recursion:
Exception in thread "main" java.lang.StackOverflowError
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
I’d appreciate knowing what I’m doing wrong.
Try to use field keyword inside get():
private var mySecret: String? = null
get() {
if (field == null) initMySecret()
return field
}
Generally speaking, field allows to access your value directly without calling get, almost in the same way as in your Java example. More information can be found in documentation.
The problem you're facing is that when you call your property this way, the getter will be called again. And when you call getter, another getter is called, and so on until an StackOverflow.
You can fix this as shown by #Google, and using field inside the getter, instead of the property name:
if (field == null)initMySecret()
This way you won't access the property using its getter.
But more importantly: why don't you use a lazy initialization? If the variable is final, and it seems to be, you could use a lazy val
This way, the field won't be nullable anymore, so you won't have to safe-call it. And you'll not use boilerplate code, Kotlin can do this lazy initialization for you!
val mySecret: String by lazy {
println("Initializing Secret. This print will be executed only once!")
"SECRETE" //This value will be returned on further calls
}
More examples on Lazy can be seen at Kotlin Docs

Required <Object> and found <Object>?

class TaskRepo(taskData: TaskData) {
companion object {
private val repoByTask: LRUMap<String, OrderFormRepo> = LRUMap(2, 10);
fun getInstance(taskData: TaskData): OrderFormRepo {
if (notFoundObject(taskData.taskId)) {
repoByTask[taskData.taskId] = OrderFormRepo(taskData);
}
return repoByTask[taskData.taskId];//PROBLEM HERE
}
private fun notFoundObject(taskId: String): Boolean {
if (repoByTask.containsKey(taskId) && repoByTask[taskId] != null) {
return false
}
return true
}
}
}
in getInstance method of companion object I am getting compile time error:
Required TaskRepo and found TaskRepo?
LRUMap implements the Map interface, the get method of which in Kotlin returns a V?, as it returns null when no element is present for the given key.
As you've already done the checking beforehand in this case, you can be reasonably sure (assuming no other threads are modifying the map at the same time) that this value won't be null, and force a conversion to the non-nullable type with the !! operator:
return repoByTask[taskData.taskId]!!
For other ways to handle a missing key when reading from a Map, see the getOrDefault and getOrElse methods.

Passing parameters to a custom getter in kotlin

I have been reading about properties in Kotlin, including custom getters and setters.
However, I was wondering if it is possible to create a custom getter with extra parameters.
For example, consider the following method in Java:
public String getDisplayedValue(Context context) {
if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
Note that the static method in PrefUtils has to have Context as a parameter, so removing this is not an option.
I would like to write it like this in Kotlin:
val displayedValue: String
get(context: Context) {
return if (PrefUtils.useImperialUnits(context)) {
// stuff
} else {
// other stuff
}
}
But my IDE highlights all of this in red.
I am aware I can create a function in my class to get the displayed value, but this would mean I would have to use .getDisplayedValue(Context) in Kotlin as well instead of being able to refer to the property by name as in .displayedValue.
Is there a way to create a custom getter like this?
EDIT: If not, would it be best to write a function for this, or to pass Context into the parameters of the class constructor?
As far as I know, property getter cannot have parameter. Write a function instead.
You can do this by having a property that returns an intermediate object that has a get and/or set operator with the parameters that you want, rather than returning the value directly.
Having that intermediate object be an inner class instance may be useful for providing easy access to the parent object. However, in an interface you can't use inner classes so in that case you might need to provide an explicit constructor parameter referencing the parent object when constructing your intermediate object.
For instance:
class MyClass {
inner class Foo {
operator fun get(context: Context): String {
return if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
}
val displayedValue = Foo()
}
...
val context : Context = whatever
val mc : MyClass = whatever
val y: String = mc.displayedValue[context]
You can do for example:
val displayedValue: String by lazy {
val newString = context.getString(R.string.someString)
newString
}