Titanium Appcelerator; CommonJS has no method - titanium

I'm pretty new to Appcelerator and I tried to import my own commonJS Library. I followed the instructions on
http://docs.appcelerator.com/titanium/latest/#!/guide/CommonJS_Modules_in_Titanium
and created a new file named "logger.js", with the following code:
exports.info = function(str) {
Titanium.API.info(new Date()+': '+str);
};
Now I simply try so exceute this code with:
var logger = require('logger');
logger.info('TEST TEST TEST');
Just like in the example. He found the the file, but didn't recognize my method and I get the following exception:
[ERROR] : TiExceptionHandler: (main) [602,602] ----- Titanium Javascript Runtime Error -----
[ERROR] : TiExceptionHandler: (main) [0,602] - In alloy/controllers/index.js:100,12
[ERROR] : TiExceptionHandler: (main) [0,602] - Message: Uncaught TypeError: Object function Controller() {
[ERROR] : TiExceptionHandler: function logOutput(str) {
[ERROR] : TiExceptionHandler: Titanium.API.info(str);
[ERROR] : TiExceptionHandler: }
[ERROR] : TiExceptionHandler: require("alloy/controllers/BaseController").apply(this, Array.prototype.slice.call(arguments));
[ERROR] : TiExceptionHandler: this.__controllerPath = "login";
[ERROR] : TiExceptionHandler: if (arguments[0]) {
[ERROR] : TiExceptionHandler: __processArg(arguments[0], "__parentSymbol");
[ERROR] : TiExceptionHandler: __processArg(arguments[0], "$model");
[ERROR] : TiExceptionHandler: __processArg(arguments[0], "__itemTemplate");
[ERROR] : TiExceptionHandler: }
[ERROR] : TiExceptionHandler: var $ = this;
[ERROR] : TiExceptionHandler: var exports = {};
[ERROR] : TiExceptionHandler: exports.destroy = function() {};
[ERROR] : TiExceptionHandler: _.extend($, $.__views);
[ERROR] : TiExceptionHandler: exports = logOutput;
[ERROR] : TiExceptionHandler: _.extend($, exports);
[ERROR] : TiExceptionHandler: } has no method 'info'
[ERROR] : TiExceptionHandler: (main) [1,603] - Source: logger.info("TEST TEST TEST");
[ERROR] : V8Exception: Exception occurred at alloy/controllers/index.js:100: Uncaught TypeError: Object function Controller() {
[ERROR] : V8Exception: function logOutput(str) {
[ERROR] : V8Exception: Titanium.API.info(str);
[ERROR] : V8Exception: }
[ERROR] : V8Exception: require("alloy/controllers/BaseController").apply(this, Array.prototype.slice.call(arguments));
[ERROR] : V8Exception: this.__controllerPath = "login";
[ERROR] : V8Exception: if (arguments[0]) {
[ERROR] : V8Exception: __processArg(arguments[0], "__parentSymbol");
[ERROR] : V8Exception: __processArg(arguments[0], "$model");
[ERROR] : V8Exception: __processArg(arguments[0], "__itemTemplate");
[ERROR] : V8Exception: }
[ERROR] : V8Exception: var $ = this;
[ERROR] : V8Exception: var exports = {};
[ERROR] : V8Exception: exports.destroy = function() {};
[ERROR] : V8Exception: _.extend($, $.__views);
[ERROR] : V8Exception: exports = logOutput;
[ERROR] : V8Exception: _.extend($, exports);
[ERROR] : V8Exception: } has no method 'info'
I guess it's so simple but I don't where is my fault.
thanks in advance

The code you showed works for me. Did you create the logger.js in the app/lib directory?
Perhaps you should try to comment out the logger.info(...) line in index.js just to ensure that you are looking at the right problem ;-)
Which version of Titanium Studio are you using? - and on which OS?
/John

It is better exports Main Object and access info function (Titanium Good Practices).
logger.js
var logger = (function(){
var self = {};
self.info = function info(str)
{
Ti.API.info(new Date()+': '+str);
};
return self;
}());
module.exports = logger;
file.js where you need logger
var loggerObject = require('logger.js'); // (both files are at the same Path)
loggerObject.info("TEST TEST");
I hope my answer helps you ;)

