I Have a file json named production_2.json
[
{
"v":{
"id":"rep_01564526",
"name":"tuttoverde.pgmx",
"type":"PRODUCTION_STARTED",
"ute":"CDL",
"ver":"1.0",
"status":"EXE"
},
"ts":"2020-11-19T08:00:00Z"
},
{
"v":{
"id":"rep_01564526",
"name":"tuttoverde.pgmx",
"type":"PRODUCTION_ENDED",
"ute":"CDL",
"ver":"1.0",
"status":"EXE"
},
"ts":"2020-11-19T17:00:00Z"
}
]
And have the folling Karate code, that:
Read the file production_2.json
and for each element of the array send a topic
I * def sendtopics =
"""
function(i){
var topic = "data." + machineID + ".Production";
var payload = productions[i];
karate.log('topic: ', topic )
karate.log('payload: ', payload )
return mqtt.sendMessage(payload, topic);
}
"""
* def productions = read('this:productions_json/production_2.json')
* def totalProductionEvents = productions.length
* def isTopicWasSent = karate.repeat(totalProductionEvents, sendtopics)
* match each isTopicWasSent == true
The function
mqtt.sendMessage(payload, topic);
is a function in java, that have the following segnature
public Boolean sendMessage(String payload, String topic) {
System.out.println("Publishing message: ");
System.out.println("payload " + payload);
System.out.println("topic " + topic);
return true;
}
the problem is that the value of the "payload" inside the javascript function is correct and is printed correctly, while inside the "sendMessage" function the value of the payload is formatted incorrectly.
For example here is what it prints inside karate.log('payload: ', payload )
payload: {
"v": {
"id": "rep_01564526",
"name": "tuttoverde.pgmx",
"type": "PRODUCTION_STARTED",
"ute": "CDL",
"ver": "1.0",
"status": "EXE"
},
"ts": "2021-01-08T08:00:00Z"
}
And Here instead what is printed on the function "sendMessage" of the java class
payload {v={id=rep_01564526, name=tuttoverde.pgmx, type=PRODUCTION_STARTED, ute=CDL, ver=1.0, status=EXE, ts=2021-01-08T08:00:00Z}
I don't understand why the payload is formatted incorrectly (= instead of : ) and is it not a string. I also tried using the following solution and it doesn't work for me
* def sendtopics =
"""
function(i){
var topic = "data." + machineID + ".Production";
var payload = productions[i];
var payload2 = JSON.stringify(payload);
return mqtt.sendMessage(payload2, topic);
}
"""
How do I convert an object inside javascript to a string so I can pass it to java?
You are doing some really advanced stuff in Karate. I strongly suggest you start looking at the new version (close to release) and you can find details here: https://github.com/intuit/karate/wiki/1.0-upgrade-guide
The reason is because the async and Java interop has some breaking changes - and there are some new API-s you can call on the karate object in JS to do format conversions:
var temp = karate.fromString(payload);
And karate.log() should work better and not give you that odd formatting you are complaining about. With the current version you can try karate.toJson() if that gives you the conversion you expect.
Given your advanced usage, I recommend you start using the new version and provide feedback on anything that may be still needed.
I'm using a screenshot library (in Github) and it is has been written in Kotlin(I don't know Kotlin very well).
<https://github.com/bolteu/screenshotty>
I don't know how to translate to Java a part of code.
in the read me file :
val screenshotResult = screenshotManager.makeScreenshot()
val subscription = screenshotResult.observe(
onSuccess = { processScreenshot(it) },
onError = { onMakeScreenshotFailed(it) }
)
It says that you can get a screenshot object from "it"?
how can I do that?
please help me...
and how can I translate this code to Java :
fun show(screenshot: Screenshot) {
val bitmap = when (screenshot) {
is ScreenshotBitmap -> screenshot.bitmap
}
screenshotPreview.setImageBitmap(bitmap)
}
I'm using ExcelJS to export excel file from JSON, the export works good but I need to add some changes in the excel file likes: color - font - width and etc.
And also I'm asking if I can write in an excel file already customized with a model.
Here is the service :
public exportAsExcelFile(json: any[], excelFileName: string): void {
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(json);
const workbook: XLSX.WorkBook = { Sheets: { data: worksheet }, SheetNames: ['data'] };
const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
this.saveAsExcelFile(excelBuffer, excelFileName);
}
private saveAsExcelFile(buffer: any, fileName: string): void {
const data: Blob = new Blob([buffer], { type: EXCEL_TYPE });
FileSaver.saveAs(data, fileName + '_export_' + EXCEL_EXTENSION);
}
And thats how I call it:
this.excelService.exportAsExcelFile(dealTable, 'deals');
To my knowledge styling is supported in SheetJS Pro.
You can also look into ExcelJS which is not a paid version, but is slightly buggy.
I have a retrofit response like this:
langs: {
af: "Afrikaans",
am: "Amharic",
ar: "Arabic",
az: "Azerbaijani",
ba: "Bashkir",
...
I tried to read it to List<Map<String,String>>but it not works.
Have anyone idea what is the best way to convert this json to object?
Call:
val result = RestAPI.instance.retrofit?.create(TranslateService::class.java)
val call = result?.getLangs("en")
call?.enqueue(object : Callback<LangsResponse>{
override fun onFailure(call: Call<LangsResponse>?, t: Throwable?) {
}
override fun onResponse(call: Call<LangsResponse>?, response: Response<LangsResponse>?) {
}
})
data class LangsResponse(val dirs: List<String>,val langs: List<Map<String,String>>)
langs is a JSON object, so it can be read as a Map<String,String>. If it was an array of objects ([{..},{..}]) it would be List<Map<String,String>>.
Simply adjust the type and it should read properly.
In Android it is possible to use placeholders in strings, such as:
<string name="number">My number is %1$d</string>
and then in Java code (inside a subclass of Activity):
String res = getString(R.string.number);
String formatted = String.format(res, 5);
or even simpler:
String formatted = getString(R.string.number, 5);
It is also possible to use some HTML tags in Android string resources:
<string name="underline"><u>Underline</u> example</string>
Since the String itself cannot hold any information about formatting, one should use getText(int) instead of getString(int) method:
CharSequence formatted = getText(R.string.underline);
The returned CharSequence can be then passed to Android widgets, such as TextView, and the marked phrase will be underlined.
However, I could not find how to combine these two methodes, using formatted string together with placeholders:
<string name="underlined_number">My number is <u>%1$d</u></string>
How to process above resource in the Java code to display it in a TextView, substituting %1$d with an integer?
Finally I managed to find a working solution and wrote my own method for replacing placeholders, preserving formatting:
public static CharSequence getText(Context context, int id, Object... args) {
for(int i = 0; i < args.length; ++i)
args[i] = args[i] instanceof String? TextUtils.htmlEncode((String)args[i]) : args[i];
return Html.fromHtml(String.format(Html.toHtml(new SpannedString(context.getText(id))), args));
}
This approach does not require to escape HTML tags manually neither in a string being formatted nor in strings that replace placeholders.
Kotlin extension function that
works with all API versions
handles multiple arguments
Example usage
textView.text = context.getText(R.string.html_formatted, "Hello in bold")
HTML string resource wrapped in a CDATA section
<string name="html_formatted"><![CDATA[ bold text: <B>%1$s</B>]]></string>
Result
bold text: Hello in bold
Code
/**
* Create a formatted CharSequence from a string resource containing arguments and HTML formatting
*
* The string resource must be wrapped in a CDATA section so that the HTML formatting is conserved.
*
* Example of an HTML formatted string resource:
* <string name="html_formatted"><![CDATA[ bold text: <B>%1$s</B> ]]></string>
*/
fun Context.getText(#StringRes id: Int, vararg args: Any?): CharSequence =
HtmlCompat.fromHtml(String.format(getString(id), *args), HtmlCompat.FROM_HTML_MODE_COMPACT)
<resources>
<string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string>
</resources>
Resources res = getResources();
String text = String.format(res.getString(R.string.welcome_messages), username, mailCount);
CharSequence styledText = Html.fromHtml(text);
More Infos here: http://developer.android.com/guide/topics/resources/string-resource.html
For the simple case where you want to replace a placeholder without number formatting (i.e. leading zeros, numbers after comma) you can use Square Phrase library.
The usage is very simple: first you have to change the placeholders in your string resource to this simpler format:
<string name="underlined_number">My number is <u> {number} </u></string>
then you can make the replacement like this:
CharSequence formatted = Phrase.from(getResources(), R.string.underlined_number)
.put("number", 5)
.format()
The formatted CharSequence is also styled. If you need to format your numbers, you can always pre-format them using String.format("%03d", 5) and then use the resulting string in the .put() function.
This is the code that finally worked for me
strings.xml
<string name="launch_awaiting_instructions">Contact <b>our</b> team on %1$s to activate.</string>
<string name="support_contact_phone_number"><b>555 555 555</b> Opt <b>3</b></string>
Kotlin code
fun Spanned.toHtmlWithoutParagraphs(): String {
return HtmlCompat.toHtml(this, HtmlCompat.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE)
.substringAfter("<p dir=\"ltr\">").substringBeforeLast("</p>")
}
fun Resources.getText(#StringRes id: Int, vararg args: Any): CharSequence {
val escapedArgs = args.map {
if (it is Spanned) it.toHtmlWithoutParagraphs() else it
}.toTypedArray()
val resource = SpannedString(getText(id))
val htmlResource = resource.toHtmlWithoutParagraphs()
val formattedHtml = String.format(htmlResource, *escapedArgs)
return HtmlCompat.fromHtml(formattedHtml, HtmlCompat.FROM_HTML_MODE_LEGACY)
}
Using this I was able to render styled text on Android with styled placeholders too
Output
Contact our team on 555 555 555 Opt 3 to activate.
I was then able to expand on this solution to create the following Compose methods.
Jetpack Compose UI
#Composable
fun annotatedStringResource(#StringRes id: Int, vararg formatArgs: Any): AnnotatedString {
val resources = LocalContext.current.resources
return remember(id) {
val text = resources.getText(id, *formatArgs)
spannableStringToAnnotatedString(text)
}
}
#Composable
fun annotatedStringResource(#StringRes id: Int): AnnotatedString {
val resources = LocalContext.current.resources
return remember(id) {
val text = resources.getText(id)
spannableStringToAnnotatedString(text)
}
}
private fun spannableStringToAnnotatedString(text: CharSequence): AnnotatedString {
return if (text is Spanned) {
val spanStyles = mutableListOf<AnnotatedString.Range<SpanStyle>>()
spanStyles.addAll(text.getSpans(0, text.length, UnderlineSpan::class.java).map {
AnnotatedString.Range(
SpanStyle(textDecoration = TextDecoration.Underline),
text.getSpanStart(it),
text.getSpanEnd(it)
)
})
spanStyles.addAll(text.getSpans(0, text.length, StyleSpan::class.java).map {
AnnotatedString.Range(
SpanStyle(fontWeight = FontWeight.Bold),
text.getSpanStart(it),
text.getSpanEnd(it)
)
})
AnnotatedString(text.toString(), spanStyles = spanStyles)
} else {
AnnotatedString(text.toString())
}
}
Similar to the accepted answer, I attempted to write a Kotlin extension method for this.
Here's the accepted answer in Kotlin
#Suppress("DEPRECATION")
fun Context.getText(id: Int, vararg args: Any): CharSequence {
val escapedArgs = args.map {
if (it is String) TextUtils.htmlEncode(it) else it
}.toTypedArray()
return Html.fromHtml(String.format(Html.toHtml(SpannedString(getText(id))), *escapedArgs))
}
The problem with the accepted answer, is that it doesn't seem to work when the format arguments themselves are styled (i.e. Spanned, not String). By experiment, it seems to do weird things, possibly to do with the fact that we're not escaping non-String CharSequences. I'm seeing that if I call
context.getText(R.id.my_format_string, myHelloSpanned)
where R.id.my_format_string is:
<string name="my_format_string">===%1$s===</string>
and myHelloSpanned is a Spanned that looks like <b>hello</b> (i.e. it would have HTML <i><b>hello</b></i>) then I get ===hello=== (i.e. HTML ===<b>hello</b>===).
That is wrong, I should get ===<b>hello</b>===.
I tried to fix this by converting all CharSequences to HTML before applying String.format, and here is my resulting code.
#Suppress("DEPRECATION")
fun Context.getText(#StringRes resId: Int, vararg formatArgs: Any): CharSequence {
// First, convert any styled Spanned back to HTML strings before applying String.format. This
// converts the styling to HTML and also does HTML escaping.
// For other CharSequences, just do HTML escaping.
// (Leave any other args alone.)
val htmlFormatArgs = formatArgs.map {
if (it is Spanned) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.toHtml(it, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE)
} else {
Html.toHtml(it)
}
} else if (it is CharSequence) {
Html.escapeHtml(it)
} else {
it
}
}.toTypedArray()
// Next, get the format string, and do the same to that.
val formatString = getText(resId);
val htmlFormatString = if (formatString is Spanned) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.toHtml(formatString, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE)
} else {
Html.toHtml(formatString)
}
} else {
Html.escapeHtml(formatString)
}
// Now apply the String.format
val htmlResultString = String.format(htmlFormatString, *htmlFormatArgs)
// Convert back to a CharSequence, recovering any of the HTML styling.
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(htmlResultString, Html.FROM_HTML_MODE_LEGACY)
} else {
Html.fromHtml(htmlResultString)
}
}
However, this didn't quite work because when you call Html.toHtml it puts <p> tags around everything even when that extra padding wasn't in the input. Said another way, Html.fromHtml(Html.toHtml(myHelloSpanned)) is not equal to myHelloSpanned - it's got extra padding. I didn't know how to resolve this nicely.
Update: this answer https://stackoverflow.com/a/56944152/6007104 has been updated, and is now the preferred answer
Here's a more readable Kotlin extension which doesn't use deprecated APIs, works on all Android versions, and doesn't require strings to be wrapped in CDATA sections:
fun Context.getText(id: Int, vararg args: Any): CharSequence {
val escapedArgs = args.map {
if (it is String) TextUtils.htmlEncode(it) else it
}.toTypedArray()
val resource = SpannedString(getText(id))
val htmlResource = HtmlCompat.toHtml(resource, HtmlCompat.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE)
val formattedHtml = String.format(htmlResource, *escapedArgs)
return HtmlCompat.fromHtml(formattedHtml, HtmlCompat.FROM_HTML_MODE_LEGACY)
}
You can add an alias as as extension of Fragment - just remember to spread the args in between:
fun Fragment.getText(id: Int, vararg args: Any) = requireContext().getText(id, *args)
You can use java.lang.String for string formatting in Kotlin
fun main(args : Array<String>) {
var value1 = 1
var value2 = "2"
var value3 = 3.0
println(java.lang.String.format("%d, %s, %6f", value1, value2, value3))
}