Type conversion of declarative client URI argument - kotlin

I am implementing a declarative client in Micronaut that looks like this:
#Get("/dostuff{?requestObject*}")
fun getStuff(requestObject: MyRequestObject): String
My MyRequestObject contains an enum that is represented by some string:
data class MyRequestObject(val myEnum: MyEnum)
enum class MyEnum(val stringRep: String) {
AREASONABLENAME("someSillyString");
}
When I now send a request via the client the value from requestObject generates the following query /?myEnum=AREASONABLENAME. What I actually need is /?myEnum=someSillyString.
I tried the following things without any success:
add JsonValue function to MyEnum:
#JsonValue fun getJsonValue() = stringRep - of course did not help
implement a TypeConverter for MyEnum
#Singleton
class MyEnumTypeConverter : TypeConverter<MyEnum, String> {
override fun convert(`object`: MyEnum?, targetType: Class<String>?, context: ConversionContext?): Optional<String> {
return Optional.ofNullable(`object`?.stringRep)
}
}
Is there a way to achieve the desired behaviour?

You can override the toString method in the Enum so that when the converter tries to convert it to a string you can control the result of the operation:
enum class MyEnum(val stringRep: String) {
AREASONABLENAME("someSillyString");
override fun toString(): String {
return stringRep
}
}

Related

Jackson Serializaiton/Deserialization by custom property in enum

I want to make Jackson work with enums not by name and not by ordinal, but with a custom property I added called "stringId".
I wanted to support this with all Enums in the system so I made an interface called StringIdEnum which the FooEnum will implement.
I'm using Kotlin so I created a property in the interface called stringId which I override in each enum value.
Now I want to make Jackson serialize and deserialize using this stringId field, from what I seen I have several options:
Use #JsonProperty annotation on each enum value and make sure it is aligned with the stringId property.
I see two issues with this approach. one it's a lot of annotation to add (we have many enum classes across the system). two I need to make sure the annotation value and the property value should be always the same which can cause issues in the future.
I tried to use the READ_ENUMS_USING_TO_STRING feature, but because I'm using an interface I can't override the toString in the interface class (I can override it in every enum class but that again seems like a lot of redundant code)
Implement a custom serializer/deserializer.
The serializer is pretty straightforward, however, I had trouble with the deserializer.
I wanted to register the deserializer on the StringIdEnum interface, but I had an issue getting all the runtime enum values for the actual FooType enum.
StringIdEnum:
interface StringIdEnum {
val stringId: String
}
enum class FooType(override val stringId: String) : StringIdEnum {
FOO("FOO"),
GOO("GOO");
}
Managed to get it working:
#JsonSerialize(using = StringIdEnumSerializer::class)
#JsonDeserialize(using = StringIdEnumDeserializer::class)
interface StringIdEnum: DbEnum {
val stringId: String
}
class StringIdEnumSerializer: StdSerializer<StringIdEnum>(StringIdEnum::class.java) {
override fun serialize(value: StringIdEnum, gen: JsonGenerator, provider: SerializerProvider) {
gen.writeString(value.stringId)
}
}
class StringIdEnumDeserializer : JsonDeserializer<Enum<*>>(), ContextualDeserializer {
private lateinit var type: JavaType
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Enum<*> {
val t = p.text
val enumConstants = (type.rawClass as Class<Enum<*>>).enumConstants
return enumConstants.single { (it as StringIdEnum).stringId == t }
}
override fun createContextual(ctxt: DeserializationContext?, property: BeanProperty?): JsonDeserializer<*> {
val wrapperType: JavaType = property!!.type
val stringIdEnumDeserializer = StringIdEnumDeserializer()
stringIdEnumDeserializer.type = wrapperType
return stringIdEnumDeserializer
}
}

Can I omit type in generics? - Kotlin

