Sunday, October 30, 2011

Full working runtime annotation example

Annotations are metadata(data about data) that allows you to keep an additional information right in your code. Annotations have been introduced into Java in 5th edition.

Before annotations almost all configuration data had to be kept in XML format. And as the application grew, the number and complexity of its XML-files had been increasing exponentially. They called it XML hell.

And now when we have annotations we can keep the configuration of the code right with it. Besides annotations are tested and verified by the compiler.

But the use of annotations is not limited to configuration, annotations allow you to get rid of the boilerplate code (e.g. cross-cutting concerns such as transactions and security).

The boon of annotations can be very easily noted using Hibernate Annotation package, Spring 2.5 and newer, Seam. But how do they write the annotations of their own?

So here is the definition of our annotation @Testing:
package com.test.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Testing { }
As you can see this definition is not much unlike of the definition of an interface. And really it compiles to the class file as any other Java interface. As you can see the annotation definition requires @Target and @Retention annotations:
  • @Target defines where you can use your annotation. In this example it can be used only with methods. Here are all possible values and places where you can use annotations:
    • TYPE - class, interface (including annotation type), or enum declaration 
    • FIELD - field declaration (includes enum constants)
    • METHOD - method declaration
    • PARAMETER - parameter declaration
    • CONSTRUCTOR - constructor declaration
    • LOCAL_VARIABLE - local variable declaration
    • ANNOTATION_TYPE - annotation type declaration 
    • PACKAGE - package declaration
  • @Retention defines when the annotation can be available:
    • SOURCE - in the source code (discarded by the compiler)
    • CLASS - in the class files (not retained at run time). This is the default behavior.
    • RUNTIME - at run time (can be read reflectively)
Often annotations contain some values (as @Target and @Retention above). These values are represented as interface methods in the definition. If an annotation does not have any element than it is called marker annotation.

We will use proxy pattern to allow our processor intercept the calls to the methods annotated with @Testing. Java provides implementation of the proxy with the java.lang.reflect.Proxy. It is very powerful tool but unfortunately it does not provide possibility to create proxies just for the class, you have to provide the list of interfaces to create the proxy (if you need to proxy classes and not just interfaces then you should use CGLib).

So let's create the annotation processor:
package com.test.annotation.processor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.test.annotation.Testing;

public class TestingInvocationHandler implements InvocationHandler {
 private Object proxied;
 
 public TestingInvocationHandler(Object proxied) {
  this.proxied = proxied; } 

 @Override
 public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable {
  Method m = proxied.getClass().getMethod(method.getName(), method.getParameterTypes());
  if (m.isAnnotationPresent(Testing.class)) {
   System.out.println("\tIn the annotation processor");   
  } 
  return method.invoke(proxied, args);
 }
}
The annotation processor implements InvocationHandler interface. This interface is responsible for handling the proxy object invocation.
As you can see we only print additional line before invoking the original method.

Here is the helper class with the static method to get the proxy object:
package com.test.annotation.processor;
import java.lang.reflect.Proxy;

public class TestingProxy {
 
 public static Object getNewProxy(Object proxied, Class<?> interfaze) {
  Object proxy = Proxy.newProxyInstance(
      TestingInvocationHandler.class.getClassLoader(),
      new Class[] {interfaze}, 
      new TestingInvocationHandler(proxied));
  return proxy;
 }

}
Let's define the interface
package com.test.service;

public interface Observable {
 void print1();
 
 void print2(); 
}
and the class of the proxied objects
package com.test.service;

import com.test.annotation.Testing;
import com.test.annotation.processor.TestingProxy;

public class PrintService implements Observable {
 private static Observable instance;
 private PrintService(){
  
 }
 public static Observable getInstance() {
  if (instance == null) {   
   instance = (Observable) TestingProxy.getNewProxy(new PrintService(),
     Observable.class);   
  }
  return instance;
 }
 
 @Testing
 public void print1() {
  System.out.println("1 - Text in annotated method");
 }
 
