Kotlin has this noarg plugin to generate a synthetic noarg constructor for classes without one to help JPA (and frameworks like mybatis, hibernate) to instantiate a new object. Ex:
data class User(val id: Int, val name: String)
Given these properties are declared as val, i.e. immutable, how do these frameworks go about creating a fully baked object with all the values set. The kotlin-noarg plugin is just helping in instantiating a new instance, but the properties (id and name) are still immutable and hence shouldn't be allowed to change once the object is created.
To be clear, things work perfectly fine after adding the noarg plugin. The question is how, given that the properties are immutable.
This SO question too talks about this solution, but not the how part.
Related
val list = listOf(1, 2, 3)
fun main() {
if (list is MutableList) {
list.add(4)
}
}
The above code throws the below runtime exception.
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add (:-1)
at java.util.AbstractList.add (:-1)
at FileKt.main (File.kt:5)
After reading Kotlin's collection documentation I understand that the kotlin differentiate mutable and immutable collection via interfaces and the immutable interface doesn't have any mutable methods like add() but I wonder what would be the underlying implementation for both List and MutableList on JVM platform? In this case, it looks like the underlying concrete class has the add() method but it throws an exception.
Question:
As I don't have much experience in Java it's quite hard for me to find the concrete implementation of the List and MutableList interface in JVM. It would be great if someone point me to the code or way to track what's the actual java collection under these interfaces. Are both these interfaces get implemented by the same java collections or different ones?
Note:
I'm doing this for my learning and I know it's really bad code and I should use.toMutableList() extension function instead of the smart cast.
As you say, Java doesn't distinguish mutable from immutable lists. (Or at least, not in the type system.) So both the kotlin.List and kotlin.MutableList types are mapped to the java.util.List interface.
The unfortunate consequence of this is that the check:
if (list is MutableList)
…doesn't do what it looks like. It's really just checking whether the object is a java.util.List, and so both mutable and immutable lists will pass the test.
That's why your code is going on to throw an UnsupportedOperationException (which is the Java way to distinguish immutable lists, and indeed any other optional features).
I don't know of any way to reliably distinguish mutable from immutable lists, short of trying to modify them and seeing whether they throw that exception…
It's also worth being aware that listOf() doesn't promise to return any specific implementation. All you can tell is that it'll return something implementing kotlin.List, but it may be mutable or immutable. (In practice, I think it varies depending whether you pass zero, one, or more items. But the exact implementation may well change in future releases of Kotlin, so you shouldn't make any assumptions.)
Similarly, mutableListOf() returns some implementation of kotlin.MutableList, but makes no promises which one.
In practice, if you need a mutable list, then you should create one explicitly (either by creating a specific class such as ArrayList, or better still, calling mutableListOf() and letting it pick the most suitable type). Or if you don't have control over the list creation, then — as you say — you can call toMutableList() (though that may create an unnecessary copy).
Lists can almost always be cast to MutableLists (unless you wrote your own class that implements Kotlin List and not MutableList) because most (maybe all?) of Kotlin’s functions that generate lists use Java Lists under the hood, and Java Lists are always equivalent to Kotlin MutableList. Java’s way of making a List immutable is to throw an exception at runtime when you try to mutate it, which is why you’re getting a crash.
Basically, you should never cast to a MutableList because it is inherently unsafe. It is a common design pattern for classes to expose read-only views of MutableLists as Lists to protect them from being mutated externally. This is how Kotlin protects you from crashes when working with Lists that must not be mutated. If you subvert this design pattern by casting, sometimes it will succeed at runtime because the underlying list was not a Java immutable list implementation, and then you will trigger bugs that are very difficult to track down.
If you want to explore source code, in IntelliJ IDEA or Android Studio, you can Ctrl+click the function to see it’s source code. So in this case you could have done that with listOf and clicked in through until you got to the List implementation being generated in Java.
Data classes print out just fine in MPP projects. When I toString() the KClass object for my class, I get:
class com.example.MySimpleClass (Kotlin reflection is not available)
How Can I do what data class does and have a nice clean name without reflection?
I don't have it set up myself to test, so answer is based purely on documentation:
KClass.simpleName is available in Common code; qualifiedName isn't, but since 1.3 it is on every platform, so you could define an expect fun in your multiplatform part and make all actual implementations access qualifiedName.
I`m new at kotlin and want to build a multiplatform application.
For the common part I want to use data classes that contains platform specific functions.
Is it possible to use the kotlin data class in a platform specific declaration?
something like
expect data class Foo(val bar: String)
best regards
From Kotlin's docs on Platform Specific Declarations:
Expected declarations never contain any implementation code.
Since data classes generate implementations they can't be used in expect declarations. The actual implementation can be a data class since it does not change the semantics of the declared class.
expect class Some {}
actual data class Some(val test: UUID)
I'm trying to solve the problem of serializing and deserializing Box<SomeTrait>. I know that in the case of a closed type hierarchy, the recommended way is to use an enum and there are no issues with their serialization, but in my case using enums is an inappropriate solution.
At first I tried to use Serde as it is the de-facto Rust serialization mechanism. Serde is capable of serializing Box<X> but not in the case when X is a trait. The Serialize trait can’t be implemented for trait objects because it has generic methods. This particular issue can be solved by using erased-serde so serialization of Box<SomeTrait> can work.
The main problem is deserialization. To deserialize polymorphic type you need to have some type marker in serialized data. This marker should be deserialized first and after that used to dynamically get the function that will return Box<SomeTrait>.
std::any::TypeId could be used as a marker type, but the main problem is how to dynamically get the deserialization function. I do not consider the option of registering a function for each polymorphic type that should be called manually during application initialization.
I know two possible ways to do it:
Languages that have runtime reflection like C# can use it to get
deserialization method.
In C++, the cereal library uses magic of static objects to register deserializer in a static map at the library initialization time.
But neither of these options is available in Rust. How can deserialization of polymorphic objects be added in Rust if at all?
This has been implemented by dtolnay.
The concept is quite clever ans is explained in the README:
How does it work?
We use the inventory crate to produce a registry of impls of your trait, which is built on the ctor crate to hook up initialization functions that insert into the registry. The first Box<dyn Trait> deserialization will perform the work of iterating the registry and building a map of tags to deserialization functions. Subsequent deserializations find the right deserialization function in that map. The erased-serde crate is also involved, to do this all in a way that does not break object safety.
To summarize, every implementation of the trait declared as [de]serializable is registered at compile-time, and this is resolved at runtime in case of [de]serialization of a trait object.
All your libraries could provide a registration routine, guarded by std::sync::Once, that register some identifier into a common static mut, but obviously your program must call them all.
I've no idea if TypeId yields consistent values across recompiles with different dependencies.
A library to do this should be possible. To create such a library, we would create a bidirectional mapping from TypeId to type name before using the library, and then use that for serialization/deserialization with a type marker. It would be possible to have a function for registering types that are not owned by your package, and to provide a macro annotation that automatically does this for types declared in your package.
If there's a way to access a type ID in a macro, that would be a good way to instrument the mapping between TypeId and type name at compile time rather than runtime.
I am currently using Guava's ForwardingMap as a base class and have numerous types that extend it. I need to maintain the Map type because instances need to be treated as such in consumers. So, even though internally the ForwardingMap using composition the external interface still has to be a map.
As a map, deserializing just key-value properties using #JsonAnyGetter and #JsonAnySetter work fine but, I also need to take into account custom properties, using #JsonProperty, which may also be a part of the instance as well.
So, when serializing or deserializing I want all of the entries and any custom properties which may be a part of the extended class.
I have looked at numerous types of solutions, such as using the Shape.OBJECT and apply interfaces, but none of them seem to work properly for me. I believe I need to create a custom deserializer/serializer to handle the bean + map processing in Jackson but cannot find any examples as to how to do this.
These links help to explain what I am trying to do with no luck:
http://www.cowtowncoder.com/blog/archives/2013/10/entry_482.html
How to serialize with Jackson a java.util.Map based class (cannot change base of ForwardingMap)
Jackson - ignore Map superclass when serializing (cannot change base because it needs to remain a Map)
Ideally, I would like an example or pointer of how to serialize and deserialize an instance that extends ForwardingMap using #JsonAnySetter and #JsonAnyGetter and has custom properties using #JsonProperty as well.
I would want my output to look like
"modules": {
"MyModel": { <-- extends ForwardingMap<>
"domain": "typeinfo",
"property":"hello", <-- comes from #JsonProperty
"another": "GoodBye", <-- comes from #JsonAnyGetter
"another2": 50 <-- comes from #JsonAnyGetter
}
}