If I have a following interface:
interface BaseDataRemote<T, in Params> {
fun getData(params: Params? = null): Single<T>
}
Would it be possible have implementation of this interface that does not take Params?
To have effectively something like:
interface BaseDataRemote<T> {
fun getData(): Single<T>
}
Implementation is as follows:
class RemoteSellerDataSource #Inject constructor(
private val sellerApi: SellerApi,
#Named("LANG") private val lang: String
) : BaseDataRemote<SellerEntity, Nothing> {
override fun getData(params: Nothing?): Single<SellerEntity> {
return sellerApi.getSeller(lang).map { it.fromApiEntity() }
}
}
I use Dagger 2 to module to bind this implementation:
#Module
internal interface RemoteModule {
#Binds
#CoreScope
fun bindsSellerRemote(remoteSellerDataSource: RemoteSellerDataSource): BaseDataRemote<SellerEntity, Nothing>
}
I tried using Nothing as second type parameter, but it does not seem to work
(I'm getting required: class or interface without bounds error
Full error message:
RemoteSellerDataSource.java:6: error: unexpected type
public final class RemoteSellerDataSource implements com.bigchangedev.stamps.business.sdk.data.base.data.BaseDataRemote<SellerEntity, ?> {
^
required: class or interface without bounds
found:?
Thanks.
EDIT: the original answer was a pure Kotlin answer because the OP didn't mention Dagger.
Using Nothing is correct and works in pure Kotlin. However, Dagger seems to convert your code to Java, and in doing so it uses wildcards for the generics (which it doesn't like because it wants exact type matches). To avoid this issue, you can try using #JvmSuppressWildcards on your generic type parameters:
class RemoteSellerDataSource #Inject constructor(
private val sellerApi: SellerApi,
#Named("LANG") private val lang: String
) : BaseDataRemote<SellerEntity, #JvmSuppressWildcards Nothing> {
override fun getData(params: Nothing?): Single<SellerEntity> {
return sellerApi.getSeller(lang).map { it.fromApiEntity() }
}
}
Although I'm not sure what will happen in Java with Nothing in that case. I guess this should have the same effect on the Java code as removing the in variance for the second type param in the interface declaration, but without weakening your Kotlin types.
Another workaround would be to use Unit instead of Nothing, which Dagger will most likely convert to Void in this case. This is not great for your types, though.
Original answer:
You can technically already call getData() without arguments thanks to the default value. An implementation that doesn't care about the params argument can simply expect null all the time.
The Kotlin type that only contains null and no other value is technically Nothing?, and since getData is defined with Params? (note the ?) as input, it should be correct to specify Nothing (even without ?) as second type argument. So you should be able to define an implementation like this:
interface BaseDataRemote<T, in Params> {
fun getData(params: Params? = null): Single<T>
}
class ImplementationWithoutParams<T> : BaseDataRemote<T, Nothing> {
override fun getData(params: Nothing?): Single<T> {
// params will always be null here
}
}
To avoid confusion for the users, this implementation may additionally provide a getData() method without arguments at all:
class ImplementationWithoutParams<T> : BaseDataRemote<T, Nothing> {
override fun getData(params: Nothing?): Single<T> = getData()
fun getData(): Single<T> {
TODO("implementation")
}
}

Kotlin: common interface on Enum class with static method to map from String

Suppose I have many enum classes like the following:
enum class Hero(val alias: String) {
SUPERMAN("Clark Kent"),
BATMAN("Bruce Wayne");
companion object {
fun fromAlias(value: String): Hero? = Hero.values().find { it.alias.equals(value, true) }
}
}
enum class Villain(val alias: String) {
TWO_FACE("Harvey Dent"),
RIDDLER("Edward Nigma");
companion object {
fun fromAlias(value: String): Villain? = Villain.values().find { it.alias.equals(value, true) }
}
}
I'd like to be able to create a generic interface to handle the fromAlias method in such a way that I can still call it using Hero.fromAlias("Bruce Wayne"). So my enum classes would be simplified to something like:
enum class Hero(override val alias: String): AliasedEnum<Hero> {
SUPERMAN("Clark Kent"),
BATMAN("Bruce Wayne");
}
enum class Villain(override val alias: String): AliasedEnum<Villain> {
TWO_FACE("Harvey Dent"),
RIDDLER("Edward Nigma");
}
I attempted to incorporate the answer from Kotlin define interface for enum class values method, but couldn't see a way to access the enum values() from the companion object in the interface. Is there a clean way to do what I am wanting?
You can quite easily do this by using the fact that companion object objects can extend other classes.
Pretty much any solution will require two different parts, since you need:
A common interface that provides any data required for the function, so it is available regardless of the actual implementation.
A way to attach the shared function to the companion object for <Class>.function access. This can either be an abstract class with the required implementation or a marker class with the implementation as an extension function.
In the end the "cleanest" solution would probably be this:
// Attaching point for the extension function which provides the answer
interface EnumCompanion<T : Enum<T>>
// Marker interface to provide the common data
interface WithAlias {
val alias: String
}
inline fun <reified T> EnumCompanion<T>.fromAlias(
value: String
): T? where T : Enum<T>, T : WithAlias {
return enumValues<T>().find { it.alias == value }
}
// Define the enums and attach the helper to their companion object
enum class Hero(override val alias: String) : WithAlias {
SUPERMAN("Clark Kent"),
BATMAN("Bruce Wayne");
companion object : EnumCompanion<Hero>
}
enum class Villain(override val alias: String) : WithAlias {
TWO_FACE("Harvey Dent"),
RIDDLER("Edward Nigma");
companion object : EnumCompanion<Villain>
}
fun main() {
println(Hero.fromAlias("Bruce Wayne"))
println(Villain.fromAlias("Edward Nigma"))
}

Overriding a JVM method using Kotlin property

MyKotlinClass is implementing ThirdPartyJavaInterface.
ThirdPartyJavaInterface
public interface ThirdPartyJavaInterface {
String getName();
}
MyKotlinClass
class MyKotlinClass (val name: String) : ThirdPartyJavaInterface
MyKotlinClass is not getting compiled because of Accidental Override error for getName() method by name field.
I do want to override the getName() intentionally. Is there any way to suppress the error by telling the compiler my intention?
One possible solution in my mind is as below but I don't want to write this much code (because in actual scenario I have 8 methods to override)
class MyKotlinClass (val aName: String) : ThirdPartyJavaInterface {
override fun getName(): String {
return aName
}
}

How to overcome "same JVM signature" error when implementing a Java interface?

With the code below, I am getting the following error in IntelliJ IDEA 13.1.6 and Kotlin plugin 0.11.91.AndroidStudio.3:
Platform declaration clash: The following declarations have the same JVM signature (getName()Ljava/lang/String;):
• public open fun getName(): kotlin.String?
• internal final fun <get-name>(): kotlin.String?
Java class, JavaInterface.java:
public interface JavaInterface {
public String getName();
}
Kotlin class, KotlinClass.kt
public class KotlinClass(val name: String?) : JavaInterface
I've tried overriding the 'getter' method by
adding override fun getName(): String? = name, but that produces the same error.
I can see one workaround by doing this instead:
public class KotlinClass(val namePrivate: String?) : JavaInterface {
override fun getName(): String? = namePrivate
}
But in my real-world case I have a number of properties to implement and need setters too. Doing this for each property doesn't seem very Kotlin-ish. What am I missing?
Making that variable private solves the problem.
public class KotlinClass(private val name: String?) : JavaInterface
You could use #JvmField for instructs the compiler not generate getter/setter, and you can implement your setters and getters. With this your code work well in Java (as attribute getter/setter) and Kotlin as property
Example:
JAVA:
public interface Identifiable<ID extends Serializable>
{
ID getId();
}
KOTLIN:
class IdentifiableImpl(#JvmField var id: String) :Identifiable<String>
{
override fun getId(): String
{
TODO("not implemented")
}
}
The annotation feature of Kotlin named #JvmName will solve the duplication problem in Java and Kotlin when having the same signature.
fun function(p: String) {
// ...
}
// Signature: function(Ljava/lang/String)
With the use of JvmName will be:
#JvmName("functionOfKotlin")
fun function(p: String) {
// ...
}
// Signature: functionOfKotlin(Ljava/lang/String)
IMHO most readable combination is field + explicit interface implementation by the single-expression function (combination of #Renato Garcia's and #Steven Spungin's answers):
Java:
public inteface SomeInterface {
String getFoo();
}
Kotlin:
class Implementation(#JvmField val foo: String) : SomeInterface {
override fun getFoo() = foo
}
Another work-around is to declare the properties in an abstract Kotlin class, then write a small java class that extends KotlinClass and implements JavaInterface.
// JavaInterface.java
public interface JavaInterface {
int getFoo();
void setFoo(int value);
}
// KotlinClass.kt
abstract class KotlinClass(open var foo : Int = 0) {
}
// JavaAdapter.java
class JavaAdapter extends KotlinClass implements JavaInterface {
// all code in KotlinClass, but can't implement JavaInterface there
// because kotlin properties cannot override java methods.
}
We have found that to use the same names without clashing, the ctor args must be private AND you must still override the interfaces methods. You don't need any additional backing fields. Also, your expression body assignment will not recurse, so you can safely use that syntax.
Java Interface
interface IUser {
String getUserScope();
String getUserId();
}
Kotlin Class
class SampleUser(private val userScope: String, private val userId: String) : IUser {
override fun getUserId() = userId
override fun getUserScope() = userScope
}
If you have direct control over the interface then the best approach is to write the interface in Kotlin. You can then write your class
public class KotlinClass(override val name: String?) : KotlinInterface
and still reference it from any Java code using the same interface as before. This looks a lot neater than setting all the properties to private and overriding the get function. Obviously if you can't migrate the interface to Java because you don't own it then that seems to be the only solution.
public interface JavaInterface {
public String getName();
}
public class KotlinClass(val namePrivate: String?) : JavaInterface {
private var name = namePrivate
override fun getName(): String? {
return name
}
}
Rename the variable to something else, or make it private if u dont want it to be public.
convert function to property instead of initializing property from a function.
for ex:
fun getCountriesList(): List<Country> {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States",R.drawable.us_flag))
return countries
}
to
val countriesList: List<Country>
get() {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States", R.drawable.us_flag))
return countries
}