Put "List of Objects" in KrollDict with Titanium Android Module Development - titanium

I have a custom class declared in the module source code.
public class Friend{
public String name;
public List<String> phoneNumbers;
public List<String> emailAddresses;
public Friend(String name, List<String>emailAddresses,
List<String>phoneNumbers){
this.name = name;
this.emailAddresses = emailAddresses;
this.phoneNumbers = phoneNumbers;
}
}
I declared an Android Method in the Module
#Kroll.method
protected synchronized void getListOfObjects(){
List<String> emailAddresses = Arrays.asList("email1#yahoo.com", "email2#yahoo.com", "email3#yahoo.com");
List<String> phoneNumbers = Arrays.asList("1", "2", "3");
List<Friend> friendList = new ArrayList<Friend>();
friendList.add(new Friend("test1", emailAddresses, phoneNumbers));
friendList.add(new Friend("test2", emailAddresses, phoneNumbers));
friendList.add(new Friend("test3", emailAddresses, phoneNumbers));
KrollDict kd = new KrollDict();
kd.put("friendList", friendList);
if (hasListeners("onShow")) {
fireEvent("onShow", kd);
}
}
Upon Calling the getListOfOjects method in the Titanium App
module.getListOfObjects();
module.addEventListener('onShow', function(e){
Ti.API.info(JSON.stringify(e.friendList));
});
I cant seem to retrieve the friendList object.
The EXPECTED RESULT that I wanted to achieve would be like this
[
{test1, ["email1#yahoo.com", "email2#yahoo.com", "email3#yahoo.com"], ["1", "2", "3"]},
{test2, ["email1#yahoo.com", "email2#yahoo.com", "email3#yahoo.com"], ["1", "2", "3"]},
{test3, ["email1#yahoo.com", "email2#yahoo.com", "email3#yahoo.com"], ["1", "2", "3"]}
]
The question is, HOW TO ACHIEVE THE EXPECTED RESULT BASED ON THE SAMPLE CODES ABOVE?

Convert the List object into JSON string using GSON and assign the result string to the KrollDict property
KrollDict kd = new KrollDict();
Gson gson = new Gson();
String friendListStr = gson.toJson(friendList);
kd.put("friendList", friendListStr);

Another option is to return an object array like this:
KrollDict kd = new KrollDict();
Object[] obj = new Object[friendList.size()];
for (int i=0; i< friendList.size(); ++i){
KrollDict model = new KrollDict();
model.put("name", friendList.get(i).name);
// ...
obj[i] = model;
}
kd.put("list", obj);
fireEvent("onShow", kd);
That way you'll have an array in your event and don't need to convert that string into json later on.
If you want to use a JSON you can use TiConvert with toJSON, toJSONArray or toJSONString depending on your parameter. No need for Gson.

Related

Saving and Loading file definitions while using <generic> version of FileEngine

I've successfully use the SaveToXml and LoadFromXml methods on the ClassBuilder class to store and retrieve the file definitions while using the Standard version of the File Helper Engine.
However I'd really prefer to use the generic version of the File Helper Engine. In other words I'd like to instatiate the engine like so:
var eng = new DelimitedFileEngine<OutputClass>(params....);
OutputClass[] records = eng.ReadFile("Sample.csv");
So my results are strongly typed and not just an array of objects.
Does this save and load functionality exist for the generic file helper engine?
Sure, it works exactly as you'd expect.
[DelimitedRecord("|")]
public class OutputClass
{
public string First { get; set; }
public string Second { get; set; }
}
class Program
{
static void Main(string[] args)
{
var eng = new DelimitedFileEngine<OutputClass>();
// To read from a file use ReadFile()
//OutputClass[] records = eng.ReadFile("Sample.csv");
// Or to read from a string use ReadString()
OutputClass[] records = eng.ReadString("First|Second");
Debug.Assert(records.Length == 1);
Debug.Assert(records[0].First == "First");
Debug.Assert(records[0].Second == "Second");
Console.WriteLine("All OK");
Console.ReadKey();
}
}
Edit:
Based on your comment below, you want to map the results from your XML class to a concrete C# object. The easiest way is to use read into a DataTable and map the fields to the C# object.
var cb = new DelimitedClassBuilder(nameof(OutputClass), "|");
cb.AddField("First", typeof(string));
cb.AddField("Second", typeof(string));
var xmlString = cb.SaveToXmlString();
var outputClass = DelimitedClassBuilder.LoadFromXmlString(xmlString);
var eng = new FileHelperEngine(outputClass.CreateRecordClass());
OutputClass[] records = eng
.ReadStringAsDT("First|Second")
.Rows.OfType<DataRow>()
.Select(x => new OutputClass() {
First = x.Field<string>("First"),
Second = x.Field<string>("Second")
})
.ToArray();

