Why initialData() Realm is never called when setting up configuration? - kotlin

First, I would like to ask you, if you think that this question deserves -1, be honest enough and please explain why.
This is the code for Application class:
class WeatherApp: Application() {
override fun onCreate() {
super.onCreate()
Realm.init(this)
Realm.setDefaultConfiguration(
RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.initialData(DatabaseInitTransaction(applicationContext))
.build()
)
}
}
This is the transaction class:
class DatabaseInitTransaction(private val applicationContext: Context): Realm.Transaction {
override fun execute(realm: Realm) {
Log.d("DatabaseInitTransaction", "execute called.")
val cityDao = CityDao(realm)
realm.deleteAll()
var stream :InputStream? = null
try {
stream = applicationContext.assets.open("city.list.json")
cityDao.createAllFromJson(CityEntity::class.java, stream)
} catch (thr: Throwable) {
} finally {
stream?.close()
}
}
}
So, on cold start method execute() of DatabaseInitTransaction class is never get called. I could not figure out why, please, help!

You must check first your Custom Applicatiom Class name is written in Manifest file.
in
<Application>
tag with Class name

Related

Configuring graphqlServlet with Jetty Server

Getting below compilation error while adding servlet mapping. Not Sure what is wrong with below code while adding graphqlServlet to handler.
Compilation error- None of the following functions can be called
with the arguments supplied.
(Servlet!) defined in org.eclipse.jetty.servlet.ServletHolder
(Class<out Servlet!>!) defined in org.eclipse.jetty.servlet.ServletHolder
(Source!) defined in org.eclipse.jetty.servlet.ServletHolder
GraphQLServlet.kt
class GraphQLServlet(schemaBuilder: SchemaBuilder) : SimpleGraphQLHttpServlet() {
private val schema = schemaBuilder.buildSchema()
public override fun doPost(request: HttpServletRequest?, response: HttpServletResponse?) {
super.doPost(request, response)
}
public override fun getConfiguration(): GraphQLConfiguration {
return GraphQLConfiguration.with(schema)
.with(GraphQLQueryInvoker.newBuilder().build())
.build()
}
}
Jetty.kt
class API {
fun start() {
val handler = createHandler()
Server(8080).apply {
setHandler(handler)
start()
}
}
private fun createHandler(): WebAppContext {
val schemaBuilder = MyApiSchemaBuilder();
val graphqlServlet : Servlet =GraphQLServlet(schemaBuilder)
val handler = ServletHandler()
return WebAppContext().apply {
setResourceBase("/")
handler.addServletWithMapping(ServletHolder(graphqlServlet), "/graphql")
}
}
}
handler.addServletWithMapping(ServletHolder(graphqlServlet),
"/graphql")
I am able to figure out. i have added jetty-servlet in my dependency which solved my purpose

How can I override onCurrentListChanged of ListAdapter with Kotlin?