 public void print2() {
  System.out.println("2 - Just ususal text");
 }
}
This class is implemented as a simple singleton and uses the proxy object in getInstance() method. Also this class implements both methods of the interface. One of this methods is annotated and the other is not.

Finally let's create the class with the main method:
package com.test;

import com.test.service.Observable;
import com.test.service.PrintService;

public class Application {
 public static void main(String[] args) {
  Observable printService = PrintService.getInstance();  
  printService.print1();  
  printService.print2();
 }
}
That's all.

Thursday, October 27, 2011

Java FTP client

If you are looking for Java FTP client I suggest you to look at Apache Commons Net library. There is a class FTPClient. It is very easy to use and has all the functionality you may want to have.
To use this library we have to download it from the official site or add maven dependency:
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.0.1</version>
</dependency>
After this if we want to upload the file to the server we should do something like this:
public static boolean uploadFile(File file, String workingDirectory, String fileName) {
  FTPClient client = new FTPClient();
  try {
    client.connect(FTP_HOST, FTP_PORT);
    // After connection attempt, we have to check the reply code to
    // verify success.
    int reply = client.getReplyCode();
    if (!FTPReply.isPositiveCompletion(reply)) {
      System.err.println("FTP server refused connection.");
      return false;
    }
  
    client.login(FTP_USERNAME, FTP_PASSWORD);
    client.changeWorkingDirectory(workingDirectory);
    client.storeFile(fileName, new FileInputStream(file));
    client.logout();
    return true;
  } catch (SocketException e) {
    throw new RuntimeException(e);
  } catch (IOException e) {
    throw new RuntimeException(e);
  } finally {
    if (client.isConnected()) {
      try {
        client.disconnect();
      } catch (IOException ioe) {
        // swallow exception
        System.err.println("Cannot disconnect from the host");
      }
    }
  } 
}
If you need to download, delete or append file it would be pretty similar.
To get listing of directories you may need to enter local passive mode. Here is an example:
public static void printFiles(String workingDirectory) {
  FTPClient client = new FTPClient();
  try {
    client.connect(FTP_HOST, FTP_PORT);   
    // After connection attempt, we have to check the reply code to
    // verify success.
    int reply = client.getReplyCode();
    if (!FTPReply.isPositiveCompletion(reply)) {
      System.err.println("FTP server refused connection.");
    }
  
    client.enterLocalPassiveMode();
    client.login(FTP_USERNAME, FTP_PASSWORD);
    FTPFile[] files = client.listFiles(workingDirectory);
     
    for (FTPFile file : files) {
      System.out.println(file.getName());
    }
    client.logout();
  } catch (SocketException e) {
    throw new RuntimeException(e);
  } catch (IOException e) {
    throw new RuntimeException(e);
  } finally {
    if (client.isConnected()) {
      try {
        client.disconnect();
      } catch (IOException ioe) {
        // swallow exception
        System.err.println("Cannot disconnect from the host");
      }
    }
  }
}
It was easy wasn't it? To learn more see the documentation.

Tuesday, October 25, 2011

Recursively unzip archive in memory

In addition to the previous post about recursive unzipping you may need to unzip archive in memory. In this situation the following code will help you:

package com.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class Unzipper {
 private final static int BUFFER_SIZE = 2048;
 private final static String ZIP_EXTENSION = ".zip";
 
 public static void main(String[] args) throws IOException {
  File f = new File("/home/anton/test/test.zip");
  FileInputStream fis = new FileInputStream(f);
  BufferedInputStream bis = new BufferedInputStream(fis);
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  BufferedOutputStream bos = new BufferedOutputStream(baos);
  byte[] buffer = new byte[BUFFER_SIZE];
  while (bis.read(buffer, 0, BUFFER_SIZE) != -1) {
   bos.write(buffer);
  }
  bos.flush();
  bos.close();
  bis.close();
  List<ByteArrayOutputStream> listFiles =  unzip(baos);
 }

 public static List<ByteArrayOutputStream> unzip(
   ByteArrayOutputStream zippedFileOS) {
  try {
   ZipInputStream inputStream = new ZipInputStream(
     new BufferedInputStream(new ByteArrayInputStream(
       zippedFileOS.toByteArray())));
   ZipEntry entry;

   List<ByteArrayOutputStream> result = new ArrayList<ByteArrayOutputStream>();
   while ((entry = inputStream.getNextEntry()) != null) {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    System.out.println("\tExtracting entry: " + entry);
    int count;
    byte data[] = new byte[BUFFER_SIZE];

    if (!entry.isDirectory()) {
     BufferedOutputStream out = new BufferedOutputStream(
       outputStream, BUFFER_SIZE);
     while ((count = inputStream.read(data, 0, BUFFER_SIZE)) != -1) {
      out.write(data, 0, count);
     }
     out.flush();
     out.close();
     // recursively unzip files
     if (entry.getName().toLowerCase().endsWith(ZIP_EXTENSION)) {
      result.addAll(unzip(outputStream));
     } else {
      result.add(outputStream);
     }
    }
   }
   inputStream.close();
   return result;
  } catch (Exception e) {
   throw new RuntimeException(e);
  }
 }
}

You may also want to check how to recursively unzip archive to file

Recursively unzip archive

Once I had to unzip some difficult zip archive that consisted of inner zip archives, directories and files. I have googled for examples, though there were some solutions I didn't find the perfect one for me. So I decided to develop my own unzipper. Here is it, feel free to use it:

package com.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class Unzipper {  
    private final static int BUFFER_SIZE = 2048;
    private final static String ZIP_FILE = "/home/anton/test/test.zip";
    private final static String DESTINATION_DIRECTORY = "/home/anton/test/";
    private final static String ZIP_EXTENSION = ".zip";
 
    public static void main(String[] args) {
     System.out.println("Trying to unzip file " + ZIP_FILE); 
        Unzipper unzip = new Unzipper();  
        if (unzip.unzipToFile(ZIP_FILE, DESTINATION_DIRECTORY)) {
         System.out.println("Succefully unzipped to the directory " 
             + DESTINATION_DIRECTORY);
        } else {
         System.out.println("There was some error during extracting archive to the directory " 
             + DESTINATION_DIRECTORY);
        }
    } 

 public boolean unzipToFile(String srcZipFileName,
   String destDirectoryName) {
  try {
   BufferedInputStream bufIS = null;
   // create the destination directory structure (if needed)
   File destDirectory = new File(destDirectoryName);
   destDirectory.mkdirs();

   // open archive for reading
   File file = new File(srcZipFileName);
   ZipFile zipFile = new ZipFile(file, ZipFile.OPEN_READ);

   //for every zip archive entry do
   Enumeration<? extends ZipEntry> zipFileEntries = zipFile.entries();
   while (zipFileEntries.hasMoreElements()) {
    ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
    System.out.println("\tExtracting entry: " + entry);

    //create destination file
    File destFile = new File(destDirectory, entry.getName());

    //create parent directories if needed
    File parentDestFile = destFile.getParentFile();    
    parentDestFile.mkdirs();    
    
    if (!entry.isDirectory()) {
     bufIS = new BufferedInputStream(
       zipFile.getInputStream(entry));
     int currentByte;

     // buffer for writing file
     byte data[] = new byte[BUFFER_SIZE];

     // write the current file to disk
     FileOutputStream fOS = new FileOutputStream(destFile);
     BufferedOutputStream bufOS = new BufferedOutputStream(fOS, BUFFER_SIZE);

     while ((currentByte = bufIS.read(data, 0, BUFFER_SIZE)) != -1) {
      bufOS.write(data, 0, currentByte);
     }

     // close BufferedOutputStream
     bufOS.flush();
     bufOS.close();

     // recursively unzip files
     if (entry.getName().toLowerCase().endsWith(ZIP_EXTENSION)) {
      String zipFilePath = destDirectory.getPath() + File.separatorChar + entry.getName();

      unzipToFile(zipFilePath, zipFilePath.substring(0, 
              zipFilePath.length() - ZIP_EXTENSION.length()));
     }
    }
   }
   bufIS.close();
   return true;
  } catch (Exception e) {
   e.printStackTrace();
   return false;
  }
 } 
}  
I have placed some comments inline so now it seems pretty straightforward, but if you have some questions feel free to ask them.
You may also want to check how to recursively unzip archive in memory