Formatting YAML with Jackson

I am using the Jackson library to convert Java objects to YAML format. Based on the documentation I found on the Internet, I was able to quickly write a function that does the conversion.
I am seeking to convert the following classes to YAML:
public class RequestInfo
{
private String thePath;
private String theMethod;
private String theURL;
private List<ParamInfo> theParams = new ArrayList<>();
// getters and setters
}
public class ParamInfo
{
private String paramName;
private String paramType;
// getters and setters
}
Using Jackson's ObjectMapper, I can easily generate the YAML:
public String basicTest()
{
ObjectMapper theMapper = new ObjectMapper(new YAMLFactory());
RequestInfo info = new RequestInfo();
info.setThePath("/");
info.setTheMethod("GET");
info.setTheURL("http://localhost:8080/");
List<ParamInfo> params = new ArrayList<>();
params.add(new ParamInfo("resource","path"));
info.setTheParams(params);
String ret = null;
try
{
ret = theMapper.writeValueAsString(info);
}
catch(Exception exe)
{
logger.error(exe.getMessage());
}
return(ret);
}
The YAML I get is below:
---
thePath: "/"
theMethod: "GET"
theURL: "http://localhost:8080/"
theParams:
- paramName: "resource"
paramType: "path"
The YAML I get is OK, but it has some problems in my eyes. One probem is the "---" that it begins with. Another is the fact that I would like to be able to group the information in a manner similar to the YAML below:
RequestInfo:
thePath: "/"
theMethod: "GET"
theURL: "http://localhost:8080/"
theParams:
- paramName: "resource"
paramType: "path"
All of the examples I am seeing on the Internet use an Employee class, and talk about how to convert that class to YAML, but do not tell how to avoid the "---" (or change it into soething more descriptive). I also cannot find anything that tells how to group the YAML in the manner I describe.
Does anyone know how to do this? Is there a way to eliminate the "---", or create a name (like "RequestInfo") that groups together the translated data in an object?
You can ignore --- by disable YAMLGenerator.Feature.WRITE_DOC_START_MARKER..
If you want to wrap value under class name then u need to use #JsonRootName...
Try with this:
RequestInof class:
#JsonRootName("RequestInfo")
public class RequestInfo
{
private String thePath;
private String theMethod;
private String theURL;
private List<ParamInfo> theParams = new ArrayList<>();
// getters and setters
}
Test:
public String basicTest()
{
ObjectMapper theMapper = new ObjectMapper(new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER));
theMapper.enable(SerializationFeature.WRAP_ROOT_VALUE); RequestInfo info = new RequestInfo();
info.setThePath("/");
info.setTheMethod("GET");
info.setTheURL("http://localhost:8080/");
List<ParamInfo> params = new ArrayList<>();
params.add(new ParamInfo("resource","path"));
info.setTheParams(params);
String ret = null;
try
{
ret = theMapper.writeValueAsString(info);
}
catch(Exception exe)
{
logger.error(exe.getMessage());
}
return(ret);
}

How to pass bean class to a test method in testng?