I hope to override onCurrentListChanged of ListAdapter, but Code A doesn't work, how can I fix it?
Code A
myAdapter.onCurrentListChanged(){previousList, currentList ->
}
Added Content
To Alexey Romanov: Thanks!
Code C can work well, but Code D by your answer can not work, what error is there?
Code C
private val myAdapter by lazy{
VoiceAdapters(mHomeViewModel,mPlay)
}
Code D
private val myAdapter by lazy{
VoiceAdapters(mHomeViewModel,mPlay) {
override fun onCurrentListChanged(previousList: MutableList<MVoice>, currentList: MutableList<MVoice>) {
}
}
Both
class VoiceAdapters (private val aHomeViewModel: HomeViewModel, private val mPlay: PlayInterface):
ListAdapter<MVoice, VoiceAdapters.VoiceViewHolder>(MVoiceDiffCallback()) {
...
}
The code you show looks more like an attempt to call onCurrentListChanged, but
that would be simply myAdapter.onCurrentListChanged(someList1, someList2);
it probably shouldn't be called manually.
To override a method of ListAdapter, you need to do it when defining myAdapter (or whatever class it's an instance of). E.g.
val myAdapter = object : ListAdapter<SomeType> {
override fun onCurrentListChanged(previousList: MutableList<SomeType>, currentList: MutableList<SomeType>) {
...
}
// other overrides
}
See object expressions for the explanation and details of object : ... syntax.
When you already have myAdapter, it's too late, though you could create a new ListAdapter which has its own onCurrentListChanged and delegates to myAdapter for other methods. Kotlin has special support for this pattern for interfaces, but ListAdapter is a class and you'd have to do everything manually:
val myAdapter2 = object : ListAdapter<SomeType> {
override fun onCurrentListChanged(previousList: MutableList<SomeType>, currentList: MutableList<SomeType>) {
...
}
override fun getCurrentList() = myAdapter.getCurrentList()
override fun getItemCount() = myAdapter.getItemCount()
// etc.
}
Code C can work well, but Code D by your answer can not work, what error is there?
It should be
private val myAdapter by lazy {
object : VoiceAdapters(mHomeViewModel,mPlay) {
override fun onCurrentListChanged(previousList: MutableList<MVoice>, currentList: MutableList<MVoice>) {
}
}
}

How can I override logRequest/logResponse to log custom message in Ktor client logging?

Currently, the ktor client logging implementation is as below, and it works as intended but not what I wanted to have.
public class Logging(
public val logger: Logger,
public var level: LogLevel,
public var filters: List<(HttpRequestBuilder) -> Boolean> = emptyList()
)
....
private suspend fun logRequest(request: HttpRequestBuilder): OutgoingContent? {
if (level.info) {
logger.log("REQUEST: ${Url(request.url)}")
logger.log("METHOD: ${request.method}")
}
val content = request.body as OutgoingContent
if (level.headers) {
logger.log("COMMON HEADERS")
logHeaders(request.headers.entries())
logger.log("CONTENT HEADERS")
logHeaders(content.headers.entries())
}
return if (level.body) {
logRequestBody(content)
} else null
}
Above creates a nightmare while looking at the logs because it's logging in each line. Since I'm a beginner in Kotlin and Ktor, I'd love to know the way to change the behaviour of this. Since in Kotlin, all classes are final unless opened specifically, I don't know how to approach on modifying the logRequest function behaviour. What I ideally wanted to achieve is something like below for an example.
....
private suspend fun logRequest(request: HttpRequestBuilder): OutgoingContent? {
...
if (level.body) {
val content = request.body as OutgoingContent
return logger.log(value("url", Url(request.url)),
value("method", request.method),
value("body", content))
}
Any help would be appreciative
No way to actually override a private method in a non-open class, but if you just want your logging to work differently, you're better off with a custom interceptor of the same stage in the pipeline:
val client = HttpClient(CIO) {
install("RequestLogging") {
sendPipeline.intercept(HttpSendPipeline.Monitoring) {
logger.info(
"Request: {} {} {} {}",
context.method,
Url(context.url),
context.headers.entries(),
context.body
)
}
}
}
runBlocking {
client.get<String>("https://google.com")
}
This will produce the logging you want. Of course, to properly log POST you will need to do some extra work.
Maybe this will be useful for someone:
HttpClient() {
install("RequestLogging") {
responsePipeline.intercept(HttpResponsePipeline.After) {
val request = context.request
val response = context.response
kermit.d(tag = "Network") {
"${request.method} ${request.url} ${response.status}"
}
GlobalScope.launch(Dispatchers.Unconfined) {
val responseBody =
response.content.tryReadText(response.contentType()?.charset() ?: Charsets.UTF_8)
?: "[response body omitted]"
kermit.d(tag = "Network") {
"${request.method} ${request.url} ${response.status}\nBODY START" +
"\n$responseBody" +
"\nBODY END"
}
}
}
}
}
You also need to add a method from the Ktor Logger.kt class to your calss with HttpClient:
internal suspend inline fun ByteReadChannel.tryReadText(charset: Charset): String? = try {
readRemaining().readText(charset = charset)
} catch (cause: Throwable) {
null
}

How to override in Kotiln Volley JsonObjectRequest class?

I'm writing a Kotlin app that has a class. I need that class to extend JsonObjectRequest, since I need to override the function
override fun parseNetworkResponse(response: NetworkResponse?): Response<T>
That's because I need to interpret in Kotlin the HTTP response code the server is sending.
However, I admit to being new to Kotlin and haven't managed to figure out how to extend the JsonObjectRequest class. I keep running into silly compiler issues.
Can someone provide a quick example of that?
After a bit of iteration, i managed to finally figure it out. Posting it here since it may be useful to others -
class DataRequest(
method: Int,
uri: String,
jsonObject: JSONObject,
listener: Response.Listener<JSONObject>,
errorListener: Response.ErrorListener
) :
JsonObjectRequest(method, uri, jsonObject, listener, errorListener)
{
override fun parseNetworkResponse(response: NetworkResponse): Response<JSONObject>
{
try
{
val jsonString = String(
response.data,
Charset.forName(HttpHeaderParser.parseCharset(response.headers))
)
return Response.success(
JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response)
)
} catch (e: UnsupportedEncodingException)
{
return Response.error(ParseError(e))
} catch (je: JSONException)
{
return Response.error(ParseError(je))
}
}
}

What is the reason for twitter4j.StreamListner IllegalAccessError in Kotlin?

When implementing a twitter4j.StatusListner in Kotlin, I get the following IllegalAccessError and associated stack trace:
Exception in thread "main" java.lang.IllegalAccessError: tried to access class twitter4j.StreamListener from class rxkotlin.rxextensions.TwitterExampleKt$observe$1
at rxkotlin.rxextensions.TwitterExampleKt$observe$1.subscribe(TwitterExample.kt:50)
at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40)
at io.reactivex.Observable.subscribe(Observable.java:10700)
at io.reactivex.Observable.subscribe(Observable.java:10686)
at io.reactivex.Observable.subscribe(Observable.java:10615)
at rxkotlin.rxextensions.TwitterExampleKt.main(TwitterExample.kt:8)
Produced by the following code:
val twitterStream = TwitterStreamFactory().instance
// See https://stackoverflow.com/questions/37672023/how-to-create-an-instance-of-anonymous-interface-in-kotlin/37672334
twitterStream.addListener(object : StatusListener {
override fun onStatus(status: Status?) {
if (emitter.isDisposed) {
twitterStream.shutdown()
} else {
emitter.onNext(status)
}
}
override fun onException(e: Exception?) {
if (emitter.isDisposed) {
twitterStream.shutdown()
} else {
emitter.onError(e)
}
}
// Other overrides.
})
emitter.setCancellable { twitterStream::shutdown }
If I don't use Rx, it makes the exception a bit simpler:
twitterStream.addListener(object: twitter4j.StatusListener {
override fun onStatus(status: Status) { println("Status: {$status}") }
override fun onException(ex: Exception) { println("Error callback: $ex") }
// Other overrides.
})
Exception in thread "main" java.lang.IllegalAccessError: tried to access class twitter4j.StreamListener from class rxkotlin.rxextensions.TwitterExampleKt
at rxkotlin.rxextensions.TwitterExampleKt.main(TwitterExample.kt:14)
However, if I implement a Java wrapper function, no error is thrown and the behaviour is as expected:
Wrapper -
public class Twitter4JHelper {
public static void addStatusListner(TwitterStream stream, StatusListener listner) {
stream.addListener(listner);
}
}
Revised implementation -
val twitterStream = TwitterStreamFactory().instance
val listner = object: StatusListener {
override fun onStatus(status: Status?) {
if (emitter.isDisposed) {
twitterStream.shutdown()
} else {
emitter.onNext(status)
}
}
override fun onException(e: Exception?) {
if (emitter.isDisposed) {
twitterStream.shutdown()
} else {
emitter.onError(e)
}
}
// Other overrides.
}
Twitter4JHelper.addStatusListner(twitterStream, listner)
emitter.setCancellable { twitterStream::shutdown }
This revised solution comes from a blog post, which I think tries to explain the cause but Google translate is not being my friend. What is causing the IllegalAccessError? Is there a purely Kotlin based solution, or will I have to live with this workaround?
Yep that's not going to work.
addListener method takes a StreamListener param and StreamListener is non-public (package private). I would definitely raise a bug against Kotlin compiler for this.
The code Kotlin compiler generates is:
TwitterStream twitterStream = (new TwitterStreamFactory()).getInstance();
twitterStream.addListener((StreamListener)(new StatusListener() {
// ..overrides ...
}));
StatusListener already implements StreamListener so I don't see why the cast is required.
I worked around this by using a java utility class:
public class T4JCompat {
public static void addStatusListener(TwitterStream stream, StatusListener listener) {
stream.addListener(listener);
}
public static void removeStatusListener(TwitterStream stream, StatusListener listener) {
stream.removeListener(listener);
}
}
You can call these methods from Kotlin and things work as expected.