No args error retrofit request body - android

I am facing problem while sending json object body using retrofit to the server. Below is the error.
Failed to invoke public
com.nitesh.brill.saleslines._User_Classes.User_PojoClass.UpdatePreviousDetails()
with no args
code snippet
// Api endpoint
#Headers("Content-Type: application/json")
#POST("UpdatePreviousDetails/{Id}")
fun updatePreviousDetails(#Path("Id") Id: Int, #Body updateDetails :UpdatePreviousDetails): Call<UpdatePreviousDetails>
//pojo class
package com.nitesh.brill.saleslines._User_Classes.User_PojoClass
import java.util.*
/**
* Created by Nitesh Android on 16-08-2017.
*/
class UpdatePreviousDetails(
var CompanyName: String? = null!!,
var Designation: String? = null!!,
var DateOfJoin: Date? = null!!,
var DateOfLeaving: Date? = null!!,
var SectorPreviouslyWorked: String? = null!!,
var Id: Int? = null!!
) {
}
//sending data
val details = UpdatePreviousDetails("rr", "asm", date, date, "Pharmaceuticals",3)
val call = apiEndpointInterface!!.updatePreviousDetails(5, details)
call.enqueue(object :Callback<UpdatePreviousDetails> {
override fun onResponse(call: Call<UpdatePreviousDetails>?, response: Response<UpdatePreviousDetails>?) {
objUsefullData.showSnackBar("success")
UsefullData.Log("============="+response!!.body().toString())
}
override fun onFailure(call: Call<UpdatePreviousDetails>?, t: Throwable?) {
objUsefullData.showSnackBar("fail")
UsefullData.Log("============="+t)
}
})
I am using kotlin language

Your UpdatePreviousDetails class has to have a constructor with no params to enable Gson (inside Retrofit) to convert your object into JSON.
EDIT
class UpdatePreviousDetails() {
var CompanyName: String? = null
var Designation: String? = null
var DateOfJoin: Date? = null
var DateOfLeaving: Date? = null
var SectorPreviouslyWorked: String? = null
var Id: Int? = null
constructor(
CompanyName: String?,
Designation: String?,
DateOfJoin: Date?,
DateOfLeaving: Date?,
SectorPreviouslyWorked: String?,
Id: Int?
) : this() {
this.CompanyName = CompanyName
this.Designation = Designation
this.DateOfJoin = DateOfJoin
this.DateOfLeaving = DateOfLeaving
this.SectorPreviouslyWorked = SectorPreviouslyWorked
this.Id = Id
}
}

Related

Send a ZIP file for a server using kotlin and retrofit

I looking for a way to send a zip file for a server using retrofit in kotlin. Some functions are deprecated that's make this more dificulte. When I star the request the response is NULL, there is no error.
That is the function who start the request:
fun sendZipeFile() {
val retrofitClient = NetworkUtils
.getRetrofitInstance("http://url.com")
val sendZipeFileEndPoint = retrofitClient.create(SendZipeFile::class.java)
var file = File("/storage/emulated/0/Download/file.zip")
val requestImageFile = file?.asRequestBody("multipart/form-data".toMediaType())
val callback = startZipeFileUpload.zipeFileUpload("application/zip","Atualização", requestImageFile, "0.0.2")
callback.enqueue(object : Callback<UploadZipFile> {
override fun onFailure(call: Call<UploadZipFile>, t: Throwable) {
t.message
t.fillInStackTrace()
}
override fun onResponse(call: Call<UploadZipFile>, response: Response<UploadZipFile>) {
val responseString = response.body()
}
})
}
Below is an interface
interface SendZipeFile{
#Headers("Content-Type: multipart/form-data")
#Multipart
#POST("updateModelsAndParameters/" +
"")
fun zipeFileUpload(
#Header("Content-Type") contentType: String?,
#Part("description") description: String?,
#Part("Zip") file: RequestBody?,
#Part("flag")flag: String?,
): Call<UploadZipFile>
}
And the data class
import com.google.gson.annotations.SerializedName
data class UploadZipFile(
#SerializedName("status_code") var statusCode: Int? = null,
#SerializedName("message") var message: String? = null,
#SerializedName("elapsed_ms") var elapsedMs: Double? = null,
#SerializedName("response") var resposta: Boolean? = null,
)

