4

This project has MVVM, Room, Koin and Coroutines.

Project code:

@Dao
interface MovieDao {
   @get:Query("select poster_path from Movie")
   val getImgPopularMovieList: LiveData<List<String>>
}

What means "@get:Query" instead "@Query" and "val" instead "fun" in DAO interface?

And how to add WHERE clause without a function to pass parameter or using a constant? (Using mandatorily val instead fun). Example: "select poster_path from Movie WHERE category = :someParameterOrConstant"

  • 2
    If you want a parameter, you want a `fun`. What makes you think that isn't an option? – ianhanniballake Jun 24 '20 at 01:16
  • 1
    I guess this type of solution is about Single Sorce of Truth with koin integration. And there is a reason to be "val", but I don't know why. I would like to at least add a Constant in WHERE clause like ${Constant.category} – Lucas Simões Martins Jun 24 '20 at 01:18
  • 2
    You can certainly add a constant. What makes you think you can't do that? – ianhanniballake Jun 24 '20 at 01:21
  • "An annotation argument must be a compile-time constant" When I tried "select backdrop_path from Movie WHERE category = ${Constant.category}" – Lucas Simões Martins Jun 24 '20 at 01:28
  • 1
    So where do you define `Constant.category`? Is it actually a `const`? – ianhanniballake Jun 24 '20 at 01:39
  • Thank you to ask it, I didn't realized it. I've tried Enum... But I guess that isn't possible to use it... Now I don't know if I use Constant instead Enum or if exists another way to do it. I guess if I change "val" to "fun" won't be in the architecture – Lucas Simões Martins Jun 24 '20 at 02:03

1 Answers1

3

I would like to leave this answer, in case someone new in Kotlin like me encounters this.

I was learning codelab about Android, and @get:Query mentioned in the project, which lead me to this question, then after a good research I found this concept relates to Kotlin than Android and it is called Use-site Targets annotation.


Annotation Use-site Targets

Simply put, annotation use-site targets allow any @Annotations in your source code to end up at a very specific place in your compiled bytecode or in the Java code generated by kapt.

Kotlin supports the following values of the use-site targets that correspond to:

  • delegate – a field storing a delegated property
  • field – a field generated for a property
  • file – a class containing top-level functions and properties defined in that file
  • get/set – the property getter/setter
  • param – a constructor parameter
  • property – the Kotlin's property, it is not accessible from Java code
  • receiver – the receiver parameter of an extension function or property

Let's use simple class:

class Example(@param:ColorRes val resId:Int )

We used the use-site of param with @ColorRes, that will apply @ColorRes to the constructor parameter in the generated Java class:

public final class Example {

   private final int resId;

   public final int getResId() {
      return this.resId;
   }

   public Example(@ColorRes int resId) {
      this.resId = resId;
   }

}

Let's change the use-site to field:

class Example(@field:ColorRes val resId:Int )

Now @ColorRes annotation will be applied to the resId field of the generated class:

public final class Example {

   @ColorRes
   private final int resId;

   public final int getResId() {
      return this.resId;
   }

   public ViewModel(int resId) {
      this.resId = resId;
   }

}

By using the use-site of get:

class Example(@get:ColorRes val resId:Int )

The getter method of resId field will have the @ColorRes annotation:

public final class Example {

   private final int resId;

   @ColorRes
   public final int getResId() {
      return this.resId;
   }

   public Example(int resId) {
      this.resId = resId;
   }

}

So!

In our Android code:

@Dao
interface MovieDao {

   @get:Query("select poster_path from Movie")
   val popularMovieImageList: LiveData<List<String>>

}

The annotation use-site of get will require th implementation of MovieDao to apply Query("...") to getter method of popularMovieImageList:


public final class MovieDaoImpl {

   private final LiveData<List<String>> popularMovieImageList;

   @Query("select poster_path from Movie")
   public final LiveData<List<String>> getPopularMovieImageList() {
       ...
   }

}

NOTE: Previous java code is from my imagination, I have no idea how generated implementation for this Dao by Room will look, just to support my explanation.


So far!
Why @get:Query instead of @Query?

Well, from the docs of Android we use @Query for methods:

Marks a method in a Dao annotated class as a query method.

And from the docs of Kotlin we don't use the Annotation Use-site targets for methods but for a property or a primary constructor parameter:

When you're annotating a property or a primary constructor parameter, there are multiple Java elements which are generated from the corresponding Kotlin element, and therefore multiple possible locations for the annotation in the generated Java bytecode.

As far as I learned in Kotlin, property getter cannot have parameter but instead use methods for that.

I think all other confusions should be clear now.


References:

Ahmed Shendy
  • 1,424
  • 15
  • 28