I have a get request that returns certain features where 11 properties of the objects are common. Since data classes in Kotlin can't inherit from other classes i decided to define the common properties with the following interface.
interface AccountFeature {
val feature: String?
val status: String?
val id: String?
val urlLogo: String?
val minAppVersion: String?
val target: String?
val title: String?
val backgroundColor: String?
val bodyTextColor: String?
val bodyText: String?
val titleTextColor: String?
}
One of the data classes look like this.
data class AccountFeatureHelp(val privacyStatement: String? = null,
val supportFAQ: String? = null,
val termsOfService: String? = null,
val supportHotline: String? = null,
val supportEmail: String? = null,
override val feature: String?,
override val status: String?,
override val id: String?,
override val urlLogo: String?,
override val minAppVersion: String?,
override val target: String?,
override val title: String?,
override val backgroundColor: String?,
override val bodyTextColor: String?,
override val bodyText: String?,
override val titleTextColor: String?): AccountFeature
So far everthing is fine.
In the Interface definition of my Request, i expect an observable array of AccountFeature. My goal is depending on the feature value, mapping the hashmap to corresponding Feature object.
interface AccountFeaturesAPIService {
#GET("accounts/{id}/features")
fun getAccountFeature(#Path("id") id: String): Observable<Array<AccountFeature>>
}
I get the following runtime exception.
java.lang.RuntimeException: Unable to invoke no-args constructor for interface com.thinxnet.native_tanktaler_android.core.model.account.feature.AccountFeature. Registering an InstanceCreator with Gson for this type may fix this problem.
How would i overcome this in an elegant way apart from changing Observable> to Observable>
Related
Im trying to implement diffutil in my adapter and im getting the following error:
One type argument expected for class Result<out T>
This is the code where i get the error:
private val diffCallback = object: DiffUtil.ItemCallback<Result>() {
}
This is my Result class:
data class Result(
val adult: Boolean,
val backdrop_path: String,
val genre_ids: List<Int>,
val id: Int,
val media_type: String,
val original_language: String,
val original_title: String,
val overview: String,
val popularity: Double,
val poster_path: String,
val release_date: String,
val title: String,
val video: Boolean,
val vote_average: Double,
val vote_count: Int
)
I don't understand,this is exactly how i do this every time,and it works without problems
Kotlin already has a Result<T> type, and it's imported by default. You might need to fully qualify your own class name if you want to make sure you're using that one. Or maybe just rename your class, it will make things easier.
Issue Basics
ObjectBox version 2.5.1
Reproducibility: [always]
Hi, I am getting this error everytime I want to load my Object even though on saving I checked in the debugger and see that the relation target is not null and everything is saved correctly.
I am having those trhee entity classes
#Entity
data class NetflixCache (
val results: List<NetflixSearchResult>,
#Id var objectBoxId: Long?
) {
var searchParams: ToOne<SearchParams> = ToOne<SearchParams>(this, NetflixCache_.searchParams)
}
#Entity
data class SearchParams(val genrelist: String,
val type: String,
val imdbRatingMin: String,
val countryId: String,
val startYear: Int,
val endYear: Int,
val offset: Int? = 0,
val timeStamp: Long,
#Id var id: Long? = null)
#Entity
data class NetflixSearchResult (
val vtype: String?,
val img: String?,
val nfid: Long?,
val imdbid: String?,
val title: String?,
val clist: String?,
val poster: String?,
val imdbrating: Double?,
val synopsis: String?,
val titledate: Date?,
val year: Int?,
var id: Long,
#Id var objectBoxId: Long?
)
Using this code to save:
val cacheBox = LetsFlixApplication.boxStore.boxFor(NetflixCache::class.java)
val netflixCache = NetflixCache(searchResults, null)
netflixCache.searchParams.target = searchParams
cacheBox.put(netflixCache)
And this code to load:
val cachedResult = cacheBox.all //<-Exception is thrown here
As you can see in debugger when saving, ToOne Object is NOT null:
https://ibb.co/s3tdhqP
This is the exact exception message I am getting:
ToOne object is null inside com.haenles.letsflix.domain.NetflixCache
Issue for me was that data class was missing default values as recommended in the doc:
#Entity
data class User(
#Id var id: Long = 0,
var name: String? = null
)
I'm trying to build custom deserializers for the responses I get from OMDb API.
Here's the data class for Movie:
data class Movie(
val title: String?,
val year: String?,
val imdbID: String?,
val type: String?,
val poster: String?,
val mpaRating: String?,
val runtime: String?,
val genres: String?,
val director: String?,
val writers: List<String>?,
val actors: List<String>?,
val plot: String?,
val awards: String?,
val boxOfficeEarnings: String?,
val ratings: List<Rating>,
val response: Boolean?
)
And for Rating:
data class Rating(
#SerializedName("Source")
val source: String,
#SerializedName("Value")
val value: String
)
This is the custom JsonDeserializer so far:
class MovieDeserializer : JsonDeserializer<Movie>
{
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): Movie
{
val movieJsonObject = json?.asJsonObject
return Movie(
movieJsonObject?.get("Title")?.asString,
movieJsonObject?.get("Year")?.asString,
movieJsonObject?.get("imdbID")?.asString,
movieJsonObject?.get("Type")?.asString,
movieJsonObject?.get("Poster")?.asString,
movieJsonObject?.get("Rated")?.asString,
movieJsonObject?.get("Runtime")?.asString,
movieJsonObject?.get("Genre")?.asString,
movieJsonObject?.get("Director")?.asString,
separateStringByComma(movieJsonObject?.get("Writer")?.asString),
separateStringByComma(movieJsonObject?.get("Actors")?.asString),
movieJsonObject?.get("Plot")?.asString,
movieJsonObject?.get("Awards")?.asString,
movieJsonObject?.get("BoxOffice")?.asString,
// this is where I need help,
movieJsonObject?.get("Response")?.asBoolean
)
}
fun separateStringByComma(stringToSeparate: String?): List<String>?
{
return stringToSeparate?.split(", ")
}
}
How can I convert that JsonElement directly to List<Rating> without some json string manipulation?
By the way, I'm using Retrofit with Gson:
val gsonMovieDeserializer = GsonBuilder()
.registerTypeAdapter(Movie::class.java, MovieDeserializer())
.create()
val retrofit = Retrofit.Builder()
.baseUrl("https://www.omdbapi.com/")
.addConverterFactory(GsonConverterFactory.create(gsonMovieDeserializer))
.build()
val omdbApi = retrofit.create(OmdbApi::class.java)
val movie = omdbApi.getMovie(movieImdbId.value.toString())
First of all, I'd like to point the usage of nullables there: instead of checking wheter movieJsonObject is null or not for every call inside deserialize(), you should change the function parameters not to be null and then check only once, right at the beggining, if json is a JsonObject, just skipping everything if it's not. That way, we have a solid base to extract the data. Also, for the Movie data class, check the API documentation for which fields are optional and only set those to nulalble (I'm pretty sure at least the title and ID there are always present, so it's way more useful to have them as non-nullable).
Now, for the question itself, you should probably be able to deserialize that list using context.deserialize<List<Rating>>(movieJsonObject.get("Ratings"), List::class.java), which, in Kotlin, will return a type-safe List<Rating> (but, again, make sure that's not an optional field in the API and, if it is, make it nullable).
How to create constructor for data class in Kotlin Android ?
data class EventItem(
#SerializedName("dateEvent")
val dateEvent: String,
#SerializedName("dateEventLocal")
val dateEventLocal: Any,
#SerializedName("idAwayTeam")
val idAwayTeam: String,
#SerializedName("idEvent")
val idEvent: String,
#SerializedName("idHomeTeam")
val idHomeTeam: String,
#SerializedName("idLeague")
val idLeague: String,
#SerializedName("idSoccerXML")
val idSoccerXML: String,
#SerializedName("intAwayScore")
val intAwayScore: Any,
#SerializedName("intAwayShots")
val intAwayShots: Any,
#SerializedName("intHomeScore")
val intHomeScore: Any,
#SerializedName("intHomeShots")
val intHomeShots: Any,
#SerializedName("intRound")
val intRound: String,
#SerializedName("intSpectators")
val intSpectators: Any,
#SerializedName("strAwayFormation")
val strAwayFormation: Any,
#SerializedName("strAwayGoalDetails")
val strAwayGoalDetails: String,
#SerializedName("strAwayLineupDefense")
val strAwayLineupDefense: String,
#SerializedName("strAwayLineupForward")
val strAwayLineupForward: String,
#SerializedName("strAwayLineupGoalkeeper")
val strAwayLineupGoalkeeper: String,
#SerializedName("strAwayLineupMidfield")
val strAwayLineupMidfield: String,
#SerializedName("strAwayLineupSubstitutes")
val strAwayLineupSubstitutes: String,
#SerializedName("strAwayRedCards")
val strAwayRedCards: String,
#SerializedName("strAwayTeam")
val strAwayTeam: String,
#SerializedName("strAwayYellowCards")
val strAwayYellowCards: String,
#SerializedName("strBanner")
val strBanner: Any,
#SerializedName("strCircuit")
val strCircuit: Any,
#SerializedName("strCity")
val strCity: Any,
#SerializedName("strCountry")
val strCountry: Any,
#SerializedName("strDate")
val strDate: String,
#SerializedName("strDescriptionEN")
val strDescriptionEN: Any,
#SerializedName("strEvent")
val strEvent: String,
#SerializedName("strEventAlternate")
val strEventAlternate: String,
#SerializedName("strFanart")
val strFanart: Any,
#SerializedName("strFilename")
val strFilename: String,
#SerializedName("strHomeFormation")
val strHomeFormation: Any,
#SerializedName("strHomeGoalDetails")
val strHomeGoalDetails: String,
#SerializedName("strHomeLineupDefense")
val strHomeLineupDefense: String,
#SerializedName("strHomeLineupForward")
val strHomeLineupForward: String,
#SerializedName("strHomeLineupGoalkeeper")
val strHomeLineupGoalkeeper: String,
#SerializedName("strHomeLineupMidfield")
val strHomeLineupMidfield: String,
#SerializedName("strHomeLineupSubstitutes")
val strHomeLineupSubstitutes: String,
#SerializedName("strHomeRedCards")
val strHomeRedCards: String,
#SerializedName("strHomeTeam")
val strHomeTeam: String,
#SerializedName("strHomeYellowCards")
val strHomeYellowCards: String,
#SerializedName("strLeague")
val strLeague: String,
#SerializedName("strLocked")
val strLocked: String,
#SerializedName("strMap")
val strMap: Any,
#SerializedName("strPoster")
val strPoster: Any,
#SerializedName("strResult")
val strResult: Any,
#SerializedName("strSeason")
val strSeason: String,
#SerializedName("strSport")
val strSport: String,
#SerializedName("strTVStation")
val strTVStation: Any,
#SerializedName("strThumb")
val strThumb: Any,
#SerializedName("strTime")
val strTime: String,
#SerializedName("strTimeLocal")
val strTimeLocal: String,
#SerializedName("strTweet1")
val strTweet1: Any,
#SerializedName("strTweet2")
val strTweet2: Any,
#SerializedName("strTweet3")
val strTweet3: Any,
#SerializedName("strVideo")
val strVideo: Any
) {
constructor(
idEvent: String,
strEvent: String,
strDate: String,
idHomeTeam: String,
strHomeTeam: String,
intHomeScore: Any,
idAwayTeam: String,
strAwayTeam: String,
intAwayScore: Any
) : this(idEvent, strEvent, strDate, idHomeTeam, strHomeTeam, intHomeScore, idAwayTeam, strAwayTeam, intAwayScore)
}
screenshot : https://i.stack.imgur.com/riGkU.png
How to create constructor for data class in Kotlin Android ?
i've try to create constructor. But, i get "There's a cycle in the delegation calls chain"
please, correct my code and tell me solution for it. . .
For a data class, the constructor defined in the class header is the primary constructor. It can't delegate to any other constructor in that class (though it can delegate to a superclass constructor).
However, you can define secondary constructors in the body of the class, as long as those delegate to the primary constructor. For example:
data class EventItem(val dateEvent: String) {
constructor(date: Date) : this(date.toString())
}
The problem in the code you've posted is that your secondary constructor is trying to delegate back to itself. You have to delegate to the primary constructor instead, and that means you need to be able to determine a value for all of the parameters missing from the secondary constructor.
Hi I am using gson library to map values of response to model. I am doing it like this but it is not mapping values of response to model. I am getting list of 50 models but values in it is zero.
#Provides
#Singleton
fun provideRestApiHelper(
okHttpClient: OkHttpClient,
gson: Gson,
rxJava2CallAdapterFactory: RxJava2CallAdapterFactory): RestApi {
val builder = Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addCallAdapterFactory(rxJava2CallAdapterFactory)
.addConverterFactory(GsonConverterFactory.create(gson))
val retrofit = builder.client(okHttpClient).build()
return retrofit.create(RestApi::class.java)
}
RestApi.kt
interface RestApi {
#GET(ApiEndPoint.ENDPOINT_GITHUB_JOBS)
fun getJobsApiCall(): Observable<List<JobsResponse>>
}
ApiHelperImpl.kt
class ApiHelperImpl #Inject constructor(private val restApi: RestApi) : ApiHelper {
override fun getJobsApiCall(): Observable<List<JobsResponse>> {
return restApi.getJobsApiCall()
}
}
JobsResponse.kt
data class JobsResponse(
#field:SerializedName("company_logo")
val companyLogo: String?,
#field:SerializedName("how_to_apply")
val howToApply: String?,
#field:SerializedName("created_at")
val createdAt: String?,
#field:SerializedName("description")
val description: String?,
#field:SerializedName("location")
val location: String?,
#field:SerializedName("company")
val company: String?,
#field:SerializedName("company_url")
val companyUrl: String?,
#field:SerializedName("id")
val id: String?,
#field:SerializedName("title")
val title: String?,
#field:SerializedName("type")
val type: String?,
#field:SerializedName("url")
val url: String?
) : BaseResponse()
I am calling this API https://jobs.github.com/positions.json. Does anyone know what could be the issue ?
That's because you rely on auto-converted java code
remove #field:SerializedName changed it to #SerializedName
don't put them in to primary constructor
define them like this:
data class JobsResponse(){
#SerializedName("company_logo")
val companyLogo: String? = null
....
}