Moshi JSON adapter with generic type

I want to use a Moshi adapter with a generic type.
Here is my generic type adapter code,
fun <T> getObjectFromJson(typeOfObject: Class<T>, jsonString: String): T? {
val moshi = Moshi.Builder().build()
val jsonAdapter: JsonAdapter<T> = moshi.adapter<T>(
typeOfObject::class.java
)
return jsonAdapter.fromJson(jsonString)!!
}
This code is not working. It is throwing an error,
Platform class java.lang.Class requires explicit JsonAdapter to be registered
But, If I don’t use a generic type like this,
fun getObjectFromJson(jsonString: String): UserProfile? {
val moshi = Moshi.Builder().build()
val jsonAdapter: JsonAdapter<UserProfile> = moshi.adapter<UserProfile>(
UserProfile::class.java
)
return jsonAdapter.fromJson(jsonString)!!
}
Then the code is working fine.
Here is the UserProfile class,
#Parcelize
#JsonClass(generateAdapter = true)
data class UserProfile(
#get:Json(name = "p_contact")
val pContact: String? = null,
#get:Json(name = "profile_pic")
var profilePic: String? = null,
#get:Json(name = "lname")
val lname: String? = null,
#get:Json(name = "token")
var token: String? = null,
#get:Json(name = "fname")
val fname: String? = null,
#SerializedName("_id")
#get:Json(name = "_id")
var id: String? = null,
#get:Json(name = "email")
var email: String? = null,
#SerializedName("refresh_token")
#get:Json(name = "refresh_token")
var refreshToken: String? = null
) : Parcelable
The typeOfObject is an instance of the Class<T> class already, you are calling ::class.java on it unnecessary: it returns Class<Class> and that's not what you want.
Just change
val jsonAdapter: JsonAdapter<T> = moshi.adapter<T>(typeOfObject::class.java)
to
val jsonAdapter: JsonAdapter<T> = moshi.adapter<T>(typeOfObject)
By the way: creating a new Moshi instance on each deserialization is suboptimal. You should reuse it.

Moshi: Platform class java.lang.Class requires explicit JsonAdapter to be registered

I'm using a Moshi adapter to get the object from a JSON string. But, I'm getting an error,
java.lang.IllegalArgumentException: Platform class java.lang.Class requires explicit JsonAdapter to be registered
All the data members of the UserProfile class are only String type then why it is asking to create an explicit JsonAdapter?
MoshiDataConverter
class MoshiDataConverter() {
fun <T> getObjectFromJson(typeOfObject: Class<T>, jsonString: String): T? {
val moshi = Moshi.Builder().build()
val jsonAdapter: JsonAdapter<T> = moshi.adapter<T>(
typeOfObject::class.java
)
return jsonAdapter.fromJson(jsonString)!!
}
}
getObject method
fun <T> getObject(#Keys key: String?, typeOfObject: Class<T>?): T? {
val value = getString(key, null) ?: return null
return MoshiDataConverter().getObjectFromJson(typeOfObject!!, value)
}
UserProfile.kt
#Parcelize
#JsonClass(generateAdapter = true)
data class UserProfile(
#get:Json(name = "p_contact")
val pContact: String? = null,
#get:Json(name = "profile_pic")
var profilePic: String? = null,
#get:Json(name = "lname")
val lname: String? = null,
#get:Json(name = "token")
var token: String? = null,
#get:Json(name = "fname")
val fname: String? = null,
#SerializedName("_id")
#get:Json(name = "_id")
var id: String? = null,
#get:Json(name = "email")
var email: String? = null,
#SerializedName("refresh_token")
#get:Json(name = "refresh_token")
var refreshToken: String? = null
) : Parcelable
Your typeOfObject parameter is already a class reference, so you don't need to call ::class.java on it before passing it to the Moshi adapter.
Try replacing
val jsonAdapter: JsonAdapter<T> = moshi.adapter<T>(
typeOfObject::class.java
)
with
val jsonAdapter: JsonAdapter<T> = moshi.adapter<T>(typeOfObject)

