What should my data class be so that when I convert it to json using moshi it would come out like this?
{"id":"abcdef""formValues":{}}
At the moment my class looks like this.
#JsonClass(generateAdapter = true)
class MyDataClass(
#Json(name = "id")
val id: String
) {
#Json(name = "formValues")
val formValues = FormValues()
#JsonClass(generateAdapter = true)
class FormValues
}
But you see the statement
Moshi.Builder().build().adapter(MyDataClass::class.java).toJson(MyDataClass("abcdef"))
produces this
{"id": "abcdef"}
and I want this
{"id":"abcdef""formValues":{}}
It turns out you have to use var instead of val for your class members. I change my class to this
#JsonClass(generateAdapter = true)
class MyDataClass(
#Json(name = "id")
var id: String
) {
#Json(name = "formValues")
var formValues = FormValues()
#JsonClass(generateAdapter = true)
class FormValues
}
and moshi generates json like this
{"id":"abcdef""formValues":{}}
Related
[{"id":1,"first_name":"Lillis","last_name":"Hawgood"," cars":[ {"item":"Savana 1500"}, {"item":"Vibe"}, {"item":"Estate"} ]}]
data class MyData( val id: Int = 0, val first_name: String = "", val last_name: String = "", val cars: List
)
class Car { #Json(name = "item") var item: String? = null How to use Item in Data class the how ot print in main clas using moshi txtResult.text = "" for (myDataLst in myDataList ?: emptyList()) { txtResult.append("${myDataLst.first_name} - ${myDataLst.last_name} - ${myDataLst.cars} \n") }enter code here
I tried this way only first name and last showing but for cars showing some worng infor
Try this data classes i transform it using Json to Data Class plugin.
data class MyData(
val cars: List<Car>,
val first_name: String,
val id: Int,
val last_name: String
)
data class Car(
val item: String
)
class car : ArrayList<MyData>()
Firstly, please format your code, it's hard to read your code.
Secondly, you can use the Moshi like this:
#JsonClass(generateAdapter = true)
data class MyData(
#Json(name = "id") val id: String,
#Json(name = "first_name") val firstName: String,
#Json(name = "last_name") val lastName: String,
#Json(name = "cars") val cars: List<Car>
)
#JsonClass(generateAdapter = true)
data class Car(
#Json(name = "item") val item: String
)
I have an object that comes down from the API with another json object (with no named attributes) as one of its attributes:
"stickerData": {}
I would like this to be parsed into this object:
#JsonClass(generateAdapter = true)
class StickerDto(
#Json (name = "totalAnimatedStickers") val total: Int,
#Json(name = "pages") val pages: Int,
#Json(name = "data") val stickers: List<Sticker>
)
#JsonClass(generateAdapter = true)
class Sticker(
#Json(name = "name") val name: String,
#Json(name = "id") val id: String,
#Json(name = "stickerData") val stickerData: String,
)
The architecture of this app uses a single Retrofit instance for every API call:
private fun createNewUserApiClient(authRefreshClient: AuthRefreshClient,
preferencesInteractor: PreferencesInteractor): UserApiClient {
val moshi = Moshi.Builder()
.add(SkipBadElementsListAdapter.Factory)
return Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(Interactors.apiEndpoint)
.build()
.create(UserApiClient::class.java)
}
Which, uses this adapter that you can see getting attached above:
internal class SkipBadElementsListAdapter(private val elementAdapter: JsonAdapter<Any?>) : JsonAdapter<List<Any?>>() {
object Factory : JsonAdapter.Factory {
override fun fromJson(reader: JsonReader): List<Any?>? {
val result = mutableListOf<Any?>()
reader.beginArray()
while (reader.hasNext()) {
try {
val peeked = reader.peekJson()
result.add(elementAdapter.fromJson(peeked))
} catch (e: JsonDataException) {
Timber.w(e, "Item skipped while parsing:")
}
reader.skipValue()
}
reader.endArray()
return result
}
}
However, this adapter does not allow for the parsing of a JSON object as a string. If I try, it throws a
Gson: Expected a string but was BEGIN_OBJECT
error. Is there any way to get this adapter to parse attributes like this as raw strings, rather than looking for an object ?
The stickerData should be Object in POJO class, like this...
#JsonClass(generateAdapter = true)
class Sticker(
#Json(name = "name") val name: String,
#Json(name = "id") val id: String,
#Json(name = "stickerData") val stickerData: StickerData,
)
Sorry if this is a basic question, but i'm new to Moshi.
So, I have a class with Generic Type Paramter as follows:
class BaseResponse<T> {
#Json(name = "message")
var message: String? = null
#Json(name = "data")
var data: T? = null
#Json(name = "meta")
var meta: JsonObject? = null
#Json(name = "error")
var error: ErrorResponse? = null
}
In GSON, this is done automatically and it works as long as i provide #SerializedName("data") and extends BaseResponse in my retrofit method. But it returns error with moshi as i could not deserialize BaseResponse. How can i fix this?
Both base class and class that replace generic type in code must be annotated with #JsonClass(generateAdapter = true). Please notice that the most important thing in order json to be converted correctly to a model class such as this, is to declare fields at base class as var and NOT as val. Please look the example below:
#JsonClass(generateAdapter = true)
class BaseResponse<T> {
#Json(name = "message")
var message: String? = null
#Json(name = "data")
var data: T? = null
#Json(name = "meta")
var meta: JsonObject? = null
#Json(name = "error")
var error: ErrorResponse? = null
}
Api example:
#GET("api/info")
suspend fun getInfo(): BaseResponse<Info>
Info:
#JsonClass(generateAdapter = true)
data class Info(
val language: String? = null,
val profile: Profile? = null
)
In Moshi you have to explicitly declare your annotations as field annotations, like #field:Json(name = "message")
Can anyone please tell me why this is not working
Model class :
#JsonClass(generateAdapter = true)
data class InstagramBusinessAccountResponse(
val data : List<Account>
) {
data class Account(
#Json(name = "id") val id : String,
#Json(name = "instagram_business_account") val instagramBusinessAccount : InstagramBusinessAccount
) {
data class InstagramBusinessAccount(
#Json(name = "id") val id: String,
#Json(name = "name") val name: String,
#Json(name = "profile_picture_url") val profilePictureUrl: String = ""
)
}
companion object {
fun fromJson(json: String) : InstagramBusinessAccountResponse {
val moshi = Moshi.Builder().build()
val jsonAdapter = moshi.adapter(InstagramBusinessAccountResponse::class.java)
return jsonAdapter.fromJson(json)!!
}
}
}
When parsing the following json
{"data":[{"instagram_business_account":{"id":"id","username":"name","name":"Suyash Chavan","profile_picture_url":"image"},"id":"id"}]}
with
InstagramBusinessAccountResponse.fromJson(json.toString())
...
companion object {
fun fromJson(json: String) : InstagramBusinessAccountResponse {
val moshi = Moshi.Builder().build()
val jsonAdapter = moshi.adapter(InstagramBusinessAccountResponse::class.java)
return jsonAdapter.fromJson(json)!!
}
}
gives instagramBusinessAccount null but if I don't use Custom field names with #Json i.e. replacing instagramBusinessAccount with instagram_business_account and profilePictureUrl with profile_picture_url, it works fine.
I was missing .add(KotlinJsonAdapterFactory()) in Moshi Builder.
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
It works now.
I would like to pass objects (that I got through Retrofit) to fragments. I heard of 2 methods, but I have problems with both. I am trying to pass a FullForecast object to my fragments.
Use Parcelize. I implemented it on my class, but it conflicted with my constructor.
I heard I could pass a Json string from the activity to fragment and then convert it to an object once inside the fragment. However, I could not get the Json string from my Json call. I tried Call<ResponseBody>, and did response.body().toString(), but didnt get a Json string
Here is my code
repository.getWeatherForecast(place,
object : Callback<FullForecast> {
override fun onFailure(call: Call<FullForecast>?, t: Throwable?) {
println("onFailure")
}
override fun onResponse(call: Call<FullForecast>?, response: Response<FullForecast>?) {
if (response != null && response.isSuccessful && response.body() != null) {
forecastObj = response.body() as FullForecast
// Try to get Json string here
}
}
})
#JsonClass(generateAdapter = true)
data class FullForecast(#Json(name = "list")
val forecastList: List<WeatherForecast>) {
}
#JsonClass(generateAdapter = true)
data class WeatherForecast(#Json(name = "main")
val weatherDetail: WeatherDetail,
#Json(name = "weather")
val weatherIcon: List<WeatherIcon>,
#Json(name = "dt_txt")
val date: String) {
}
#JsonClass(generateAdapter = true)
data class Place(#Json(name = "main")
val weatherDetail: WeatherDetail,
#Json(name = "weather")
val weatherIcon: List<WeatherIcon>,
#Json(name = "sys")
val countryDetail: CountryDetail,
#Json(name = "dt_txt")
var forecastDate: String = "",
val name: String,
var placeIdentifier: String = "",
var lastUpdated: String = "") {
}
#JsonClass(generateAdapter = true)
data class CountryDetail(val country: String) {
}
#JsonClass(generateAdapter = true)
data class WeatherDetail(#Json(name = "temp")
val temperature: Double,
val temp_min: Double,
val temp_max: Double) {
}
#JsonClass(generateAdapter = true)
data class WeatherIcon(val icon: String) {
}
You should implement Parcelize as below
#Parcelize
#JsonClass(generateAdapter = true)
data class FullForecast(#Json(name = "list")
val forecastList: List<WeatherForecast>) : Parcelable {
}
#Parcelize
#JsonClass(generateAdapter = true)
data class WeatherForecast(#Json(name = "main")
val weatherDetail: WeatherDetail,
#Json(name = "weather")
val weatherIcon: List<WeatherIcon>,
#Json(name = "dt_txt")
val date: String) : Parcelable {
}
#Parcelize
#JsonClass(generateAdapter = true)
data class Place(#Json(name = "main")
val weatherDetail: WeatherDetail,
#Json(name = "weather")
val weatherIcon: List<WeatherIcon>,
#Json(name = "sys")
val countryDetail: CountryDetail,
#Json(name = "dt_txt")
var forecastDate: String = "",
val name: String,
var placeIdentifier: String = "",
var lastUpdated: String = "") : Parcelable {
}
#Parcelize
#JsonClass(generateAdapter = true)
data class CountryDetail(val country: String) : Parcelable {
}
#Parcelize
#JsonClass(generateAdapter = true)
data class WeatherDetail(#Json(name = "temp")
val temperature: Double,
val temp_min: Double,
val temp_max: Double) : Parcelable {
}
#Parcelize
#JsonClass(generateAdapter = true)
data class WeatherIcon(val icon: String) : Parcelable {
}
If you face error:
This is a known bug in the IDE itself and you can ignore it, there’s nothing wrong with the code and it works as expected. You can keep track of the issue here.
Try EventBus to pass objects to fragments.
Follow this
Step 1:
make your object implements Serializable
ex.public class Match implements Serializable {
}
step 2: put your object to bundle and pass it to Activity or Fragment
ex.
Bundle args = new Bundle();
args.putSerializable("ARG_PARAM1", yourObject);
step 3: get your object form bundle like this
yourObj = (Match) getArguments().getSerializable(ARG_PARAM1);