I have a legacy code that looks like this,
///
....
List<Object[]> reportResults = new ArrayList<Object[]>();
reportResults = query.getResultList();
logger.info("reportResults ==== "+reportResults.toString());
workbook = expService.exportExcel(fileName, reportResults, reportHeaders);
...///
So when the resultset is more than 1 column then logger prints '[[Ljava.lang.Object;#391472f5] ' like an object.
When the reportResult is only 1 column then results look like this, '[USA, EUROPE]' when its 1 column 1 row it looks like '[USA]'
The problem is when I iterate with the reportResults in the below method. reportData parameter is nothing but reportResults below.
The inner for loop throws 'java.lang.ClassCastException: java.lang.String cannot be cast to [Ljava.lang.Object;' when reportData is just 1 column. How can i handle so it works for all the cases.
public XSSFWorkbook exportExcel(String reportName, List<Object[]> reportData, String headers) throws Exception {
...///
System.out.println("... "+reportData.size());
for(int i=0; i<reportData.size(); i++){
row = sheet.createRow(rownum);
rownum++;
System.out.println("....... "+reportData.get(i));
for(int j = 0; j < reportData.get(i).length; j++){
cell = row.createCell(j);
Object oCellValue = reportData.get(i)[j];
if(oCellValue != null){
String className=oCellValue.getClass().getName();
if(className.equals(Timestamp.class.getName())){
CellStyle cStyle = workbook.createCellStyle();
cStyle.setDataFormat((short)14);
Timestamp tsValue=(Timestamp)oCellValue;
Date dtValue = new Date(tsValue.getTime());
cell.setCellValue(dtValue);
cell.setCellStyle(cStyle);
}else{
cell.setCellValue(""+oCellValue);
}
}else{
cell.setCellValue("");
}
}
}
...//
}
So the 1st line sysout prints size as 1. It gets into the loop and prints the 2nd sysout as 'USA'.
reportData.get(i) -> this is supposed to be a object and in my case for this scenario its 'USA'.
Please let me know how i can get rid of this exception and handle the same for all cases. Any help is highly appreciated. Thank you.
Related
I'd like to implement the data from Excel file to different tests depending on the scenario correct data/invalid one, however when I want to get the cell value I get the "NegativeArraySizeException".
The first row has just a title so I don't want to read it, that's why I have the parameters [rows-1].
Could you please indicate what is my mistake?
Thank you
public class SignInTest extends Driver {
#BeforeMethod
public void setUp() {
Driver.initConfiguration();
}
public Object[][] getData(String excelPath, String sheetName) {
int rows = excel.getRowCount(sheetName);
int cols = excel.getColumnCount(sheetName);
Object[][] data = new Object[rows - 1][1];
excel = new ExcelReader(excelPath);
for (int rowNum = 1; rowNum < rows; rowNum++) {
for (int colNum = 0; colNum < cols; colNum++) {
data[rowNum - 1][colNum] = excel.getCellData(sheetName, colNum, rowNum);
}
}
return data;
}
#DataProvider(name = "credentials")
public Object[][] getCredentials() {
Object[][] data = getData(excelPath, sheetName);
return data;
}
#Test(dataProviderClass = DataProviders.class, dataProvider = "credentials")
public void loginWithCorrectCredentials(String email, String password) {
HomePageActions hp = new HomePageActions();
SignInActions sign = new SignInActions();
DataProviders dp = new DataProviders();
dp.getData(excelPath, "correctData");
System.out.println("email " + email);
System.out.println("password " + password);
}
This function "excel.getRowCount(sheetName)"
On this line:
int rows = excel.getRowCount(sheetName);
Is returning 0 (or possibly null), thus when you do rows-1, you get a number less than zero. I should hope that much is obvious. So the question becomes WHY?
Things to look for in troubleshooting:
Is the getColumnCount also returning zero? If so, this points to a possible
error in the worksheet reference.
Is the sheetName actually correctly being passed into the function?
Can you insert an explicit value into a specific place on the worksheet? Meaning is that reference working? Throw in a test line and see what happens.
What happens if you hard set the array to say:
Object[][] data = new Object[100][1];
My gut is telling me you have an issue with the reference to the worksheet, but without knowing more about your worksheet referencing, it's impossible to know for sure.
I hope some of this points you in the right direction and gets you going. Good luck!
I am reading cells from an Excel spreadsheet. I am reading the first cell in each row, and comparing them to a String object that I have passed into the function. The function correctly iterates over all rows and accesses the first cell in each row, but when comparing them to the String object parameter, the IF statement does not execute, despite both the value obtained from the cell and the String parameter printing the same thing. I have used '==' operators, as well as .equals() but nothing seems to let the IF statement execute.
public static ArrayList<Integer> returnCurrency(String currency, String fileName) throws IOException
{
FileInputStream excelFile = new FileInputStream(newFile(fileName));
Workbook workbook = new XSSFWorkbook(excelFile);
Sheet sheet = workbook.getSheetAt(0);
Iterator<Row> iterator = sheet.iterator();
ArrayList<Double> currencyRateArray = new ArrayList<Double>();
for( int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++)
{
Row row = sheet.getRow(rowNum);
Cell tempCell = row.getCell(0);
System.out.printf("temp cell has value of:%s\n",tempCell.getStringCellValue());
System.out.printf("currency variable is: %s\n", currency);
if(currency.equals(tempCellString))
{
System.out.println("Found the currency\n");
}
}
}
When I pass the parameter String as "USD", both print statements print "USD", but it will never print "Found the currency" as that IF statement does not execute. Any help would be appreciated :)
Found the answer - the cell in the database had the value 'USD ' instead of 'USD'.
My java spring boot app needs to create a new excel file based on the contents of my DB. My current solution places all the data from my DB and inserts it in my excel sheet, but I want to improve it by not stating what the cell values are. For example, although it works, my solution has 34 fields so I am stating the userRow.createCell line 34 times for each field which is repetitive. Ideally I want to say create the cell(n) and take all the values from each row in the DB. How can this be done? Another for loop within this for loop? Every example I looked at online seems to specifically state what the cell value is.
List<CaseData> cases = (List<CaseData>) model.get("cases");
Sheet sheet = workbook.createSheet("PIE Cases");
int rowCount = 1;
for (CaseData pieCase : cases) {
Row userRow = sheet.createRow(rowCount++);
userRow.createCell(0).setCellValue(pieCase.getCaseId());
userRow.createCell(1).setCellValue(pieCase.getAcknowledgementReceivedDate());
}
Use the Reflection API
Example:
try {
Class caseDataObj = CaseData.class;
Method [] methods = caseDataObj.getDeclaredMethods();
Sheet sheet = workbook.createSheet("PIE Cases");
int rowCount = 1;
for(CaseData cd : cases) {
int cellIndex = 0;
Row userRow = sheet.createRow(rowCount++);
for (Method method : methods) {
String methodName = method.getName();
if(methodName.startsWith("get")) {
// Assuming all getters return String
userRow.createCell(cellIndex++).setCellValue((String) method.invoke(cd));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
There are probably many ways to do this, You can try something like this, this is how I usually go about it for things like what you are doing.
public enum DATA {
CASE_ID(0),
ACK_RECIEVED(1),
ETC(2);
//ETC(3) and so on
public int index;
DATA(int index) {
this.index = index;
}
public Object parse(CaseData data) throws Exception {
switch (this) {
case CASE_ID:
return data.getCaseId();
case ACK_RECIEVED:
return data.getAcknowledgementReceivedDate();
case ETC:
return "etc...";
default: return null;
}
}
}
Then, the implementation is:
List<CaseData> cases = (List<CaseData>) model.get("cases");
Sheet sheet = workbook.createSheet("PIE Cases");
int rowCount = 1;
for (CaseData pieCase : cases) {
Row userRow = sheet.createRow(rowCount++);
for (DATA DAT : DATA.values()) {
userRow.createCell(DAT.index).setCellValue(DAT.parse(pieCase));
}
}
Using a list of strings, I am trying to match the string in a excel sheet and add the cell elements in the inner list. Adding the inner list in the outer list using a loop. Please refer the code below
public static List<ArrayList<String>> getKeywords(List<String> testCaseIdList, String fileName, String sheetName){
try {
ArrayList<String> listTestSteps = new ArrayList<String>();
List<ArrayList<String>> listTestCases = new ArrayList<ArrayList<String>>(0);
Sheet sheetKW = ReadExcelFile.readExcel(ST_KEYWORDS);
String columnValue = null;
int matchFlag, addListFlag = 0;
for(String testCaseId : testCaseIdList) {
Iterator<Row> rowIterator = sheetKW.rowIterator();
listTestSteps.clear();
while(rowIterator.hasNext()) {
Row rowNext = (Row) rowIterator.next();
Iterator<Cell> cellIterator = rowNext.cellIterator();
matchFlag = 0;
addListFlag = 0;
//listTestSteps.clear();
while(cellIterator.hasNext()) {
Cell nextCell = cellIterator.next();
columnValue = nextCell.getStringCellValue();
//System.out.println("Column value " +columnValue);
if((columnValue.equalsIgnoreCase(testCaseId)) && (columnValue != "" )) {
matchFlag = 1;
}
if(matchFlag == 1 && columnValue != "") {
listTestSteps.add(columnValue);
addListFlag = 1;
System.out.println("Add Value : "+columnValue);
}
}
if((listTestSteps.isEmpty() == false) && (addListFlag == 1)) {
System.out.println("Adding to the Main list");
listTestCases.add(listTestSteps);
//listTestCases.forEach(System.out::println);
}
}
}
//listTestSteps.forEach(System.out::println);
// Return ArrayList of ArrayLists
return listTestCases;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I am getting the output as
[TC_0003, login, createUser, deleteUser]
[TC_0003, login, createUser, deleteUser]
Firstly added list listTestSteps is getting replaced by the last iteration list.
Expected output is
[[TC_0002, login, createUser, deleteUser, newUser], [TC_0003, login, createUser, deleteUser]]
Something is wrong for sure. Any help will be appreciated.
Using the
listTestSteps.clear();
instruction in the loop lets you use always the same list, so in every iteration you just empty and refill the same list and add it to the outer list. For this reason the outer list will at the end contain x entries pointing always at the same list, which is filled with the data you put there in last iteration.
So you just have to do
ArrayList<String> listTestSteps = new ArrayList<String>();
instead of clearing the list
The problem is you add the reference of listTestSteps to listTestCases and then in the next loop you clear the listTestSteps, but the cleared list is still referenced in listTestCases. So would suggest using the answer to Add an object to an ArrayList and modify it later to ensure that both lists are resolved properly.
I have below class file. If I try to insert values from Vector to database, then it will display below error. I want to use Vector in this case and looking how to resolve this issue.
error : The method setString(int, String) in the type PreparedStatement is not applicable for the arguments (int, Object)
below is the class code:
public class ReadExcelFile {
public static void main(String[] args) {
String fileName = "C:\\excelFile.xls";
Vector dataHolder = ReadCSV(fileName);
printCellDataToConsole(dataHolder);
}
public static Vector ReadCSV(String fileName) {
Vector cellVectorHolder = new Vector();
try {
FileInputStream myInput = new FileInputStream(fileName);
POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput);
HSSFWorkbook myWorkBook = new HSSFWorkbook(myFileSystem);
HSSFSheet mySheet = myWorkBook.getSheetAt(0);
Iterator rowIter = mySheet.rowIterator();
while (rowIter.hasNext()) {
HSSFRow myRow = (HSSFRow) rowIter.next();
Iterator cellIter = myRow.cellIterator();
Vector cellStoreVector = new Vector();
while (cellIter.hasNext()) {
HSSFCell myCell = (HSSFCell) cellIter.next();
cellStoreVector.addElement(myCell);
}
cellVectorHolder.addElement(cellStoreVector);
}
} catch (Exception e) {
e.printStackTrace();
}
return cellVectorHolder;
}
public static void printCellDataToConsole(Vector dataHolder) {
for (int i = 0; i < dataHolder.size(); i++) {
Vector cellStoreVector = (Vector) dataHolder.elementAt(i);
// System.out.println(cellStoreVector);
for (int j = 0; j < cellStoreVector.size(); j++) {
HSSFCell myCell = (HSSFCell) cellStoreVector.elementAt(j);
String stringCellValue = myCell.toString();
System.out.print(stringCellValue + "\t\t");
}
System.out.println();
}
}
}
//below is the database query
String sql = "INSERT INTO table_name(EMP_ID,FNAME, LNAME, CATEGORY, DEPARTMENT, Title, REASON, Manager, sDate, eDate, ID) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
PreparedStatement pst1 = conn.prepareStatement(sql);
pst1.setString(1, cellStoreVector.get(0));
pst1.setString(2, cellStoreVector.get(1));
pst1.setString(3, cellStoreVector.get(2));
pst1.setString(4, cellStoreVector.get(3));
pst1.setString(5, cellStoreVector.get(4));
pst1.setString(6, cellStoreVector.get(5));
pst1.setString(7, cellStoreVector.get(6));
pst1.setString(8, cellStoreVector.get(7));
pst1.setString(9, cellStoreVector.get(8));
pst1.setString(10, cellStoreVector.get(9));
pst1.setString(11, "555"); //Hardcoded for testing.
pst1.execute();
Your Vector is defined to hold Objects.
The Vector#get will return an Object.
The PreparedStatement#setString method is expecting a String, this is a simple type mismatch issue.
You can declare you Vector so that it only contains String...
Vector<String> myVector = new Vector<String>(25);
...But I don't think you can from your example...
You can cast the value in the Vector to a String
pst1.setString(1, (String)cellStoreVector.get(0));
But this is dangerous as you won't find out that the Vector doesn't contain a String element until run-time
Or you can let the PreparedStatement handle it...
pst1.setObject(1, cellStoreVector.get(0));
Your cellStoreVector contains instances of HSSFCell. But since your using a non-generic collection, when you retrieve elements you get them as Object, which is why the compiler is complaining, because an String is expected instead.
As the cells can be of different types, how you should handle it really depends what types cells they are.
For example if all cells were for string data then there is a method which returns the value in the cell as a String.
HSSFCell#getStringCellValue
get the value of the cell as a string - for numeric cells we throw an exception. For blank cells we return an empty string. For formulaCells that are not string Formulas, we throw an exception
So if they were all string cells, I think this is what you could do
pst1.setString(1, ((HSSFCell) cellStoreVector.get(0)).getStringCellValue());
Cast the object you get from the vector to HSSFCell and then get the value as String.
But, that's just an idea, you will have make sure what you are getting. Also, when dealing with collections it's always good use the generic versions for type safety.
This is an elementary programming error and the error message is self-explanatory. The second argument to that method is a String, not an Object. So you have to cast it to a String, if it really is a String, which it isn't in this case. You need to check your datatypes. You should be using Generics for the cellStoreVector to make this more clear and more typesafe.