Normally we used to put this type of extra functions files under lib directory so you should create one folder and named it lib under app directory and put logger.js file under that folder and try again.

Finaly I got it. The problems were I'm using an "Alloy Project", just like "Alejandro F. Carrera" mentioned it. I simply have to use Alloy.createController(); to get it work.
var logger = Alloy.createController('logger');
logger.info('TEST TEST TEST');
now it work.
Thanks to all of you to pointing me to the right direction

Related

Kotlin `use` with AutoCloseable type and a lambda returning Boolean

This must be simple, but I've been banging my head against it for half an hour now... Here's my old, exception-unsafe code:
fun isReady(): Boolean {
try {
val cc: CommandChannel = getCommandChannel() // implements AutoCloseable
cc.writeMessage("blahblah")
val response = cc.readMessage() // might throw
cc.close()
if (response.error == null) {
return true
}
} catch (e: ChannelConnectionException) {
}
return false
}
I'd like to rewrite it to use use, something like this:
fun isReady(): Boolean {
getCommandChannel().use {
try {
it.writeMessage("blahblah")
if (it.readMessage().error == null) {
return true
}
} catch (e: ChannelConnectionException) {
}
return false
}
}
But Kotlin gives me an error:
[ERROR] X.kt:[108,29] Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
[ERROR] #InlineOnly public inline fun <T : Closeable?, R> ???.use(block: (???) -> ???): ??? defined in kotlin.io
[ERROR] X.kt:[110,17] Unresolved reference: it
[ERROR] X.kt:[111,21] Unresolved reference: it
[ERROR] X.kt:[112,21] 'return' is not allowed here
[ERROR] X.kt:[116,13] 'return' is not allowed here
[ERROR] X.kt:[118,5] A 'return' expression required in a function with a block body ('{...}')
[ERROR] -> [Help 1]
Or, I say "okay I don't understand terse lambda syntax, let me use fun," and I try this:
fun isReady(): Boolean {
return getCommandChannel().use(fun(cc: CommandChannel): Boolean {
try {
cc.writeMessage("blahblah")
if (cc.readMessage().error == null) {
return true
}
} catch (e: ChannelConnectionException) {
}
return false
})
}
Kotlin still complains:
[ERROR] X.kt:[108,36] Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
[ERROR] #InlineOnly public inline fun <T : Closeable?, R> ???.use(block: (???) -> Boolean): Boolean defined in kotlin.io
[ERROR]
[ERROR] -> [Help 1]
My current guess is that the problem is that the CommandChannel I'm trying to use implements AutoCloseable instead of Closeable... but I don't know what I'm supposed to do about that! (Is there some sort of adaptor I need to wrap it in, maybe?) Fundamentally, I just want to make sure that cc's close method gets called correctly at the end of cc's scope, so that I'm not leaking connections.
If you look at the Kotlin source,
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R
is available in kotlin-stdlib package (source), whereas
public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R
is available in kotlin-stdlib-jdk7(source) package.
So, the error that you get :
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
[ERROR] #InlineOnly public inline fun <T : Closeable?, R> ???.use(block: (???) -> Boolean): Boolean defined in kotlin.io
indicates that since CommandChannel implements AutoCloseable and not Closeable, the use function appropriate to that is not available in your project. Try adding the dependency of kotlin-stdlib-jdk8 or kotlin-stdlib-jdk7 and you should then be able to use .use{} for CommandChannel.

Why Ktor Post Request freeze app, but Get doesn't freeze it?