Monday, October 24, 2011

The most useful Eclipse Hot Keys

As you know hot keys may significantly increase you development speed. I believe every developer knows a list of the most used hot keys in his favorite IDE.
Because I usually work with Eclipse I have my own list with this IDE. Here is the list of the most useful commands:
  • Ctrl + Space - content assist
  • Ctrl + Shift + Space - context information
  • Ctrl + Shift + R - open resource
  • Ctrl + Shift + T - open type
  • Ctrl + Shift + G - find references in the workspace
  • Ctrl + H - search
  • Ctrl + L - go to line
  • Ctrl + W - close window
  • Ctrl + Shift + W - close all windows
  • Alt + Left - back history
  • Alt + Right - forward history
  • Ctrl + Shift + divide ('/') - collapse all
  • Ctrl + D - delete line
  • Ctrl + 8 - new editor in the same window, you can have as many as you wish
  • F2 - show tooltip
  • F3 or Ctrl + lmb click - open declaration
  • F4 - open type hierarchy
  • F12 - switch between source and design views
  • Ctrl + Shift + H - open type in hierarchy
  • Ctrl + E and Ctrl + Shift + E - switch to editor
  • Ctrl + Shift + Slash ('/') - add block comment
  • Ctrl + Shift + Backslash('\') - remove block comment
  • Ctrl + 7 or Ctrl + Slash ('/') or Ctrl + Shift + C - add/remove line comment
  • Ctrl + Shift + O - organize imports
  • Ctrl + Shift + F - format
  • Ctrl + Shift + I - inspect (use in debug)
  • Alt + Shift + O - mark occurances
  • Ctrl + O - quick outline
  • Alt + Shift + S - source quick menu

How to make correct classloading using JBoss AS 5.1

After I have added new functionality to my project I've spent a lot of time trying to make it work with JBoss AS 5.1 . The problem was that JBoss AS 5.1 has some libraries in the package with itself (look $JBOSS_HOME/lib, $JBOSS_HOME/lib/endorsed, $JBOSS_HOME/common/lib) and I wanted to use different version then provided with JBoss. But let's tell about everything consequently.

At first I tried to do nothing specific and have just specified my maven dependencies with compile scope. And of course I got exception:
java.lang.ClassCastException: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl cannot be cast to javax.xml.parsers.DocumentBuilderFactory
    at javax.xml.parsers.DocumentBuilderFactory.newInstance(Unknown Source)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:694)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:618)
    at org.apache.log4j.helpers.OptionConverter.selectAndConfigure(OptionConverter.java:470)
    at org.apache.log4j.LogManager.<clinit>(LogManager.java:122)
    ... 82 more

At first I got flabbergasted. What does this exception mean? I don't even use Apache Xerces in my project.
So that means one of libraries I use is dependent on it. Then I tried to write separate mock project for this newly added libraries. And it worked fine. Then it means JBoss is involved with this exception. And of course it is. JBoss had the xercesImpl.jar in $JBOSS_HOME/lib/endorsed.

