This question already has answers here:
How to show/hide a column at runtime?
(8 answers)
Closed 1 year ago.
I have a CSV/Excel report with 5 fixed columns and I want to add more columns, depending on the input. Each report generation may require different number of columns.
The jrxml approach is done, so my question is - Can I add dynamic columns in jrxml ?
If not, what is the correct way to do it with coding ? example
Note: I prefer not to use Dynamic Jasper library
I think your purpose can be best achieved by using DynamicJasper which creates report design and layout on the fly. This will allow you to custom made report before generating it.
DynamicJasper is perfect for generating a report having dynamic number of columns.
Here is one code which I used for my N number of columns and M number of rows to create a pdf file by using JRBeanCollectionDataSource.
private List<DynaBean> convertDynaBListFrom2DAry(Object[][] ary2D, int width, int height){
logger.info("Converting report array to dynamic bean as, we have dynamic number of columns");
DynaProperty[] props = new DynaProperty[width];
for (int p=0; p < width; p++) {
DynaProperty dp = new DynaProperty("property"+p);
props[p] = dp;
}
List<DynaBean> dynaBeans = new ArrayList<>(height);
for (Object[] objects : ary2D) {
MutableDynaClass dc = new LazyDynaClass("Row", null, props);
try {
DynaBean row = dc.newInstance();
for (int c=0 ; c < width ; c++ ) {
Object obj = objects[c];
if(obj == null) {
obj = new String("");
}else if(obj.equals("null")) {
obj = new String("");
}else if(obj.equals("NaN")){
obj = new String("");
}
row.set("property"+c, obj);
}
dynaBeans.add(row);
} catch (IllegalAccessException e) {
logger.error("Exception ",e);
} catch (InstantiationException e) {
logger.error("Exception ",e);
}
}
return dynaBeans;
}
Related
i'm trying to implement steganography's word shifting coding protocol on a microsoft word report using java application. Basicly, it uses an existing report and edit it's spacing to put some secret data. If it's wider, then its 1 bit data. And if it's narrower, then it's 0 bit data. So i wonder what kind of library should i have to start constructing this java app or if java doesn't support this kind of comunication with ms-word what kind language of programming should i use, thank you for your time.
I would recommend using C# and the Microsoft.Office.Interop.Word. You can use the free Visual Studio Community version (https://www.visualstudio.com/products/visual-studio-community-vs), create a console application and add a reference for the interop namespace (in project explorer, right click on references, add reference: COM->Microsoft Word 16.0 Object Library).
Simple example:
namespace WordShiftingExample
{
class Program
{
private static int[] getSpaces(string text)
{
System.Collections.ArrayList list = new System.Collections.ArrayList();
int index = 0;
while (index != text.LastIndexOf(" "))
{
index = text.IndexOf(" ", index + 1);
list.Add(index);
}
return list.ToArray(typeof(int)) as int[];
}
static void Main(string[] args)
{
try
{
Microsoft.Office.Interop.Word.Application winword = new Microsoft.Office.Interop.Word.Application();
winword.ShowAnimation = false;
winword.Visible = false;
object missing = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Word.Document document = winword.Documents.Add(ref missing, ref missing, ref missing, ref missing);
float zero = 0.1F;
float one = 0.15F;
document.Content.Text = "This is a test document.";
//set word-spacing for first two spaces
int[] spaces = getSpaces(document.Content.Text);
document.Range(spaces[0], spaces[0]+1).Font.Spacing=zero;
document.Range(spaces[1], spaces[1]+1).Font.Spacing = one;
//read word-spacing for first two spaces
System.Diagnostics.Debug.WriteLine(document.Range(spaces[0], spaces[0]+1).Font.Spacing); // prints 0.1
System.Diagnostics.Debug.WriteLine(document.Range(spaces[1], spaces[1]+1).Font.Spacing); // prints 0.15
//Save the document
object filename = System.Environment.GetEnvironmentVariable("USERPROFILE")+"\\temp1.docx";
document.SaveAs2(ref filename);
document.Close(ref missing, ref missing, ref missing);
document = null;
winword.Quit(ref missing, ref missing, ref missing);
winword = null;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
}
}
}
}
I am in the middle of creating an app that allows users to apply for job positions and upload their CVs. I`m currently stuck on trying to make a search box for the admin to be able to search for Keywords. The app will than look through all the CVs and if it finds such keywords it will show up a list of Cvs that contain the keyword. I am fairly new to Gui design and app creation so not sure how to go about doing it. I wish to have it done via java and am using the Eclipse Window builder to help me design it. Any help will be greatly appreciated, hints, advice anything. Thank You.
Well, this not right design approach as real time search of words in all files of given folder will be slow and not sustainable in long run. Ideally you should have indexed all CV's for keywords. The search should run on index and then get the associated CV for that index ( think of indexes similar to tags). There are many options for indexing - simples DB indexing or using Apache Lucene or follow these steps to create a index using Maps and refer this index for search.
Create a map Map<String, List<File>> for keeping the association of
keywords to files
iterate through all files, and for each word in
each file, add that file to the list corresponding to that word in
your index map
here is the java code which will work for you but I would still suggest to change your design approach and use indexes.
File dir = new File("Folder for CV's");
if(dir.exists())
{
Pattern p = Pattern.compile("Java");
ArrayList<String> list = new ArrayList<String>(); // list of CV's
for(File f : dir.listFiles())
{
if(!f.isFile()) continue;
try
{
FileInputStream fis = new FileInputStream(f);
byte[] data = new byte[fis.available()];
fis.read(data);
String text = new String(data);
Matcher m = p.matcher(text);
if(m.find())
{
list.add(f.getName()); // add file to found-keyword list.
}
fis.close();
}
catch(Exception e)
{
System.out.print("\n\t Error processing file : "+f.getName());
}
}
System.out.print("\n\t List : "+list); // list of files containing keyword.
} // IF directory exists then only process.
else
{
System.out.print("\n Directory doesn't exist.");
}
Here you get the files list to show now for "Java". As I said use indexes :)
Thanks for taking your time to look into my problem.
I have actually come up with a solution of my own. It is probably very amateur like but it works for me.
JButton btnSearch = new JButton("Search");
btnSearch.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
list.clear();
String s = SearchBox.getText();
int i = 0,present = 0;
int id;
try
{
Class.forName(driver).newInstance();
Connection conn = DriverManager.getConnection(url+dbName,userName,password);
Statement st = conn.createStatement();
ResultSet res = st.executeQuery("SELECT * FROM javaapp.test");
while(res.next())
{
i = 0;
present = 0;
while(i < 9)
{
String out = res.getString(search[i]);
if(out.toLowerCase().contains(s.toLowerCase()))
{
present = 1;
break;
}
i++;
}
if(tglbtnNormalshortlist.isSelected())
{
if(present == 1 && res.getInt("Shortlist") == 1)
{
id = res.getInt("Candidate");
String print = res.getString("Name");
list.addElement(print+" "+id);
}
}
else
{
if(present == 1 && res.getInt("Shortlist") == 0)
{
id = res.getInt("Candidate");
String print = res.getString("Name");
list.addElement(print+" "+id);
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
I've got an Excel Spreadsheet in which I store all of the test Credit Cards. These credit cards have different types. Some of these are VISA, others are MasterCard, Amex etc...
I have got a test case in which I sometimes want to use VISA cards, and sometimes MasterCard cards.
Is it possible to pass parameters to the #DataProvider?
Here is my code for #DataProvider:
#DataProvider(name="dpCreditCards")
public Object[][] getCreditCards() {
Object[][] testData = null;
try {
FileInputStream fis = new FileInputStream(dir);
XSSFWorkbook workbook = new XSSFWorkbook(fis);
XSSFSheet worksheet = workbook.getSheet("Credit Cards");
String type = "";
String cardNumber = "";
int numOfRows = worksheet.getPhysicalNumberOfRows();
int j = 0;
if (numOfRows > 0) {
for (int i = 1; i < numOfRows; i++) {
XSSFRow r = worksheet.getRow(i);
if (r.getCell(0).getCellType() == Cell.CELL_TYPE_NUMERIC) {
type = Integer.toString((int)r.getCell(0).getNumericCellValue());
} else if (r.getCell(0).getCellType() == Cell.CELL_TYPE_STRING) {
type = r.getCell(0).getStringCellValue();
}
if (type.equalsIgnoreCase("visa"))
j++;
}
testData = new Object[j][1];
}
for (int i = 1; i < numOfRows; i++) {
XSSFRow r = worksheet.getRow(i);
if (r.getCell(0).getCellType() == Cell.CELL_TYPE_NUMERIC) {
type = Integer.toString((int)r.getCell(0).getNumericCellValue());
} else if (r.getCell(0).getCellType() == Cell.CELL_TYPE_STRING) {
type = r.getCell(0).getStringCellValue();
}
if (type.equalsIgnoreCase("visa")) {
if (r.getCell(1).getCellType() == Cell.CELL_TYPE_NUMERIC) {
cardNumber = Integer.toString((int)r.getCell(1).getNumericCellValue());
} else if (r.getCell(1).getCellType() == Cell.CELL_TYPE_STRING) {
cardNumber = r.getCell(1).getStringCellValue();
}
testData[i-1][0] = cardNumber;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return testData;
}
I've checked this link: http://testng.org/doc/documentation-main.html#parameters-dataproviders but couldn't find anything that would work for me. It suggests to pass Method m as parameter to data provider, but I couldn't find a useful method that m has.
Thanks in advance
One way could be to read the parameters in the listeners and then set a property which can be used in the dataprovider.
Implement ITestListener or ISuiteListener, depending upon how you are structuring your tests. Set the global card property or threadlocal property (again depending upon how you are running your tests sequentially/parallely) in the onStart methods of any.
Read this property in your dataprovider.
If you just want to test a subset of your data you could filter it out in your data provider.
If you want to apply different tests to different subsets of data, then you could use different data providers for each of the test methods. Or you could use tbe Method parameter to decide what data to return from your data provider.
If you want to be able to configure the type of data to be loaded for your test at runtime, you could use a env variable/system property for this.
Bottom line:
If you run the same test against different subsets of data, you have multiple ways to specify the subset you want to check
If you want to run different tests for different subsets of data then you should probably go with multiple data providers
I need to iteratively extend a weka ARFF file with SparseInstance objects. Each time a new SparseInstance is added the header might change since the new Instance might add additional attributes. I thought the mergeInstances method would solve my problem but it does not. It requires both dataset to have no shared attributes.
If this is not absolutely clear look at the following example:
Dataset1
a b c
1 2 3
4 5 6
Dataset2
c d
7 8
Merged result:
a b c d
1 2 3 ?
4 5 6 ?
? ? 7 8
The only solution I see at the moment is parsing the arff file by hand and merging it using String processing. Does anyone know of a better solution?
Ok. I found the solution myself. The central part of the solution is the method Instances#insertAttributeAt, which inserts a new attribute as the last one if the second parameter is model.numAttributes(). Here is some example code for numerical attributes. It is easy to adapt to other types of attributes as well:
Map<String,String> currentInstanceFeatures = currentInstance.getFeatures();
Instances model = null;
try {
if (targetFile.exists()) {
FileReader in = new FileReader(targetFile);
try {
BufferedReader reader = new BufferedReader(in);
ArffReader arff = new ArffReader(reader);
model = arff.getData();
} finally {
IOUtils.closeQuietly(in);
}
} else {
FastVector schema = new FastVector();
model = new Instances("model", schema, 1);
}
Instance newInstance = new SparseInstance(0);
newInstance.setDataset(model);
for(Map.Entry<String,String> feature:currentInstanceFeatures.entrySet()) {
Attribute attribute = model.attribute(feature.getKey());
if (attribute == null) {
attribute = new Attribute(feature.getKey());
model.insertAttributeAt(attribute, model.numAttributes());
attribute = model.attribute(feature.getKey());
}
newInstance.setValue(attribute, feature.getValue());
}
model.add(newInstance);
model.compactify();
ArffSaver saver = new ArffSaver();
saver.setInstances(model);
saver.setFile(targetFile);
LOGGER.debug("Saving dataset to: " + targetFile.getAbsoluteFile());
saver.writeBatch();
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
I am getting Java Heap Space Error while writing large data from database to an excel sheet.
I dont want to use JVM -XMX options to increase memory.
Following are the details:
1) I am using org.apache.poi.hssf api
for excel sheet writing.
2) JDK version 1.5
3) Tomcat 6.0
Code i have wriiten works well for around 23 thousand records, but it fails for more than 23K records.
Following is the code:
ArrayList l_objAllTBMList= new ArrayList();
l_objAllTBMList = (ArrayList) m_objFreqCvrgDAO.fetchAllTBMUsers(p_strUserTerritoryId);
ArrayList l_objDocList = new ArrayList();
m_objTotalDocDtlsInDVL= new HashMap();
Object l_objTBMRecord[] = null;
Object l_objVstdDocRecord[] = null;
int l_intDocLstSize=0;
VisitedDoctorsVO l_objVisitedDoctorsVO=null;
int l_tbmListSize=l_objAllTBMList.size();
System.out.println(" getMissedDocDtlsList_NSM ");
for(int i=0; i<l_tbmListSize;i++)
{
l_objTBMRecord = (Object[]) l_objAllTBMList.get(i);
l_objDocList = (ArrayList) m_objGenerateVisitdDocsReportDAO.fetchAllDocDtlsInDVL_NSM((String) l_objTBMRecord[1], p_divCode, (String) l_objTBMRecord[2], p_startDt, p_endDt, p_planType, p_LMSValue, p_CycleId, p_finYrId);
l_intDocLstSize=l_objDocList.size();
try {
l_objVOFactoryForDoctors = new VOFactory(l_intDocLstSize, VisitedDoctorsVO.class);
/* Factory class written to create and maintain limited no of Value Objects (VOs)*/
} catch (ClassNotFoundException ex) {
m_objLogger.debug("DEBUG:getMissedDocDtlsList_NSM :Exception:"+ex);
} catch (InstantiationException ex) {
m_objLogger.debug("DEBUG:getMissedDocDtlsList_NSM :Exception:"+ex);
} catch (IllegalAccessException ex) {
m_objLogger.debug("DEBUG:getMissedDocDtlsList_NSM :Exception:"+ex);
}
for(int j=0; j<l_intDocLstSize;j++)
{
l_objVstdDocRecord = (Object[]) l_objDocList.get(j);
l_objVisitedDoctorsVO = (VisitedDoctorsVO) l_objVOFactoryForDoctors.getVo();
if (((String) l_objVstdDocRecord[6]).equalsIgnoreCase("-"))
{
if (String.valueOf(l_objVstdDocRecord[2]) != "null")
{
l_objVisitedDoctorsVO.setPotential_score(String.valueOf(l_objVstdDocRecord[2]));
l_objVisitedDoctorsVO.setEmpcode((String) l_objTBMRecord[1]);
l_objVisitedDoctorsVO.setEmpname((String) l_objTBMRecord[0]);
l_objVisitedDoctorsVO.setDoctorid((String) l_objVstdDocRecord[1]);
l_objVisitedDoctorsVO.setDr_name((String) l_objVstdDocRecord[4] + " " + (String) l_objVstdDocRecord[5]);
l_objVisitedDoctorsVO.setDoctor_potential((String) l_objVstdDocRecord[3]);
l_objVisitedDoctorsVO.setSpeciality((String) l_objVstdDocRecord[7]);
l_objVisitedDoctorsVO.setActualpractice((String) l_objVstdDocRecord[8]);
l_objVisitedDoctorsVO.setLastmet("-");
l_objVisitedDoctorsVO.setPreviousmet("-");
m_objTotalDocDtlsInDVL.put((String) l_objVstdDocRecord[1], l_objVisitedDoctorsVO);
}
}
}// End of While
writeExcelSheet(); // Pasting this method at the end
// Clean up code
l_objVOFactoryForDoctors.resetFactory();
m_objTotalDocDtlsInDVL.clear();// Clear the used map
l_objDocList=null;
l_objTBMRecord=null;
l_objVstdDocRecord=null;
}// End of While
l_objAllTBMList=null;
m_objTotalDocDtlsInDVL=null;
-------------------------------------------------------------------
private void writeExcelSheet() throws IOException
{
HSSFRow l_objRow = null;
HSSFCell l_objCell = null;
VisitedDoctorsVO l_objVisitedDoctorsVO = null;
Iterator l_itrDocMap = m_objTotalDocDtlsInDVL.keySet().iterator();
while (l_itrDocMap.hasNext())
{
Object key = l_itrDocMap.next();
l_objVisitedDoctorsVO = (VisitedDoctorsVO) m_objTotalDocDtlsInDVL.get(key);
l_objRow = m_objSheet.createRow(m_iRowCount++);
l_objCell = l_objRow.createCell(0);
l_objCell.setCellStyle(m_objCellStyle4);
l_objCell.setCellValue(String.valueOf(l_intSrNo++));
l_objCell = l_objRow.createCell(1);
l_objCell.setCellStyle(m_objCellStyle4);
l_objCell.setCellValue(l_objVisitedDoctorsVO.getEmpname() + " (" + l_objVisitedDoctorsVO.getEmpcode() + ")"); // TBM Name
l_objCell = l_objRow.createCell(2);
l_objCell.setCellStyle(m_objCellStyle4);
l_objCell.setCellValue(l_objVisitedDoctorsVO.getDr_name());// Doc Name
l_objCell = l_objRow.createCell(3);
l_objCell.setCellStyle(m_objCellStyle4);
l_objCell.setCellValue(l_objVisitedDoctorsVO.getPotential_score());// Freq potential score
l_objCell = l_objRow.createCell(4);
l_objCell.setCellStyle(m_objCellStyle4);
l_objCell.setCellValue(l_objVisitedDoctorsVO.getDoctor_potential());// Freq potential score
l_objCell = l_objRow.createCell(5);
l_objCell.setCellStyle(m_objCellStyle4);
l_objCell.setCellValue(l_objVisitedDoctorsVO.getSpeciality());//CP_GP_SPL
l_objCell = l_objRow.createCell(6);
l_objCell.setCellStyle(m_objCellStyle4);
l_objCell.setCellValue(l_objVisitedDoctorsVO.getActualpractice());// Actual practise
l_objCell = l_objRow.createCell(7);
l_objCell.setCellStyle(m_objCellStyle4);
l_objCell.setCellValue(l_objVisitedDoctorsVO.getPreviousmet());// Lastmet
l_objCell = l_objRow.createCell(8);
l_objCell.setCellStyle(m_objCellStyle4);
l_objCell.setCellValue(l_objVisitedDoctorsVO.getLastmet());// Previousmet
}
// Write OutPut Stream
try {
out = new FileOutputStream(m_objFile);
outBf = new BufferedOutputStream(out);
m_objWorkBook.write(outBf);
} catch (Exception ioe) {
ioe.printStackTrace();
System.out.println(" Exception in chunk write");
} finally {
if (outBf != null) {
outBf.flush();
outBf.close();
out.close();
l_objRow=null;
l_objCell=null;
}
}
}
Instead of populating the complete list in memory before starting to write to excel you need to modify the code to work in such a way that each object is written to a file as it is read from the database. Take a look at this question to get some idea of the other approach.
Well, I'm not sure if POI can handle incremental updates but if so you might want to write chunks of say 10000 Rows to the file. If not, you might have to use CSV instead (so no formatting) or increase memory.
The problem is that you need to make objects written to the file elligible for garbage collection (no references from a live thread anymore) before writing the file is finished (before all rows have been generated and written to the file).
Edit:
If can you write smaller chunks of data to the file you'd also have to only load the necessary chunks from the db. So it doesn't make sense to load 50000 records at once and then try and write 5 chunks of 10000, since those 50000 records are likely to consume a lot of memory already.
As Thomas points out, you have too many objects taking up too much space, and need a way to reduce that. There is a couple of strategies for this I can think of:
Do you need to create a new factory each time in the loop, or can you reuse it?
Can you start with a loop getting the information you need into a new structure, and then discarding the old one?
Can you split the processing into a thread chain, sending information forwards to the next step, avoiding building a large memory consuming structure at all?