Suppose I have a Kotlin (data) class with the primary constructor and a secondary one which fills vals/vars of the primary one with calling some methods (see the example). My question is whether the order in which these methods are being called is guaranteed, i.e. whether in my example checkConsitency would always get called before extractNames.
data class LawAndOrder(val sherifs: Int, val names: List<String>) {
constructor(westerners: List<Westerner>) :
this(sherifs = westerners.checkConsistency(),
names = westerners.extractNames())
}
data class Westerner(val name: String) {
val isCriminal: Boolean
get() = name == "Jesse James"
}
private fun List<Westerner>.checkConsistency(): Int {
println("Checking consistency")
if (isEmpty()) throw IllegalArgumentException("Crime and chaos")
if (any { it.isCriminal }) throw IllegalArgumentException("Inadmissible")
return size
}
private fun List<Westerner>.extractNames(): List<String> {
println("Extracting names")
return map { it.name }
}
fun main(args: Array<String>) {
val westerners = listOf(Westerner("John Wayne"), Westerner("Limonádový Joe"))
val lawAndOrder = LawAndOrder(westerners)
println(lawAndOrder)
}
The Kotlin Language Specification has this to say about it (emphasis mine):
16.39. Order of Evaluation
Generally, the order of evaluation is left to right, non-lazy (eager). Some expressions have special rules for order of evaluation of their constituent parts (some of them may be not evaluated at all). Order of evaluation of named arguments corresponds to their order at the invocation site, not the declaration site.
TODO
Related
I'm writing a client for a third-party REST API that returns JSON with a variety of alternative values instead of proper null or omitting the property entirely if null. Depending on the entity or even property in question, null could be represented by either null, "", "0" or 0.
It's easy enough to make a custom serializer, e.g. something like this works fine:
#Serializable
data class Task(
val id: String,
#Serializable(with = EmptyStringAsNullSerializer::class)
val parentID: String?
)
object EmptyStringAsNullSerializer : KSerializer<String?> {
private val delegate = String.serializer().nullable
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("EmptyStringAsNull", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: String?) {
when (value) {
null -> encoder.encodeString("")
else -> encoder.encodeString(value)
}
}
override fun deserialize(decoder: Decoder): String {
return delegate.deserialize(decoder) ?: ""
}
}
fun main() {
val json = """
{
"id": "37883993",
"parentID": ""
}
""".trimIndent()
val task = Json.decodeFromString(json)
println(task)
}
But annotating many properties like this is a bit ugly/noisy. And I'd also like to use inline/value classes for strong typing, like this:
#Serializable
data class Task(
val id: ID,
val parentID: ID?
/* .... */
) {
#JvmInline
#Serializable
value class ID(val value: String)
}
This means that in addition to annotating these properties I also need a custom serializer for each of them. I tried some generic/parameters-based solution that can work for all cases like this:
open class BoxedNullAsAlternativeValue<T, V>(
private val delegate: KSerializer<T>,
private val boxedNullValue: T,
private val unboxer: (T) -> V
) : KSerializer<T> {
private val unboxedNullValue by lazy { unboxer.invoke(boxedNullValue) }
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor(this::class.simpleName!!, PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: T) {
when (value) {
null -> delegate.serialize(encoder, boxedNullValue)
else -> delegate.serialize(encoder, value)
}
}
override fun deserialize(decoder: Decoder): T {
#Suppress("UNCHECKED_CAST")
return when (val boxedValue = delegate.deserialize(decoder)) {
boxedNullValue -> null as T
else -> boxedValue
}
}
}
But that doesn't work because #Serializable(with = ...) expects a static class reference as argument, so it can't have parameters or generics. Which means I'd still need a concrete object for each inline/value type:
#Serializable
data class Task(
val id: ID, // <-- missing serializer because custom serializer is of type ID? for parentID
val parentID: ID?
) {
#JvmInline
#Serializable(with = IDSerializer::class)
value class ID(val value: String)
}
internal object IDSerializer : BoxedNullAsAlternativeValue<Task.ID?, String>(
delegate = Task.ID.serializer().nullable, // <--- circular reference
boxedNullValue = Task.ID(""),
unboxer = { it.value }
)
That doesn't work because there is no longer a generic delegate like StringSerializer and using Task.ID.serializer() would mean the delegate would be the custom serializer itself, so a circular reference. It also fails to compile because one usage of the ID value class is nullable and the other not, so I would need nullable + non-nullable variants of the custom serializer and I would need to annotate each property individually again, which is noisy.
I tried writing a JsonTransformingSerializer but those need to be passed at the use site where encoding/decoding happens, which means I'd need to write one for the entire Task class, e.g. Json.decodeFromString(TaskJsonTransformingSerializer, json) and then also for all other entities of the api.
I found this feature request for handling empty strings as null, but it doesn't appear to be implemented and I need it for other values like 0 and "0" too.
Question
Using kotlinx.serialization and if necessary ktor 2, how to deserialize values like "", "0" and 0 as null for inline/values classes, considering that:
Properties of the same (value) type can be nullable and non-nullable in the same class, but I'd like to avoid having to annotate each property individually
I'd like a solution that is as generic as possible, i.e. not needing a concrete serializer for each value class
It needs to work both ways, i.e. deserializing and serializing
I read in the documentation that serializing is done in 2 distinct phases: breaking down a complex object to it's constituent primitives (serializing) --> writing the primitives as JSON or any other format (encoding). Or in reverse: decoding -> deserializing;
Ideally I'd let the compiler generate serializers for each value class, but annotate each of them with a reference to one of three value transformers (one each for "", "0" and 0) that sit in between the two phases, inspects the primitive value and replaces it when necessary.
I've been at this for quite some time, so any suggestions would be much appreciated.
How can I (de)serialize kotlin delegate properties with jackson.
I have a class like this
class MyClass {
var a: Int = 42
set(value) {
val changed = field != value
field = value
if (changed) notifyListeners()
}
... and a dozen other properties that all follow this pattern ...
}
I wanted to simplify that by using
class MyClass {
var a: Int by NotifyUiOnChange(42)
...
private inner class NotifyUiOnChange<T>(initialValue: T) : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
notifyUiListeners()
}
}
}
but then Jackson will ignore that property.
How can I tell Jackson to serialize and deserialize that property anyway?
And how do I then apply #JsonIgnore annotations (or something comparable)?
You must use outdated version on Jackson (or maybe a version for Java, not Kotlin?). I've checked this using "com.fasterxml.jackson.module:jackson-module-kotlin:2.10.+" (resolved to 2.10.1).
I've declared two classes:
class MyClass {
var a: Int = 42
set(value) {
val changed = field != value
field = value
if (changed) notifyListener(field)
}
private fun notifyListener(field: Any?) {
println("changed: $field")
}
}
class MyDelegatedClass {
var a: Int by NotifyUi(42)
private inner class NotifyUi<T>(initialValue: T) : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
notifyListener(newValue)
}
}
private fun notifyListener(field: Any?) {
println("changed: $field")
}
}
My main function:
fun main() {
val noDelegate = MyClass()
val delegated = MyDelegatedClass()
val mapper = ObjectMapper().registerKotlinModule()
// Deserialization
val noDelegateValue = mapper.writeValueAsString(noDelegate)
val delegatedValue = mapper.writeValueAsString(delegated)
println("No delegate:\t$noDelegateValue")
println("With delegate\t$delegatedValue")
// Serialization
val noDelegateObject = mapper.readValue<MyClass>("{\"a\":42}".trimIndent())
val delegateObject = mapper.readValue<MyDelegatedClass>("{\"a\":42}".trimIndent())
}
Output:
No delegate: {"a":42}
With delegate {"a":42}
changed: 42
We even can see output on delegate when we use delegate property :) (I believe it's a side-effect that should be consider as bug actually)
So, handling delegates is out of the box feature in jackson (I am not sure since when, but I used lazy delegate with jackson in older project I used to participate and there was no problems with delegates).
How to ignore delegated property?
So, you cannot apply JsonIgnore annotation to delegated field, because you will get This annotation is not applicable to target 'member property with delegate'. But, you can define the scope that annotation should be applied. Example below:
class MyDelegateClass {
#get:JsonIgnore // or set:
val a: Int by NotifyUi(42)
}
Unfortunately, seems that it's kind of broken, because you can use get: or set: and it's not apply to getter or setter only, but for both.
Let's say I have a data class like this:
data class MyData(val something: Int, val somethingElse : String) {
init {
require(something > 20) { "Something must be > 20" }
require(StringUtils.isNotEmtpy(somethingElse)) { "Something else cannot be blank" }
}
}
I'd like to be able to apply a function to somethingElse before the init method is called. In this case I want to remove all \n characters from the somethingElse String while maintaining immutability of the field (i.e. somethingElse must still be a val). I'd like to do something similar to this in Java:
public class MyData {
private final int something;
private final String somethingElse;
public MyDate(int something, String somethingElse) {
this.something = something;
this.somethingElse = StringUtils.replace(somethingElse, '\n', '');
Validate.isTrue(something > 20, "...");
Validate.isTrue(StringUtils.isNotEmtpy(this.somethingElse), "...");
}
// Getters
}
I could of course create a normal class (i.e. no data class) in Kotlin but I want MyData to be a data class.
What is the idiomatic way to do this in Kotlin?
While you can not literally do what you want, you can fake it.
Make all constructors of your data class private.
Implement factories/builders/whatevers on the companion as operator fun invoke.
Usages of Companion.invoke will -- in Kotlin! -- look just like constructor calls.
In your example:
data class MyData private constructor(
val something: Int,
val somethingElse : String
) {
init {
require(something > 20) { "Something must be > 20" }
require("" != somethingElse) { "Something else cannot be blank" }
}
companion object {
operator fun invoke(something: Int, somethingElse: String) : MyData =
MyData(something, somethingElse.replace("\n", " "))
}
}
fun main(args: Array<String>) {
val m = MyData(77, "something\nwicked\nthis\nway\ncomes")
println(m.somethingElse)
}
Prints:
something wicked this way comes
You'll note the helpful warning:
Private data class constructor is exposed via the generated 'copy' method.
This method can not be overridden (as far as I can tell) so you have to take care, still. One solution is to hide the actual data class away:
interface MyData {
val s: Int
val sE: String
private data class MyDataImpl(
override val s: Int,
override val sE: String
) : MyData {
init {
require(s > 20) { "Something must be > 20" }
require("" != sE) { "Something else cannot be blank" }
}
}
companion object {
operator fun invoke(s: Int, sE: String) : MyData =
MyDataI(s, sE.replace("\n", " "))
}
}
Now your invariant (no line breaks) is maintained, copy and other dangerous methods (if any, I haven't checked) are hidden away -- but therefore also unavailable, potentially removing some of the convenience data classes provide.
Choose your poison.
Is there a way to return several values in a function return statement (other than returning an object) like we can do in Go (or some other languages)?
For example, in Go we can do:
func vals() (int, int) {
return 3, 7
}
Can this be done in Dart? Something like this:
int, String foo() {
return 42, "foobar";
}
Dart doesn't support multiple return values.
You can return an array,
List foo() {
return [42, "foobar"];
}
or if you want the values be typed use a Tuple class like the package https://pub.dartlang.org/packages/tuple provides.
See also either for a way to return a value or an error.
I'd like to add that one of the main use-cases for multiple return values in Go is error handling which Dart handle's in its own way with Exceptions and failed promises.
Of course this leaves a few other use-cases, so let's see how code looks when using explicit tuples:
import 'package:tuple/tuple.dart';
Tuple2<int, String> demo() {
return new Tuple2(42, "life is good");
}
void main() {
final result = demo();
if (result.item1 > 20) {
print(result.item2);
}
}
Not quite as concise, but it's clean and expressive code. What I like most about it is that it doesn't need to change much once your quick experimental project really takes off and you start adding features and need to add more structure to keep on top of things.
class FormatResult {
bool changed;
String result;
FormatResult(this.changed, this.result);
}
FormatResult powerFormatter(String text) {
bool changed = false;
String result = text;
// secret implementation magic
// ...
return new FormatResult(changed, result);
}
void main() {
String draftCode = "print('Hello World.');";
final reformatted = powerFormatter(draftCode);
if (reformatted.changed) {
// some expensive operation involving servers in the cloud.
}
}
So, yes, it's not much of an improvement over Java, but it works, it is clear, and reasonably efficient for building UIs. And I really like how I can quickly hack things together (sometimes starting on DartPad in a break at work) and then add structure later when I know that the project will live on and grow.
Create a class:
import 'dart:core';
class Tuple<T1, T2> {
final T1 item1;
final T2 item2;
Tuple({
this.item1,
this.item2,
});
factory Tuple.fromJson(Map<String, dynamic> json) {
return Tuple(
item1: json['item1'],
item2: json['item2'],
);
}
}
Call it however you want!
Tuple<double, double>(i1, i2);
or
Tuple<double, double>.fromJson(jsonData);
You can create a class to return multiple values
Ej:
class NewClass {
final int number;
final String text;
NewClass(this.number, this.text);
}
Function that generates the values:
NewClass buildValues() {
return NewClass(42, 'foobar');
}
Print:
void printValues() {
print('${this.buildValues().number} ${this.buildValues().text}');
// 42 foobar
}
The proper way to return multiple values would be to store those values in a class, whether your own custom class or a Tuple. However, defining a separate class for every function is very inconvenient, and using Tuples can be error-prone since the members won't have meaningful names.
Another (admittedly gross and not very Dart-istic) approach is try to mimic the output-parameter approach typically used by C and C++. For example:
class OutputParameter<T> {
T value;
OutputParameter(this.value);
}
void foo(
OutputParameter<int> intOut,
OutputParameter<String>? optionalStringOut,
) {
intOut.value = 42;
optionalStringOut?.value = 'foobar';
}
void main() {
var theInt = OutputParameter(0);
var theString = OutputParameter('');
foo(theInt, theString);
print(theInt.value); // Prints: 42
print(theString.value); // Prints: foobar
}
It certainly can be a bit inconvenient for callers to have to use variable.value everywhere, but in some cases it might be worth the trade-off.
Dart is finalizing records, a fancier tuple essentially.
Should be in a stable release a month from the time of writing.
I'll try to update, it's already available with experiments flags.
you can use dartz package for Returning multiple data types
https://www.youtube.com/watch?v=8yMXUC4W1cc&t=110s
you can use Set<Object> for returning multiple values,
Set<object> foo() {
return {'my string',0}
}
print(foo().first) //prints 'my string'
print(foo().last) //prints 0
In this type of situation in Dart, an easy solution could return a list then accessing the returned list as per your requirement. You can access the specific value by the index or the whole list by a simple for loop.
List func() {
return [false, 30, "Ashraful"];
}
void main() {
final list = func();
// to access specific list item
var item = list[2];
// to check runtime type
print(item.runtimeType);
// to access the whole list
for(int i=0; i<list.length; i++) {
print(list[i]);
}
}
I have the following Scala enum:
object RunMode extends Enumeration {
val CLIENT_MODE = Value("CLIENT")
val SERVER_MODE = Value("SERVER")
}
I have some JSON that my app takes in as input for example:
{
"version" : "0.1",
"runMode" : "CLIENT"
}
Here the JSON field "runMode" is really my RunMode enum, and its values will always be either "CLIENT" or "SERVER". I am trying to use GSON to deserialize this JSON into an AppConfig instance:
class AppConfig(version : String, runMode : RunMode) {
def version() : String = { this.version }
def runMode() : RunMode.Value = { this.runMode }
}
I have the following GSON code:
val gson = new Gson()
val text = Source.fromFile(jsonConfigFile).mkString
gson.fromJson(text, classOf[AppConfig])
When this runs:
java.lang.RuntimeException: Unable to invoke no-args constructor for class scala.Enumeration$Value. Register an InstanceCreator with Gson for this type may fix this problem.
> Buildiat com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:226)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:210)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.Gson.fromJson(Gson.java:887)
<rest of stacktrace omitted for brevity>
So clearly, GSON expects RunMode to have a no-arg constructor, and it doesn't, and so its unable to deserialize my JSON file at runtime.
I've tried a million different combos but can't quite seem to find the magical constructor definition. So I ask: How can I add a no-arg constructor to RunMode so that GSON can deserialize it into an AppConfig instance?
This doesn't directly answer why using Gson fails, but offers an alternative. Here is an example using argonaut:
RunMode enum definition:
object RunMode extends Enumeration {
type RunMode = Value
val CLIENT_MODE = Value("CLIENT")
val SERVER_MODE = Value("SERVER")
implicit def runModeCodec: CodecJson[RunMode.RunMode] = CodecJson({
case CLIENT_MODE => "CLIENT".asJson
case SERVER_MODE => "SERVER".asJson
}, c => c.focus.string match {
case Some("CLIENT") => DecodeResult.ok(CLIENT_MODE)
case Some("SERVER") => DecodeResult.ok(SERVER_MODE)
case _ => DecodeResult.fail("Could not decode RunMode", c.history)
})
}
Definition of Foo (matching the object you want to create):
case class Foo(version: String, runMode: RunMode)
object Foo {
implicit def codec: CodecJson[Foo] =
casecodec2(Foo.apply, Foo.unapply)("version", "runMode")
}
And now the decoding/encoding example:
object ArgonautEnumCodec {
def main(args: Array[String]): Unit = {
val res: String = Foo("0.1", RunMode.CLIENT_MODE).asJson.toString
println(res)
val foo: Foo = res.decodeOption[Foo].get
println(foo)
}
}
Yields:
{"version":"0.1","runMode":"CLIENT"}
Foo(0.1,CLIENT)
Since I'm not a Scala guy, but have some Gson background, peeking some insights into how Scala works was fun to me. The reason of why you're getting the exception is that Gson cannot instantiate an abstract class scala.Enumeration.Value. The AutoConfig class content is pretty much like the following class in vanilla Java:
final class AppConfig {
final String version;
// This is where ig gets failed
final scala.Enumeration.Value runMode;
AppConfig(final String version, final scala.Enumeration.Value runMode) {
this.version = version;
this.runMode = runMode;
}
}
As far as I understand how Scala enumerations are implemented, unlike Java enumerations, they do not have their type per se, and every Scala enumeration value seem to be an instance of scala.Enumeration$Val giving not enough "host" enumeration type information from its type (however instances seem to have their outer class references). That's why custom implementing custom type adapter is not that simple and requires some inspection on the real enum type (not sure how it can be implemented, though).
Gson provides a special annotation #JsonAdapter that can annotate a certain field including a type adapter to be applied. So the AppConfig.runMode from the class above can be annotated like:
#JsonAdapter(RunModeEnumTypeAdapter.class)
final scala.Enumeration.Value runMode;
Note that it has some hint on the target type in its name. This is because there's probably no other way to specify the target enumeration type. Now, how a generic scala.Enumeration type adapter can be implemented.
// E - a special generic type bound to associate a Scala enumeration with
// So any Scala enumeration can be processed with this type adapter
abstract class AbstractScalaEnumTypeAdapter<E extends scala.Enumeration>
extends TypeAdapter<scala.Enumeration.Value> {
private final E enumeration;
protected AbstractScalaEnumTypeAdapter(final E enumeration) {
this.enumeration = enumeration;
}
#Override
#SuppressWarnings("resource")
public final void write(final JsonWriter out, final scala.Enumeration.Value value)
throws IOException {
// If the given value is null, null must be written to the writer (however it depends on a particular Gson instance configuration)
if ( value == null ) {
out.nullValue();
} else {
// Does Scala provide something like java.lang.Enumeration#name?
out.value(value.toString());
}
}
#Override
public final scala.Enumeration.Value read(final JsonReader in)
throws IOException {
final JsonToken token = in.peek();
switch ( token ) {
case NULL:
// Consume the `null` JSON token
in.nextNull();
return null;
case STRING:
// Consume a JSON string value and lookup an appropriate Scala enumeration value by its name
final String rawValue = in.nextString();
return enumeration.withName(rawValue);
// These case labels are matter of style and cover the rest of possible Gson JSON tokens, and are not really necessary
case BEGIN_ARRAY:
case END_ARRAY:
case BEGIN_OBJECT:
case END_OBJECT:
case NAME:
case NUMBER:
case BOOLEAN:
case END_DOCUMENT:
throw new MalformedJsonException("Unexpected token: " + token);
// Something else? Must never happen
default:
throw new AssertionError(token);
}
}
}
Now, RunMode can be bound to the type adapter above:
final class RunModeEnumTypeAdapter
extends AbstractScalaEnumTypeAdapter<RunMode$> {
// Gson can instantiate this itself
private RunModeEnumTypeAdapter() {
// This is how it looks like from the Java perspective
// And this is the "hint" I was talking about above
super(RunMode$.MODULE$);
}
}
Example of use:
final Gson gson = new Gson();
final AppConfig appConfig = gson.fromJson("{\"version\":\"0.1\",\"runMode\":\"CLIENT\"}", AppConfig.class);
System.out.println(appConfig.version);
System.out.println(appConfig.runMode);
System.out.println(gson.toJson(appConfig));
Output:
0.1
CLIENT
{"version":"0.1","runMode":"CLIENT"}
Probably not that nice and compact as Scala can do, but I hope the code above can be translated to Scala with no issues.