I have an Excel Util which reads all the data from excel sheet. The excel sheet has 10 columns like time, sourceType, tid, message, severity,
lastModify, entityName, operationType, replayId, recordIds.
My DataProvider has code something like this which returns all the 10 columns and their values.
#DataProvider(name="googleData")
public static Object[][] testData() {
String filePath = "/Users/TestUser/Workspace/FixProject/ExcelCheck/src/test/resources/excelreader.xlsx";
Object[][] arrayObject = excelFileUtils.getExcelData(filePath, "excelreader");
return arrayObject;
}
In My TestMethod, I have to pass all these 10 columns or else it wont allow me to run. Instead I want to create a Bean Class and pass something like this to my test method
#Test(dataProvider = "googleData", dataProviderClass = DataProviders.class)
public void testGoogleData(BeanClass object) {
System.out.println(object.getTid());
}
How do we achieve this?
Using the dataProvider you have, your test method is going to run 10 times for each object in the array.
What you can do is to create an object, convert your dataProvider into that object and than use it your test method code.
Object myDataHelper = null;
#Test()
public void testGoogleData(BeanClass object) {
myDataHelper = convertDataProviderToObject();
// use it here in a for/for each loop
System.out.println(object.getTid());
}
public static Object[][] read_excel(String Sheet_Name) throws Exception
{
File obj = new File("./src/main/java/com/Demo/TestData/Test_Data.xlsx");
FileInputStream fis = new FileInputStream(obj);
XSSFWorkbook wb = new XSSFWorkbook(fis);
XSSFSheet sheet = wb.getSheet(Sheet_Name);
int row_number = sheet.getLastRowNum();
int column_number = sheet.getRow(0).getLastCellNum();
Object data[][] = new Object[row_number][column_number];
wb.close();
for(int i=0; i<row_number; i++)
{
for(int j=0; j<column_number; j++)
{
data[i][j] = sheet.getRow(i + 1).getCell(j).toString();
}
}
return data;
}
#DataProvider
public Object[][] getDataFromExcel() throws Exception
{ Object[][] data = Utility.read_excel("Admin_Credentials");//Sheet name
return data;
}
#Test(dataProvider="getDataFromExcel")
It is supported in QAF-TestNG extension. You can have one or more complex object argument in your test method while using inbuilt or custom data provider. For excel your code may look like below:
#QAFDataProvider(dataFile = "resources/data/googletestdata.xls")
#Test
public void testGoogleData(BeanClass object) {
System.out.println(object.getTid());
}
For custom data provider it may look like below:
#QAFDataProvider
#Test(dataProvider = "googleData", dataProviderClass = DataProviders.class)
public void testGoogleData(BeanClass object) {
System.out.println(object.getTid());
}
You need to make sure that,properties name in your bean class must match column names (in any order). When using custom data provider you need to return Iterator for List of Map<String, Object> or Object[][] having Map, refer few example if you required to create custom data provider.

Set field to a shared value

I have a class that looks like this:
class Data {
#JsonCreator
public Data(#JsonProperty("string") String s, Widget w) {
string = s;
widget = w;
}
String string;
Widget widget;
}
I want to deserialize it from this from JSON like
{
"string": "string value"
}
When deserializing, I want to set widget to a shared instance. I have that instance when I create the object mapper, but I can not see how to tell Jackson to use this instance.
I see JsonDeserialize.getNullValue and getEmptyValue, but those look like they are for handling
{
"string": "string value", "widget": null
}
which is not the JSON that I have.
You could try #JacksonInject:
public class Data {
#JacksonInject
public Widget widget;
...
}
And then use as follows:
Widget widget = ...
InjectableValues injectable = new InjectableValues.Std().addValue(Widget.class, widget);
Data data = new ObjectMapper().reader(injectable).forType(Data.class).readValue(json);

FileHelpers columns headers

Simple question as i cannot find it anywhere. How to set custom column names for each column? I tried to use this: <FieldOrder(1), FieldTitle("Name")]> but it says FieldTitle not existing.
It will just use the name of the field.
[DelimitedRecord(",")]
class Product
{
// Must specify FieldOrder too
[FieldOrder(1)]
public string Name;
[FieldOrder(2)]
public string Description;
[FieldOrder(3)]
public string Size;
}
class Program
{
static void Main(string[] args)
{
var engine = new FileHelperEngine<Product>();
engine.HeaderText = engine.GetFileHeader();
var products = new Product[] { new Product() { Name = "Product", Description = "Some details", Size = "Large"} };
var productRecords = engine.WriteString(products);
Console.WriteLine(productRecords);
}
}
Output:
Name,Description,Size
Product,Some details,Large
If you need something different, you can just do
engine.HeaderText = "whatever,whatever,whatever";
Output:
whatever,whatever,whatever
Product,Some details,Large