How you do simplify this Kotlin Getter and Settle code?

I am new to Kotlin and have been developing with the language. From Java, I am used to coding getters and setters by creating two functions. For example:
public String getName(){
return name;
}
public void setName(name){
this.name = name;
}
However, can this code be simplified in Kotlin? My code right now is:
class ClassName{
private var username: String? = null
private var photoFileName: String? = null
private var userId: String? = null
private var requestSent: Boolean? = null
fun ClassName(username: String?, photoFileName: String?, userId: String?, requestSent: Boolean?) {
this.username = username
this.photoFileName = photoFileName
this.userId = userId
this.requestSent = requestSent
}
fun getUsername(): String? {
return username
}
fun setUsername(string: String){
username = string
}
fun getPhotoFileName(): String? {
return photoFileName
}
fun setPhotoFileName(string: String){
photoFileName = string
}
fun getUserId(): String? {
return userId
}
fun setUserId(string: String){
userId = string
}
fun getRequestSent(): Boolean? {
return requestSent
}
fun setRequestSent(bool: Boolean){
requestSent = bool
}
}
Here's a more enhanced version of your kotlin class
data class YourClass(
var username: String? = null,
var photoFilename: String? = null,
var userId: String? = null,
var requestSent: Boolean? = null
)
You don't have to manually create setter, getter function in Kotlin.
Your class will get converted to this if you use data class in kotlin. All the setters and getters will be replaced by the properties.And yes you can always call them like you used to do like set and get.
data class ClassName(
var username: String,
var photoFileName: String,
var userId: String,
var requestSent: String
)

Getting null value in response

I am trying to get the response from https://www.reddit.com/r/popular/.rss and map to Kotlin POJO class in Android. But when I am logging that category's label value, getting null. For the title I am getting response value as popular links.
Here is entity class FeedX:-
#Root(name = "feed", strict = false)
class FeedX {
#set: Element(name = "category")
#get: Element(name = "category")
var category: Category? = null
val entry: List<Entry>? = null
val id: String? = null
val link: List<LinkX>? = null
#set: Element(name = "title")
#get: Element(name = "title")
var title: String? = null
val updated: String? = null
}
Category class:-
#Root(name = "category", strict = false)
class Category {
#set: Element(required = false, name = "_label")
#get: Element(required = false, name = "_label")
var _label: String? = null
val _term: String? = null
}
Here is Api Interface:-
interface FeedApi {
#GET("{type}/.rss")
fun getPopularFeeds(
#Path("type") type: String?
): Call<FeedX>?
}
Here is MainActivity:-
class MainActivity : AppCompatActivity() {
private val BASE_URL = "https://www.reddit.com/r/"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(SimpleXmlConverterFactory.create())
.build()
val service = retrofit.create(FeedApi::class.java)
service.getPopularFeeds("popular")?.enqueue(object : Callback<FeedX> {
override fun onFailure(call: Call<FeedX>, t: Throwable) {
Log.d("Response Failed", "${t.localizedMessage}")
}
override fun onResponse(call: Call<FeedX>, response: Response<FeedX>) {
if (response.isSuccessful) {
Log.d("Response Success", "${response.body()!!.title}") // for this I am getting value
Log.d("Response Success", "${response.body()!!.category?._label}") // always getting null value
} else {
Log.d("Response Failed jg", "${response.errorBody()}")
}
}
})
}
}
This is because title contains a value where category tag doesn't. See the difference below.
<title>popular links</title>
<category term="AskReddit" label="r/AskReddit"/>
As you can see category tag is self closing.

Categories

Resources