Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Kotlin model classes #116

Open
EricKuck opened this issue Nov 29, 2015 · 23 comments
Open

Add support for Kotlin model classes #116

EricKuck opened this issue Nov 29, 2015 · 23 comments

Comments

@EricKuck
Copy link
Member

No description provided.

@AndreasBackx
Copy link

Any information on this?

@DebauchedSloth
Copy link

Also very interested in this.

@mradzinski
Copy link

KAPT matured pretty much lately, so I'm almost positive we can make LoganSquare kotlin-ready. I'll try some stuff and PR the outcome.

@samvanderhyden
Copy link

I'd love to see this working as well.

@marcusmotill
Copy link

as would I!

@mannodermaus
Copy link
Contributor

I just did some quick tests and found kapt to be already working with LoganSquare. This is the setup I used:

build.gradle:

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.0"
    compile "com.bluelinelabs:logansquare:1.3.5"

    kapt "com.bluelinelabs:logansquare-compiler:1.3.5"
}

Model.kt:

@JsonObject
class Model {

    @JsonField(name = arrayOf("value"))
    var value: String? = null
        get

    @OnJsonParseComplete
    fun onParseComplete(): Unit {
        println("onParseComplete")
    }

    @OnPreJsonSerialize
    fun onPreSerialize(): Unit {
        println("onPreSerialize")
    }
}

Main.kt:

fun main(args: Array<String>) {
    var model: Model = LoganSquare.parse("{\"value\":\"HELLO\"}", Model::class.java)
    println("model: ${model.value}")

    println("json: ${LoganSquare.serialize(model)}")
}

Output:

onParseComplete
model: HELLO
onPreSerialize
json: {"value":"HELLO"}

Let's collect further improvements that we would like to see made to LoganSquare in this regard!

@EricKuck
Copy link
Member Author

EricKuck commented Mar 9, 2016

That's awesome @aurae! I haven't had time to get into Kotlin anywhere near as much as I'd like to yet, so I'm probably not the one who should be driving these ideas forward. If something either doesn't work correctly or doesn't feel right for Kotlin dev, please post issues! I should be starting my first full Kotlin project in the next few weeks, so I'll be able to contribute soon(ish).

Also, PR's are definitely welcome @mradzinski

@marcusmotill
Copy link

@aurae I have had similar success...Have you used the logansquare compiler with retrofit yet?
I would assume this works just fine since the Kotlin gets compiled to java-esque dex files correct?

@mannodermaus
Copy link
Contributor

I haven't tried retrofit-logansquare in a Kotlin environment yet, but I would assume that it works. I can't say for sure though!

@mradzinski
Copy link

@aurae The problem with your test is that you are not attaching to Kotlin idiom guidelines. As per Kotlin documentation, DTO's should not be simple Kotlin classes but data classes.

data class Model(var value: String) {
    @OnJsonParseComplete
    fun onParseComplete(): Unit {
        println("onParseComplete")
    }

    @OnPreJsonSerialize
    fun onPreSerialize(): Unit {
        println("onPreSerialize")
    }
}

The reason for this is that Kotlin generates the getters and setters for you, plus you get copy(). I don't find this to be a huge problem as long as you define your getters and setters manually, but I think that by doing this you'll not be taking full advantage of Kotlin's power.

I'll check if there's a way to modify logansquare-compiler to look for constructor fields (like the ones present in data classes) instead of annotated ones and ignore those which are not part of the constructor itself (consider them transient fields). Kotlin first constructors become plain and simple java ones at compile time, so I guess it shouldn't be that hard to check for the constructor method instead of the annotated fields.

You can find more information about Kotlin idioms here: https://kotlinlang.org/docs/reference/idioms.html

@mannodermaus
Copy link
Contributor

Okay, that makes sense. Indeed, I also wasn't able to make LS work with data classes, hence the example with an "ordinary" class. Supporting constructor fields brings us back to #3, which would in turn allow Kotlin data classes to work as well, I think.

@EricKuck
Copy link
Member Author

Anyone have ideas on how using constructors would ideally work? Would it try to match member variable names w/ constructor parameters names (very error prone)? Or would the dev be expected to annotate their constructor params (kinda ugly)? Or is there another option I haven't considered?

@marcusmotill
Copy link

I would want to make a data class the normal way and then add the annotation:

@JsonObject(fieldDetectionPolicy = FieldDetectionPolicy.NONPRIVATE_FIELDS_AND_ACCESSORS)

And if you need to customize a field you can annotate in the constructor:

data class Download(@JsonField(name = "file_path") val path: String?, val mimeType: String?, val isSuccess: Boolean)

@ppamorim
Copy link
Contributor

ppamorim commented Apr 26, 2016

I don't know why, but my parse is returning empty for every field. Version 1.3.6.

@JsonObject
class Line(@PrimaryKey @JsonField var id : Int,
                @JsonField var name : String) : Parcelable {

  companion object {
    @JsonIgnore @JvmField final val CREATOR: Parcelable.Creator<Line> =
        object : Parcelable.Creator<Line> {
      override fun createFromParcel(source: Parcel): Line = Line(source)
      override fun newArray(size: Int): Array<Line?> = arrayOfNulls(size)
    }
  }

  constructor(parcel : Parcel) : this(
      parcel.readInt(),
      parcel.readString())

  override fun writeToParcel(parcel: Parcel, flag: Int) {
    parcel.writeInt(id)
    parcel.writeString(name)
  }

  override fun describeContents(): Int = 0

}

@ppamorim
Copy link
Contributor

wtf2

@ppamorim
Copy link
Contributor

The LoganSquare is not mapping all anotated fields, tested in 2 PCs with differents projects.

@ppamorim
Copy link
Contributor

Unfortunately, LoganSquare still not working with Kotlin. I will use another parser. Sorry.

@henrikpersson
Copy link

Any news on this? 😸

@alexxxdev
Copy link

guys, have any changes to support the data-classes of Kotlin? I see the project does not develop ;(

@Alexander--
Copy link

I have created a pull request, that implements this feature — #213

@LuigiPapino
Copy link

For me this syntax works fine:

@JsonObject(fieldNamingPolicy = LOWER_CASE_WITH_UNDERSCORES,
    fieldDetectionPolicy = NONPRIVATE_FIELDS_AND_ACCESSORS)
data class UserApplianceBody(var uri: String = "", var nativeId: String = "")

@JsonObject(fieldNamingPolicy = LOWER_CASE_WITH_UNDERSCORES,
    fieldDetectionPolicy = NONPRIVATE_FIELDS_AND_ACCESSORS)
data class UserApplianceContainerBody(
    var appliance: UserApplianceBody = UserApplianceBody())

Basically you have to provide a default value for each field, so Kotlin will generate an empty constructor, needed by LS.
The other problem is to use NONPRIVATE_FIELDS_AND_ACCESSORS instead of just NONPRIVATE_FIELDS
Another solution is to annotate each field withJsonField(name = arrayOf("fieldName"))

Didn't fully tested, but in my simple use case does the trick.

@Alexander--
Copy link

Alexander-- commented Jul 26, 2017

@LuigiPapino Your approach works only for fully mutable data classes (where all fields are var). Many people consider data classes to be nearly synonymous with "immutable". Some of their benefits (generated constructors, copy() method) are pointless without immutability.

Every objection I have heard against use of LoganSquare have been motivated by lack of support for immutable classes. Developers, who express such concerns in the first place, are unlikely to adapt their data classes to make LoganSquare work.

@LuigiPapino
Copy link

LuigiPapino commented Jul 26, 2017

I guess depends on the use case.
I'm happy to lose the immutability, if it avoids all the boilerplate code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests