An annotation argument must be a compile-time constant - Kotlin [duplicate] - kotlin

This question already has an answer here:
An annotation argument must be a compile-time constant
(1 answer)
Closed 9 months ago.
I wanna send an argument from an override function on my MainActivity to use on an interface to changue an URL everytime that i made click on a drop down list.
On my MainActivity i have:
before the class definition:
var item2:String="popular"
class MainActivity : AppCompatActivity(),AdapterView.OnItemClickListener {
on the same activity:
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long)
{
val item = parent?.getItemAtPosition(position).toString()
item2=item
}
and in the interface:
val get_url:String ="/3/movie/$item2?api_key=KEY_NUMBER"
interface MovieApiInterface {
#GET(get_url)
fun getMovieList(): Call<MovieResponse>
}
But there i have "An annotation argument must be a compile-time constant"
Don't understand why :(
Thanks

The error message is actually pretty descriptive, you can only pass compile-time constants as arguments to annotations, so you'll need to replace:
val get_url:String ="/3/movie/$item2?api_key=KEY_NUMBER"
interface MovieApiInterface {
#GET(get_url)
fun getMovieList(): Call<MovieResponse>
}
with:
interface MovieApiInterface {
#GET("/3/movie/$item2?api_key=KEY_NUMBER")
fun getMovieList(): Call<MovieResponse>
}

Related

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 generics supertype not applied

I was coding on Java for quite a long time and trying to migrate to Kotlin. I'm confused with Generics in Kotlin a bit...
I have a DelegateManager class. It should consume only subtypes of IViewData
class DelegateManager<T : IViewData> {
private val delegates: MutableList<AdapterDelegate<T>> = mutableListOf()
fun addDelegate(adapterDelegate: AdapterDelegate<T>) {
delegates.add(adapterDelegate)
}
...
}
Inside TrackListAdapter I want to add a delegate. As you might have seen it's AdapterDelegate<TrackViewData> and TrackViewData is a subtype of IViewData So it should work but it shows error inside init block of TrackListAdapter
class TrackListAdapter : BaseListAdapter<IViewData>() {
init {
delegateManager.addDelegate(TrackViewDelegate()) // error: Type mismatch -> Required: AdapterDelegate<IViewData>, Found: TrackViewDelegate
}
}
class TrackViewDelegate : AdapterDelegate<TrackViewData>() {
override fun onCreateViewHolder(parent: ViewGroup): ListViewHolder<TrackViewData> {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.track_item, parent, false)
return TrackViewHolder(itemView)
}
override fun isDelegateForDataType(data: IViewData) = data is TrackViewData
}
How to deal with it? How to extend the generic parameter correctly?

Kotlin Inheritance - Extend JVM class and interface which have same method names

I have a custom Exception class which looks like this:
class GenericException(message: String?, errorCode: Int) : RuntimeException(message), GraphQLError {
.....
}
As you all know, RuntimeException extends Throwable which has a method called getMessage()
Now the issue is, this interface GraphQLError (which is a library interface) also has a method called getMessage()
As a result, compiler is complaining with this:
OK so I implement the method:
override fun getMessage(): String {
TODO("Not yet implemented")
}
Now I get this:
What am I supposed to do here?
What I guessed in the comments was right, kotlin allows multiple inheritence. It was indeed because of the Throwable class.
You can use #JvmField annotation to instruct the compiler not to generate getters and setters for the field and then create the getter/setter yourself.
interface HasMessage {
fun getMessage(): String
}
class GenericException(
#JvmField override val message: String?, // var is also possible
val errorCode: Int // I made it a property, might not be as well
) : RuntimeException(message), HasMessage {
override fun getMessage(): String {
// return of the super's getter, probably no use because you have field as property in this class
val superGetMessage = super<RuntimeException>.message
TODO("Not yet implemented")
}
}
Play with the code yourself.

Restricting type of companion object in Kotlin

I want to create an interface with a print method that will print a value followed by a suffix.
So:
interface Unitary<T>{
val value: T
fun print(){
print(value)
println(suffix)
}
}
interface HasSuffix{
val suffix: String
}
inline class Centimeters(val value: Double): Unitary<Double>{
companion object: HasSuffix{
override val suffix = "cm"
}
}
Currently I'm receiving the error:
Unresolved reference: suffix
Is there a way to indicate that suffix will be declared on the companion object of any implementing interface?
Is there a way to indicate that suffix will be declared on the companion object of any implementing interface?
I don't think there is.
You can work around that with something like:
interface Unitary<T>{
val value: T
fun suffixProvider() : SuffixProvider
fun print(){
print(value)
println(suffixProvider().suffix)
}
}
interface SuffixProvider{
val suffix: String
}
inline class Centimeters(override val value: Double): Unitary<Double>{
companion object: SuffixProvider{
override val suffix = "cm"
}
override fun suffixProvider() = Centimeters
}
You cannot force subclasses to provide particular functionality namely via companion objects. Instead, you can force them provide a particular methods. How the classes implement this method is up to them.

Parcelable overload resolution ambiguity

I am trying to create a POJO (aka data classes in Kotlin) structure of a JSON response in Kotlin. I've implemented the Parcelable interface for each data class in the structure. In all of the data classes, I've auto generated the Parcelable implementation. The issue is the generated second constructor where the IDE is complaining about:
Overload resolution ambiguity
It states that it's being confused between these two constructors:
public constructor GeocodeRes(parcel: Parcel)
public constructor GeocodeRes(responset: ResponseRes)
Which I believe makes sense because ResponseRes is also of type Parcelable (ResponseRes implements Parcelable). So calling the GeocodeRes(parcel) method (within the createFromParcel companion method), it is getting confused.
That was until I removed ResponseRes from implementing the Parcelable class and it's still showing the same error.
Is there any reason to this? Am I setting this up properly? In all of the children data classes, they all implement the Parcelable interface (with dependence with eachother) but aren't running into any issues.
Here's my GeocodeRes class:
import android.os.Parcel
import android.os.Parcelable
import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName
data class GeocodeRes(
#SerializedName("Response") #Expose val responset: ResponseRes
) : Parcelable {
// this is the problem. the IDE is complaining that the usage is too ambiguous (). however, the only usage of this constructor is within this class - just doesn't tell me where exactly.
constructor(parcel: Parcel) : this(parcel.readParcelable(ResponseRes::class.java.classLoader)) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(responset, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<GeocodeRes> {
override fun createFromParcel(parcel: Parcel): GeocodeRes {
return GeocodeRes(parcel)
}
override fun newArray(size: Int): Array<GeocodeRes?> {
return arrayOfNulls(size)
}
}
}
Here's my ResponseRes class:
data class ResponseRes(
#SerializedName("MetaInfo") #Expose val metaInfo: MetaInfo,
#SerializedName("View") #Expose val views: List<View>
): Parcelable
{
[...]//parcel methods
}
however, the only usage of this constructor is within this class - just doesn't tell me where exactly
The problem is with the definition itself, not with any usage. It could never be used, and the error would still be there.
You should be able to fix this by specifying which Parcelable you want to read:
this(parcel.readParcelable<ResponseRes>(ResponseRes::class.java.classLoader))
The compiler can't decide if you mean that or
this(parcel.readParcelable<Parcel>(ResponseRes::class.java.classLoader))
Even though the second wouldn't be legal because Parcel doesn't implement Parcelable, if you look at the signature
<T extends Parcelable> T readParcelable(ClassLoader loader)
you can see only the return type can be used to infer T, not the argument. So the compiler need to pick the constructor overload before trying to infer T.