So here we have version conflict. What can we do in this situation. There are some solutions to this situation:
  1. Remove all conflicting jars from your application (make all conflicting maven dependencies in provided scope). But in my opinion, this is bad idea, because
    • it would make the application dependent on Application Server
    • it may result in a lot of rework on currently good working code 
  2. Change JBoss AS libraries with the correct versions (all conflicting maven dependencies should be in provided scope). But it has another problems:
    • you have to reconfigure your server; if you develop in team then all your teammates have to do the same with their working environment;
    • it may result in LinkageError. In my case it meant that QName class was already loaded by boot Classloader and it means that I cannot use it in my classes(loaded by another Classloader). If you're interested about this error see link1 and link2.
      • java.lang.LinkageError: loader constraint violation: when resolving method
            "org.apache.axis2.description.AxisOperation.setName(Ljavax/xml/namespace/QName;)V"
            the class loader (instance of org/jboss/classloader/spi/base/BaseClassLoader) of 
            the current class, some/path/to/my/class, and the class loader 
            (instance of <bootloader>) for resolved class, 
            org/apache/axis2/description/AxisOperation, have different Class objects for 
            the type javax/xml/namespace/QName used in the signature
  3. Configure JBoss AS classloading for the war with jboss-classloading.xml in your war/ear/jar. This is the best solution on my opinion. Because your application would be still Application Server independent(other servers won't pay attention to this additional file) and does not require additional configuration of Application Server.
So let's discuss the third solution. At first you have to create new jboss-classloading.xml in the correct location:
  • If your application is WAR then place it in /WEB-INF/
  • If your application is EAR or JAR then place it in /META-INF/
And put configuration there. Here is the configuration that worked for me:
<classloading xmlns="urn:jboss:classloading:1.0"
    name="myApp.war"
    parent-first="false"
    domain="DefaultDomain"
    top-level-classloader="true"
    parent-domain="Ignored"
    export-all="NON_EMPTY"
    import-all="true">
</classloading>
The meaning of attributes:
  • name - usually the name of war/ear/jar
  • parent-first (true/false) - the classloader should load at first everything from your war/ear/jar and then from parent(in case of war/jar within ear it would mean ear, otherwise it's JBossAS)
  • domain - classloading domain, if it already exists then you will add your application there
  • top-level-classloader (true/false) - allows you to take part in parent classloading
  • parent-domain - delegates the classloading for the specified domain if the class is not available in the current domain
  • export-all - exposes your classes to other applications
  • import-all (true/false) - import exposes classes from other applications
That's all. In conclusion here is the links that helped me with this error:

    Sunday, October 23, 2011

    Reading Excel files with Apache POI(usermodel)

    Recently I have stumbled upon need to read spreadsheet data from usual Excel files. After some research I have found that the most suitable solution for me is to use Apache POI. It works fine, simple to use, has a long history(10 years) and is still alive.

    The POI API is full of acronyms, the meanings of which is not understandable (e.g. HSSF, XSSF, SXSSF) until you read the documentation. So let's start with some definitions:
    • HSSF(Horrible SpreadSheet Format) is the POI Project's pure Java implementation of the Excel '97(-2007) file format. 
    • XSSF (XML SpreadSheet Format) is the POI Project's pure Java implementation of the Excel 2007 OOXML (.xlsx) file format.
    • SXSSF is an API-compatible streaming extension of XSSF to be used when very large spreadsheets have to be produced, and heap space is limited. It's built on top of XSSF. Available only since 3.8-beta3.
    Before I show you some examples of work I want you to be aware of additional complexities in POI. There are different ways to read files. The API provides us with 2 capabilities, they are:
    • UserModel
    • UserEventModel. 
    The first one is really straightforward and easy to use, but the second one is much more intricate and is based upon reading files using SAX (e. g. Apache Xerces). And by the way if you need to load big files then you should choose usereventmodel because usermodel consumes a lot of memory and it's very likely you will become the victim of the dreadful Java OutOfMemory exception. And if you need to write to SpreadSheet then you have no choice and will be forced to use usermodel. In this article we will see the usage of usermodel API for reading.
    Figure 1. Spreadsheet API Feature Summary

    So at first you need to download the library from official site or to configure maven dependencies. I prefer the second option, so here are dependencies (I got them from mvnrepository.com):

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>3.5-FINAL</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-contrib</artifactId>
        <version>3.5-FINAL</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.5-FINAL</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>

    There are two ways to read data in usermodel:
    • Read only data and no null value. It usually produces ragged arrays(depends on your data)
    • Read all data (inclusive nulls)
    Now let's create the code to read all data:

    public List<List<String>> parseSpreadSheet(InputStream inputStream) {
        Workbook workBook = null;
        try {
            workBook = WorkbookFactory.create(inputStream);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        Sheet sheet = workBook.getSheetAt(0);    
        List<List<String>> rowHolder = new ArrayList<List<String>>();
        int cellNum = sheet.getRow(1).getLastCellNum();    
    
        for (int i = 0; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            List<String> cellHolder = new ArrayList<String>();
    
            for (int j = 0; j < row.getLastCellNum(); j++) {
                Cell cell = row.getCell(j);           
                String cellValue = parseCellValue(workBook, cell);
                cellHolder.add(cellValue);
            }
    
            //add empty cells to the end if required
            while (cellHolder.size() < cellNum) {
                cellHolder.add(null);                   
            }
            rowHolder.add(cellHolder);    
        }
        return rowHolder;
    }
    


    The return type of the method is Java SpreadSheet representation (selected by me). The argument of the method is InputStream of the SpreadSheet file.

    I have decided to use Workbook(represents Excel file), which is the parent class of HSSFWorkbook and XSSFWorkbook. WorkbookFactory frees you from necessity to write conditions for different kinds of files (xls and xlsx), it creates appropriate descendant class from InputStream. The rest of the code is simple(The code of parseCellValue() method I will show later).

    We need the method to parse cell values:

    private String parseCellValue(Workbook workBook, Cell cell) {       
        FormulaEvaluator evaluator = workBook.getCreationHelper().createFormulaEvaluator();
        String cellValue = null;               
        if (cell != null) {
            switch (cell.getCellType()) {
                case Cell.CELL_TYPE_STRING:
                    cellValue = cell.getRichStringCellValue().getString();
                    break;
                case Cell.CELL_TYPE_NUMERIC:
                    if (DateUtil.isCellDateFormatted(cell)) {
                        cellValue = cell.getDateCellValue().toString();
                    } else {
                        cellValue = new Double(cell.getNumericCellValue()).toString();
                    }
                    break;
                case Cell.CELL_TYPE_BOOLEAN:
                    cellValue = new Boolean(cell.getBooleanCellValue()).toString();
                    break;
                case Cell.CELL_TYPE_FORMULA:
                    cellValue = evaluator.evaluate(cell).formatAsString();
                    break;
            }                   
        }
        return cellValue;
    }
    

    As you can see we should parse cell value according to its Excel format. Note POI UserAPI is pretty powerful it even allows us to evaluate formula values.

    And finally here's the way you can read all data but null values. This type of reading is based upon iterators of Row and Cell:

    public List<List<String>> readSpreadSheetWOnull(InputStream inputStream) {
        Workbook workBook = null;
        try {
            workBook = WorkbookFactory.create(inputStream);
            Sheet sheet = workBook.getSheetAt(SHEET_NUMBER);
    
            Iterator<Row> rowIter = sheet.rowIterator();
    
            List<List<String>> rowHolder = new ArrayList<List<String>>();
            while (rowIter.hasNext()) {
                Row row = (Row) rowIter.next();
                Iterator<Cell> cellIter = row.cellIterator();
    
                List<String> cellHolder = new ArrayList<String>();
                while (cellIter.hasNext()) {
                    Cell cell = (Cell) cellIter.next();
                    String cellValue = parseCellValue(workBook, cell);
                    cellHolder.add(cellValue);
                }
                rowHolder.add(cellHolder);
            }
            return rowHolder;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    

    That's all. Later I will write a post about UserEventModel

    Conditional breakpoints in Eclipse

    There is a very useful feature in many IDEs, that makes bug fixing much easier. I'm talking about conditional breakpoints. But unfortunately in Eclipse IDE its location is quite unintuitive
    So to put conditional breakpoint you should:
    1. Put usual breakpoint. It may be done by clicking on the left margin of the editor or pressing Ctrl+Shift+B while you're on the line.
      Figure 1. Breakpoint marker in the left margin of the editor
    2. Right click on the breakpoint marker int the editor's left margin and select "Breakpoint properties..."
    3. In the appeared window tick "Conditional" and enter your condition in the editor. Note that key assist is available in this editor. 
    4. Figure 2. Breakpoint properties window configured for conditional breakpoint
      • If you want to stop every time expression returns true then select "Suspend when 'true'"
      • If you want to stop only when expression changes its value then select "Suspend when value changes"
    5.  Press OK. Note the breakpoint marker has changed.
    Figure 3. Conditional breakpoint marker in the left margin of the editor

    Saturday, October 22, 2011

    opencsv is an easy CSV parser

    A lot of data is transported via CSV (comma-separated value) format. This format contains data in plain-text form and therefore the data is easily readable by man. File in CSV format may be separated not only by commas but by any other delimiter. Also it may contain quotes or not(to learn more visit wikipedia) So to manage these difficulties it would be more efficient to use some library.

    Whenever you need to parse or generate CSV file I'd recommend you to look at opencsv tool. It's very lightweight and easy to use. You can find some examples on the tool's site, but I want to provide you with some more.

    To use opencsv you should download it from Sourceforge or if you use maven then add new dependency(I recommend to use mvnrepository.com to look for dependencies):
    <dependency>
        <groupId>net.sf.opencsv</groupId>
        <artifactId>opencsv</artifactId>
        <version>2.3</version>
    </dependency>
    
    The reading is pretty straightforward:
    CSVReader reader = new CSVReader(new InputStreamReader(inputStream), ',', '"', 1);
    String[] nextLine;
    while ((nextLine = reader.readNext()) != null) {
      if (nextLine != null) {
        //do your work
      }
    }
    
    In nextLine variable you have separated values of some CSV file row. And you can work with it as with an usual String array.

    As you can see I use the constructor which sets reader of underlying CSV source ( java.io.Reader), separator character, quote character and number of lines to skip(e.g. your first line contains column headers). You can as well use any other kind of constructor:
    CSVReader reader = new CSVReader(new InputStreamReader(inputStream), ',', '"');
    CSVReader reader = new CSVReader(new InputStreamReader(inputStream), ',');
    CSVReader reader = new CSVReader(new InputStreamReader(inputStream)); //use comma as a separator
    
    The writing with opencsv is also easy. Check this:
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    CSVWriter writer = new CSVWriter(new OutputStreamWriter(baos), ',',
    CSVWriter.DEFAULT_QUOTE_CHARACTER, CSVWriter.NO_ESCAPE_CHARACTER, "\n");
    String[] entries = getStringArray();
    writer.writeNext(entries);
    writer.close()
    I have created CSVWriter providing constructor with the writer to an underlying CSV source (java.io.Writer), separator character, quote character, escape character (I decided to disable auto-escaping of opencsv and do it somewhere else) and line break. As the simple example of usage you can look here. For more detailed information see javadoc.

    opencsv also provides possibility to map CSV file to a list of JavaBeans. Here is example from http://opencsv.sourceforge.net/ :
    ColumnPositionMappingStrategy strat = new ColumnPositionMappingStrategy();
    strat.setType(YourOrderBean.class);
    String[] columns = new String[] {"name", "orderNumber", "id"}; // the fields to bind do in your JavaBean
    strat.setColumnMapping(columns);
    
    CsvToBean csv = new CsvToBean();
    List list = csv.parse(strat, yourReader);
    

    For more detailed examples, check out the test cases for each of the available mapping strategies under the /test/au/com/bytecode/opencsv/bean/.