suspend fun main(args: Array<String>) {
val client = HttpClient(CIO)
embeddedServer(Netty, 6001) {
routing {
get("/") {
println(call.request.toLogString())
call.respondText("Please use POST method", status = HttpStatusCode.BadRequest)
}
post("/") {
call.respondText("{}")
val params = call.receiveText()
println(params)
delay(200)
println("pre response")
val response2: HttpResponse = client.post("https://google.com")
println(response2.status)
val response: HttpResponse = client.post("https://discord.com/api/webhooks/discord/webhookurl") {
body = "{\"content\": \"$params\"}"
}
println("after")
println("response: ${response.receive<String>()}")
}
}
}.start(true)
}
This code print to console:
{"test":"test"}
pre response
and app freezed.
If I attempt to send GET requests to google or discord, this working and don't freezing.
Why?
Post request to google.com throws an exception:
client.post("https://google.com")
If you see this warning in your logs:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Then you should add slf4j dependency to your project to enable logging:
implementation("org.slf4j:slf4j-simple:(version)")
After that you will see full stacktrace of your error in your server logs:
[eventLoopGroupProxy-4-1] ERROR ktor.application - Unhandled: POST - /
io.ktor.client.features.ClientRequestException:
Client request(https://google.com/) invalid: 405 Method Not Allowed.
...
...

java.time.format.DateTimeParseException: Text '2020-12-04T16:00:00.432597+02:00

class DateUtil {
companion object {
const val DATE_TIME_XML_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"
fun stringToLocalDateTime(dateTimeAsString : String, dateTimeFormat : String) : LocalDateTime {
return LocalDateTime.parse(dateTimeAsString, DateTimeFormatter.ofPattern(dateTimeFormat))
}
}
But I get error when try to parse text "2020-12-04T16:00:00.432597+02:00"
15:39:16.858 [qtp192428201-24] INFO com.myproject- importOrder: availableUntil = "2020-12-04T16:00:00.432597+02:00"
15:39:16.863 [qtp192428201-24] WARN io.javalin.Javalin - Uncaught exception
java.time.format.DateTimeParseException: Text '2020-12-04T16:00:00.432597+02:00' could not be parsed, unparsed text found at index 19
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2049)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
at .DateUtil$Companion.stringToLocalDateTime(DateUtil.kt:30)
For this exact input 2020-12-04T16:00:00.432597+02:00 you should use following pattern
yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX

How to solver error for kotlin coroutines flow?

I tried to use NetworkBoundResource for my MVVM Model and after i follow some tutorial, i'm having an error look this
10-21 14:15:04.073 31376-31376/com.example.mvvmsecondmodel E/Process: android_os_Process_getProcessNameByPid pid is 31376
10-21 14:15:04.074 31376-31376/com.example.mvvmsecondmodel E/Process: android_os_Process_getProcessNameByPid value is mvvmsecondmodel
10-21 14:15:04.416 31376-31421/com.example.mvvmsecondmodel E/SQLiteLog: (283) recovered 8 frames from WAL file /data/data/com.example.mvvmsecondmodel/databases/movie_db-wal
10-21 14:15:04.640 31376-31376/com.example.mvvmsecondmodel E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.mvvmsecondmodel, PID: 31376
java.lang.IllegalArgumentException: Unable to create call adapter for kotlinx.coroutines.flow.Flow<com.example.mvvmsecondmodel.data.respository.ApiResponse<com.example.mvvmsecondmodel.data.model.MovieResponse$Movie>>
for method ApiService.getMyMovie
at retrofit2.Utils.methodError(Utils.java:52)
at retrofit2.HttpServiceMethod.createCallAdapter(HttpServiceMethod.java:105)
at retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:66)
at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:37)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:170)
at retrofit2.Retrofit$1.invoke(Retrofit.java:149)
at java.lang.reflect.Proxy.invoke(Proxy.java:397)
at $Proxy0.getMyMovie(Unknown Source)
at com.example.mvvmsecondmodel.data.remote.ApiService$DefaultImpls.getMyMovie$default(ApiService.kt:11)
at com.example.mvvmsecondmodel.data.respository.MovieRespository$getListMovie$$inlined$networkBoundResource$1.invokeSuspend(NetworkBoundResource.kt:49)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:55)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for kotlinx.coroutines.flow.Flow<com.example.mvvmsecondmodel.data.respository.ApiResponse<com.example.mvvmsecondmodel.data.model.MovieResponse$Movie>>.
Tried:
* retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
* retrofit2.DefaultCallAdapterFactory
at retrofit2.Retrofit.nextCallAdapter(Retrofit.java:241)
at retrofit2.Retrofit.callAdapter(Retrofit.java:205)
at retrofit2.HttpServiceMethod.createCallAdapter(HttpServiceMethod.java:103)
... 14 more
At first i thought there's red sign at my code so i checked ApiService and Respository class and nothing wrong cause i already follow the tutorial
ApiService:
interface ApiService {
#GET("3/movie/popular")
fun getMyMovie(#Query("api_key") api : String = "32bbbffe944d16d1d2a3ee46cfc6aaa0"
) : Flow<ApiResponse<MovieResponse.Movie>>
}
MovieRespository:
class MovieRespository (val apiService: ApiService, val movieDao: MovieDao) {
fun getListMovie() : Flow<Resource<Movie>> {
return networkBoundResource(
fetchFromLocal = { movieDao.getMyMovie() },
shouldFetchFromRemote = {true},
fetchFromRemote = {apiService.getMyMovie()},
processRemoteResponse = {},
saveRemoteData = {movieDao.insert(
it.results.let {
it.map { data -> Movie.from(data) }
}
)},
onFetchFailed = {_, _ ->}
).flowOn(Dispatchers.IO)
}
You should define your api service as suspend function.
Api Service:
interface ApiService {
#GET("3/movie/popular")
suspend fun getMyMovie(#Query("api_key") api : String = "32bbbffe944d16d1d2a3ee46cfc6aaa0"
) : ApiResponse<MovieResponse.Movie>
}
Movie Repository:
class MovieRepository (val apiService: ApiService, val movieDao: MovieDao) {
fun getListMovie() : Flow<Resource<Movie>> {
return flow {
// do your networkBoundResource functions
}.flowOn(Dispatchers.IO)
}
I can't test the code because you didn't share your NetworkBoundResource class. I hope the code help to fix your problem.

kotlin - type inference and type mismatch when updating kotlin version

I'm having some difficulties trying to understand what is going on the following code:
fun helperMethodNameA(someId: String, rules: RulesObject) {
val content = JsonNodeFactory.instance.arrayNode().apply { // A & B
add(JsonNodeFactory.instance.objectNode().apply {
set("body", JsonNodeFactory.instance.objectNode().apply { // C
set("text", JsonNodeFactory.instance.objectNode().apply { // D
set("value", JsonNodeFactory.instance.textNode(mapper.writeValueAsString(rules))) // E
})
})
})
}
return helperMethodNameB(someId, content.toString())
}
This project has a dependency on another which set Kotlin v1.3.20. The dependency project had the Kotlin version bumped up to v1.3.60. This bit broke with the update as per the following:
A - [ERROR] <pathToFile> [line, position] Type inference failed: inline fun <T> T.apply(block: T.() -> Unit): T
[ERROR] cannot be applied to
[ERROR] receiver: ArrayNode! arguments: (ArrayNode!.() -> ArrayNode!)
B - [ERROR] <pathToFile> [line, position] Type mismatch: inferred type is ArrayNode!.() -> ArrayNode! but ArrayNode!.() -> Unit was expected
C - [ERROR] <pathToFile> [line, position] Type inference failed: Not enough information to infer parameter T in operator fun <T : JsonNode!> set(p0: String!, p1: JsonNode!): T!
[ERROR] Please specify it explicitly.
D - [ERROR] <pathToFile> [line, position] Type inference failed: Not enough information to infer parameter T in operator fun <T : JsonNode!> set(p0: String!, p1: JsonNode!): T!
[ERROR] Please specify it explicitly.
E - [ERROR] <pathToFile> [line, position] Type inference failed: Not enough information to infer parameter T in operator fun <T : JsonNode!> set(p0: String!, p1: JsonNode!): T!
[ERROR] Please specify it explicitly.
What am I missing here?
The solution was to specify the type as bellow:
fun helperMethodNameA(someId: String, rules: RulesObject) {
val content = JsonNodeFactory.instance.arrayNode().apply {
add(JsonNodeFactory.instance.objectNode().apply {
set<ObjectNode>("body", JsonNodeFactory.instance.objectNode().apply {
set<ObjectNode>("text", JsonNodeFactory.instance.objectNode().apply {
set<TextNode>("value", JsonNodeFactory.instance.textNode(mapper.writeValueAsString(rules)))
})
})
})
}
return helperMethodNameB(someId, content.toString())
}