diff --git a/common/source/java/ch/systemsx/cisd/common/parser/DefaultReaderParser.java b/common/source/java/ch/systemsx/cisd/common/parser/DefaultParser.java
similarity index 70%
rename from common/source/java/ch/systemsx/cisd/common/parser/DefaultReaderParser.java
rename to common/source/java/ch/systemsx/cisd/common/parser/DefaultParser.java
index 3ae7b838629f7cb603635b8abc082a3fd136ebb7..65f2fd2c36f7762870974678d06ab23c14345f45 100644
--- a/common/source/java/ch/systemsx/cisd/common/parser/DefaultReaderParser.java
+++ b/common/source/java/ch/systemsx/cisd/common/parser/DefaultParser.java
@@ -16,15 +16,12 @@
 
 package ch.systemsx.cisd.common.parser;
 
-import java.io.Reader;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.LineIterator;
-
 /**
- * A default <code>IReaderParser</code> implementation.
+ * A default {@link IParser} implementation.
  * <p>
  * The object type returned by this implementation is generic. This implementation defines a <code>ILineFilter</code>
  * that filters out comment and empty lines.
@@ -32,18 +29,24 @@ import org.apache.commons.io.LineIterator;
  * 
  * @author Christian Ribeaud
  */
-public class DefaultReaderParser<E> implements IReaderParser<E>
+public class DefaultParser<E> implements IParser<E>
 {
     private final ILineTokenizer lineTokenizer;
 
     private IParserObjectFactory<E> factory;
 
-    public DefaultReaderParser()
+    /**
+     * Creates an instance based on the {@link DefaultLineTokenizer}.
+     */
+    public DefaultParser()
     {
         this(new DefaultLineTokenizer());
     }
 
-    public DefaultReaderParser(final ILineTokenizer lineTokenizer)
+    /**
+     * Creates an instance for the specified line tokenizer.
+     */
+    public DefaultParser(final ILineTokenizer lineTokenizer)
     {
         this.lineTokenizer = lineTokenizer;
     }
@@ -61,7 +64,7 @@ public class DefaultReaderParser<E> implements IReaderParser<E>
      * 
      * @param lineNumber line number.
      */
-    protected String[] parseLine(final int lineNumber, final String line)
+    private String[] parseLine(final int lineNumber, final String line)
     {
         return lineTokenizer.tokenize(line);
     }
@@ -70,35 +73,31 @@ public class DefaultReaderParser<E> implements IReaderParser<E>
     // Parser
     //
 
-    public final List<E> parse(final Reader reader)
-    {
-        return parse(reader, AlwaysAcceptLineFilter.INSTANCE);
-    }
-
-    public final List<E> parse(final Reader reader, final ILineFilter lineFilter) throws ParsingException
+    public final List<E> parse(final Iterator<Line> lineIterator, final ILineFilter lineFilter) throws ParsingException
     {
         final List<E> elements = new ArrayList<E>();
         synchronized (lineTokenizer)
         {
             lineTokenizer.init();
-            final LineIterator lineIterator = IOUtils.lineIterator(reader);
-            for (int lineNumber = 0; lineIterator.hasNext(); lineNumber++)
+            while (lineIterator.hasNext())
             {
-                final String nextLine = lineIterator.nextLine();
-                if (lineFilter.acceptLine(nextLine, lineNumber))
+                Line line = lineIterator.next();
+                final String nextLine = line.getText();
+                int number = line.getNumber();
+                if (lineFilter.acceptLine(nextLine, number))
                 {
-                    final String[] tokens = parseLine(lineNumber, nextLine);
+                    final String[] tokens = parseLine(number, nextLine);
                     E object = null;
                     try
                     {
                         object = createObject(tokens);
                     } catch (final ParserException parserException)
                     {
-                        throw new ParsingException(parserException, tokens, lineNumber);
+                        throw new ParsingException(parserException, tokens, number);
                     } catch (final RuntimeException runtimeException)
                     {
                         // This should not happen but...
-                        throw new ParsingException(runtimeException, tokens, lineNumber);
+                        throw new ParsingException(runtimeException, tokens, number);
                     }
                     elements.add(object);
                 }
diff --git a/common/source/java/ch/systemsx/cisd/common/parser/IParser.java b/common/source/java/ch/systemsx/cisd/common/parser/IParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..c83eb104c156ff817f74cd2781a6dc5a329cbdb1
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/parser/IParser.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.parser;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * <code>IReaderParser</code> is able to parse a given text lines and to return a list of objects of type
+ * <code>E</code>.
+ * 
+ * @author Christian Ribeaud
+ */
+public interface IParser<E>
+{
+
+    /**
+     * Parses the lines delivered by the specified iterator and creating elements of type <code>E</code>.
+     * 
+     * @param lineFilter A filter lines have to pass in order to be parsed.
+     * @return a <code>List</code> of elements.
+     */
+    public List<E> parse(final Iterator<Line> lineIterator, final ILineFilter lineFilter) throws ParsingException;
+
+    /**
+     * Sets the <code>IParserObjectFactory</code>.
+     * <p>
+     * Typically, the given <code>factory</code> transforms a line into an element.
+     * </p>
+     */
+    public void setObjectFactory(final IParserObjectFactory<E> factory);
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactory.java b/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactory.java
index 27eb3b269830b303f8ee23111efb08f5744cce1f..107c438e41c340700d619bfc31f3e83ed66a1766 100644
--- a/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactory.java
+++ b/common/source/java/ch/systemsx/cisd/common/parser/IParserObjectFactory.java
@@ -20,7 +20,7 @@ package ch.systemsx.cisd.common.parser;
  * A <code>IParserObjectFactory</code> implementation knows how to deal with given line tokens and convert them into
  * an appropriate <code>Object</code>.
  * <p>
- * A <code>IParserObjectFactory</code> is typically registered in {@link IReaderParser}.
+ * A <code>IParserObjectFactory</code> is typically registered in {@link IParser}.
  * </p>
  * 
  * @author Christian Ribeaud
diff --git a/common/source/java/ch/systemsx/cisd/common/parser/IReaderParser.java b/common/source/java/ch/systemsx/cisd/common/parser/IReaderParser.java
deleted file mode 100644
index 65325b2538fcd92c97da2724b18712fb1dab2e65..0000000000000000000000000000000000000000
--- a/common/source/java/ch/systemsx/cisd/common/parser/IReaderParser.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2007 ETH Zuerich, CISD
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ch.systemsx.cisd.common.parser;
-
-import java.io.BufferedReader;
-import java.io.Reader;
-import java.util.List;
-
-/**
- * <code>IReaderParser</code> is able to parse a given {@link Reader} and to returns <code>Object</code> instances.
- * 
- * @author Christian Ribeaud
- */
-public interface IReaderParser<E>
-{
-
-    /**
-     * Parses given <code>Reader</code>. Encapsulates given <code>Reader</code> in a {@link BufferedReader} for
-     * better performance (if not already done).
-     * <p>
-     * Note that this does not close given <code>Parser</code>. It is your responsability to do so.
-     * </p>
-     * 
-     * @param lineFilter you could define a filter for the lines found in given <code>reader</code>.
-     * @return a <code>List</code> of elements.
-     */
-    public List<E> parse(final Reader reader, final ILineFilter lineFilter) throws ParsingException;
-
-    /**
-     * Parses given <code>Reader</code>. Encapsulates given <code>Reader</code> in a {@link BufferedReader} for
-     * better performance (if not already done).
-     * <p>
-     * Note that this does not close given <code>Parser</code>. It is your responsability to do so.
-     * </p>
-     * 
-     * @return a <code>List</code> of elements.
-     */
-    public List<E> parse(final Reader reader);
-
-    /**
-     * Sets the <code>IParserObjectFactory</code>.
-     * <p>
-     * Typically, the given <code>factory</code> transforms a line into an element.
-     * </p>
-     */
-    public void setObjectFactory(final IParserObjectFactory<E> factory);
-}
diff --git a/common/source/java/ch/systemsx/cisd/common/parser/Line.java b/common/source/java/ch/systemsx/cisd/common/parser/Line.java
new file mode 100644
index 0000000000000000000000000000000000000000..332b4086fde5a6e695897e562138fb224eabdd74
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/parser/Line.java
@@ -0,0 +1,32 @@
+package ch.systemsx.cisd.common.parser;
+
+/**
+ * A small object that represents a line in a <code>File</code> context.
+ * 
+ * @author Christian Ribeaud
+ */
+public final class Line
+{
+    private final String text;
+
+    private final int number;
+
+    Line(final int number, final String text)
+    {
+        assert text != null : "Unspecified text.";
+        this.number = number;
+        this.text = text;
+    }
+
+    public final String getText()
+    {
+        return text;
+    }
+
+    public final int getNumber()
+    {
+        return number;
+    }
+    
+    
+}
\ No newline at end of file
diff --git a/common/source/java/ch/systemsx/cisd/common/parser/ParserUtilities.java b/common/source/java/ch/systemsx/cisd/common/parser/ParserUtilities.java
index 14983891d65565bc7174572255e8024c81917ec5..9bd5e73c9e4a4e6e66c1389dd857060aaae7ad57 100644
--- a/common/source/java/ch/systemsx/cisd/common/parser/ParserUtilities.java
+++ b/common/source/java/ch/systemsx/cisd/common/parser/ParserUtilities.java
@@ -41,24 +41,6 @@ public final class ParserUtilities
         // Can not be instantiated.
     }
 
-    /**
-     * A small object that represents a line in a <code>File</code> context.
-     * 
-     * @author Christian Ribeaud
-     */
-    public final static class Line
-    {
-        public final String text;
-
-        public final int number;
-
-        Line(final int number, final String text)
-        {
-            this.number = number;
-            this.text = text;
-        }
-    }
-
     /**
      * Returns the first <code>Line</code> that is not filtered out by given <code>ILineFilter</code>.
      * <p>
diff --git a/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java b/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java
index 308f92ae9851da63c32a049c84d7f2e290c99e57..fe740329977886fccffb156d437064481b6f2c80 100644
--- a/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java
+++ b/common/source/java/ch/systemsx/cisd/common/parser/TabFileLoader.java
@@ -19,11 +19,16 @@ package ch.systemsx.cisd.common.parser;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.LineIterator;
 import org.apache.commons.lang.StringUtils;
 
 import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
@@ -36,6 +41,7 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
  */
 public class TabFileLoader<T>
 {
+    private static final String PREFIX = "#";
 
     private final IParserObjectFactoryFactory<T> factory;
 
@@ -58,23 +64,11 @@ public class TabFileLoader<T>
         assert file != null : "Given file must not be null";
         assert file.isFile() : "Given file '" + file.getAbsolutePath() + "' is not a file.";
 
-        final DefaultReaderParser<T> parser = new DefaultReaderParser<T>();
-        final ParserUtilities.Line headerLine =
-                ParserUtilities.getFirstAcceptedLine(file, ExcludeEmptyAndCommentLineFilter.INSTANCE);
-        if (headerLine == null)
-        {
-            throw new IllegalArgumentException("No header line found in file '" + file.getAbsolutePath() + "'.");
-        }
-        final HeaderLineFilter lineFilter = new HeaderLineFilter(headerLine.number);
-        final String[] tokens = StringUtils.split(headerLine.text, "\t");
-        notUnique(tokens);
-        final IAliasPropertyMapper propertyMapper = new HeaderFilePropertyMapper(tokens);
-        parser.setObjectFactory(factory.createFactory(propertyMapper));
         FileReader reader = null;
         try
         {
             reader = new FileReader(file);
-            return parser.parse(reader, lineFilter);
+            return load(reader);
         } catch (IOException ex)
         {
             throw new EnvironmentFailureException(ex.getMessage());
@@ -87,6 +81,65 @@ public class TabFileLoader<T>
             IOUtils.closeQuietly(reader);
         }
     }
+    
+    
+    List<T> load(Reader reader)
+    {
+        Iterator<Line> lineIterator = createLineIterator(reader);
+        Line previousLine = null;
+        Line line = new Line(0, PREFIX);
+        boolean previousLineHasColumnHeaders = false;
+        while (lineIterator.hasNext())
+        {
+            previousLineHasColumnHeaders = previousLine != null && PREFIX.equals(previousLine.getText());
+            previousLine = line;
+            line = lineIterator.next();
+            if (line.getText().startsWith(PREFIX) == false)
+            {
+                break;
+            }
+        }
+        String headerLine = previousLineHasColumnHeaders ? previousLine.getText().substring(1) : line.getText();
+        
+        final DefaultParser<T> parser = new DefaultParser<T>();
+        final String[] tokens = StringUtils.split(headerLine, "\t");
+        notUnique(tokens);
+        final IAliasPropertyMapper propertyMapper = new HeaderFilePropertyMapper(tokens);
+        parser.setObjectFactory(factory.createFactory(propertyMapper));
+        ILineFilter filter = AlwaysAcceptLineFilter.INSTANCE;
+        List<T> result = new ArrayList<T>();
+        if (previousLineHasColumnHeaders)
+        {
+            result.addAll(parser.parse(Arrays.asList(line).iterator(), filter));
+        }
+        result.addAll(parser.parse(lineIterator, filter));
+        return result;
+    }
+
+    private Iterator<Line> createLineIterator(Reader reader)
+    {
+        final LineIterator lineIterator = IOUtils.lineIterator(reader);
+        Iterator<Line> iterator = new Iterator<Line>()
+            {
+                private int lineNumber;
+                public void remove()
+                {
+                    lineIterator.remove();
+                }
+
+                public Line next()
+                {
+                    return new Line(++lineNumber, lineIterator.nextLine());
+                }
+
+                public boolean hasNext()
+                {
+                    return lineIterator.hasNext();
+                }
+
+            };
+        return iterator;
+    }
 
     /**
      * Throws given <var>ex</var> or translates it into another kind of exception.
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultReaderParserTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultParserTest.java
similarity index 50%
rename from common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultReaderParserTest.java
rename to common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultParserTest.java
index afb4717ea3ff2e1d9c946b7bf3f07b463b11c216..bd988ecd83c09e313d558a90298cfc9d427fed1b 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultReaderParserTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/parser/DefaultParserTest.java
@@ -18,56 +18,52 @@ package ch.systemsx.cisd.common.parser;
 
 import static org.testng.AssertJUnit.assertEquals;
 
-import java.io.Reader;
-import java.io.StringReader;
+import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 
-import org.apache.commons.io.IOUtils;
 import org.testng.annotations.Test;
 
 /**
- * Test cases for corresponding {@link DefaultReaderParser} class.
+ * Test cases for corresponding {@link DefaultParser} class.
  * 
  * @author Christian Ribeaud
  */
-public final class DefaultReaderParserTest
+public final class DefaultParserTest
 {
-    private final String text =
-            "\n# This is a comment\n" + "firstName\tlastName\taddress\tcity\n"
-                    + "Christian\tRibeaud\tKapfrain 2/2\tEfringen-Kirchen\n"
-                    + "Marcel\tOdiet\tRue des Pervenches 46\t2800 DelŽmont\n";
+    private final static List<String> text 
+            = Arrays.asList("", "# This is a comment", "firstName\tlastName\taddress\tcity",
+                            "Charles\tDarwin\tHumboldt Ave. 1865\t4242 Somewhere",
+                            "Albert\tEinstein\tNewton Road 1905\t4711 Princton");
 
     @Test
     public final void testParseWithoutFactoryAndHeader()
     {
-        final IReaderParser<String[]> parser = new DefaultReaderParser<String[]>();
+        final IParser<String[]> parser = new DefaultParser<String[]>();
         parser.setObjectFactory(IParserObjectFactory.STRING_ARRAY_OBJECT_FACTORY);
-        final Reader reader = new StringReader(text);
-        final List<String[]> result = parser.parse(reader, new HeaderLineFilter());
+        final List<String[]> result = parser.parse(createLineIterator(), new HeaderLineFilter());
         assertEquals(3, result.size());
         assertEquals(result.get(0)[0], "firstName");
-        assertEquals(result.get(1)[1], "Ribeaud");
-        assertEquals(result.get(2)[2], "Rue des Pervenches 46");
-        IOUtils.closeQuietly(reader);
+        assertEquals(result.get(1)[1], "Darwin");
+        assertEquals(result.get(2)[2], "Newton Road 1905");
+        assertEquals(result.get(1)[3], "4242 Somewhere");
     }
 
     @Test
     public final void testParseWithoutFactoryWithLineFilter()
     {
-        final IReaderParser<String[]> parser = new DefaultReaderParser<String[]>();
+        final IParser<String[]> parser = new DefaultParser<String[]>();
         parser.setObjectFactory(IParserObjectFactory.STRING_ARRAY_OBJECT_FACTORY);
-        final Reader reader = new StringReader(text);
-        final List<String[]> result = parser.parse(reader, new HeaderLineFilter(2));
+        final List<String[]> result = parser.parse(createLineIterator(), new HeaderLineFilter(2));
         assertEquals(2, result.size());
-        assertEquals(result.get(0)[1], "Ribeaud");
-        assertEquals(result.get(1)[2], "Rue des Pervenches 46");
-        IOUtils.closeQuietly(reader);
+        assertEquals(result.get(0)[0], "Charles");
+        assertEquals(result.get(1)[1], "Einstein");
     }
 
     @Test
     public final void testCreateObjectWithException()
     {
-        final IReaderParser<String[]> parser = new DefaultReaderParser<String[]>()
+        final IParser<String[]> parser = new DefaultParser<String[]>()
             {
                 //
                 // DefaultReaderParser
@@ -79,16 +75,38 @@ public final class DefaultReaderParserTest
                 }
             };
         parser.setObjectFactory(IParserObjectFactory.STRING_ARRAY_OBJECT_FACTORY);
-        final Reader reader = new StringReader(text);
         try
         {
-            parser.parse(reader, new HeaderLineFilter(2));
+            parser.parse(createLineIterator(), new HeaderLineFilter(2));
         } catch (ParsingException ex)
         {
             assertEquals(
-                    "Creating an object with following tokens '[Christian, Ribeaud, Kapfrain 2/2, Efringen-Kirchen]' failed.",
+                    "Creating an object with following tokens '[Charles, Darwin, Humboldt Ave. 1865, 4242 Somewhere]' failed.",
                     ex.getMessage());
             assertEquals(3, ex.getLineNumber());
         }
     }
+    
+    private Iterator<Line> createLineIterator()
+    {
+        return new Iterator<Line>()
+            {
+                private Iterator<String> iterator = text.iterator();
+                private int lineNumber;
+                public void remove()
+                {
+                    throw new UnsupportedOperationException();
+                }
+                public Line next()
+                {
+                    return new Line(++lineNumber, iterator.next());
+                }
+        
+                public boolean hasNext()
+                {
+                    return iterator.hasNext();
+                }
+            };
+    }
+
 }
\ No newline at end of file
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/parser/ParserUtilitiesTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/parser/ParserUtilitiesTest.java
index 4b4fc1b5878fd6d7004d8891320f1c12aba98c21..dce574df6d6db66f803f2a54035c675adde1a36d 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/parser/ParserUtilitiesTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/parser/ParserUtilitiesTest.java
@@ -30,7 +30,6 @@ import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.common.logging.LogInitializer;
-import ch.systemsx.cisd.common.parser.ParserUtilities.Line;
 
 /**
  * Test cases for corresponding {@link ParserUtilities} class.
@@ -90,8 +89,8 @@ public final class ParserUtilitiesTest
         File file = new File(workingDirectory, "test.txt");
         FileUtils.writeLines(file, Arrays.asList(lines));
         Line line = ParserUtilities.getFirstAcceptedLine(file, null);
-        assertEquals(StringUtils.EMPTY, line.text);
-        assertEquals(0, line.number);
+        assertEquals(StringUtils.EMPTY, line.getText());
+        assertEquals(0, line.getNumber());
         assert file.delete();
     }
 
@@ -103,8 +102,8 @@ public final class ParserUtilitiesTest
         File file = new File(workingDirectory, "test.txt");
         FileUtils.writeLines(file, Arrays.asList(lines));
         Line line = ParserUtilities.getFirstAcceptedLine(file, ExcludeEmptyAndCommentLineFilter.INSTANCE);
-        assertEquals("hello", line.text);
-        assertEquals(3, line.number);
+        assertEquals("hello", line.getText());
+        assertEquals(3, line.getNumber());
         assert file.delete();
     }
 }
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/parser/TabFileLoaderTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/parser/TabFileLoaderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e0e931ee68ecbe776b1c71b548ae5fab73fc9dd
--- /dev/null
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/parser/TabFileLoaderTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.common.parser;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import java.io.StringReader;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class TabFileLoaderTest
+{
+    public static final class ABC
+    {
+        private String a;
+        private String b;
+        private String c;
+        public final String getA()
+        {
+            return a;
+        }
+        public final void setA(String a)
+        {
+            this.a = a;
+        }
+        public final String getB()
+        {
+            return b;
+        }
+        public final void setB(String b)
+        {
+            this.b = b;
+        }
+        public final String getC()
+        {
+            return c;
+        }
+        public final void setC(String c)
+        {
+            this.c = c;
+        }
+        @Override
+        public String toString()
+        {
+            return a + b + c;
+        }
+        
+    }
+    
+    private static final class ABCFactoryFactory implements IParserObjectFactoryFactory<ABC>
+    {
+        public IParserObjectFactory<ABC> createFactory(IAliasPropertyMapper propertyMapper) throws ParserException
+        {
+            return new IParserObjectFactory<ABC>()
+                {
+                    public ABC createObject(String[] lineTokens) throws ParserException
+                    {
+                        ABC abc = new ABC();
+                        abc.setA(lineTokens[0]);
+                        abc.setB(lineTokens[1]);
+                        abc.setC(lineTokens[2]);
+                        return abc;
+                    }
+                };
+        }
+    }
+    
+    @Test
+    public void testEmptyInput()
+    {
+        TabFileLoader<ABC> loader = new TabFileLoader<ABC>(new ABCFactoryFactory());
+        List<ABC> list = loader.load(new StringReader(""));
+        
+        assertEquals(0, list.size());
+    }
+    
+    @Test
+    public void testFirstLineHasHeadersWithoutHashSymbolButNoRows()
+    {
+        TabFileLoader<ABC> loader = new TabFileLoader<ABC>(new ABCFactoryFactory());
+        List<ABC> list = loader.load(new StringReader("A\tB\tC\n"));
+        
+        assertEquals(list.toString(), 0, list.size());
+    }
+
+    @Test
+    public void testFirstLineHasHeadersWithoutHashSymbol()
+    {
+        loadAndCheck("");
+    }
+    
+    @Test
+    public void testFirstLineHasHeadersWithHashSymbol()
+    {
+        loadAndCheck("#");
+    }
+    
+    @Test
+    public void testFirstLineHasMarkerAndSecondLineHasHeadersWithHashSymbol()
+    {
+        loadAndCheck("#\n#");
+    }
+    
+    @Test
+    public void testFirstTwoLinesWithHashAndSomething()
+    {
+        loadAndCheck("#blabla\n" + "#blubub\n");
+    }
+    
+    private void loadAndCheck(String preamble)
+    {
+        TabFileLoader<ABC> loader = new TabFileLoader<ABC>(new ABCFactoryFactory());
+        List<ABC> list = loader.load(new StringReader(preamble + "A\tB\tC\n" + "a1\tb1\tc1\n" + "a2\tb2\tc2\n"));
+        
+        assertEquals(list.toString(), 2, list.size());
+        assertEquals("a1b1c1", list.get(0).toString());
+        assertEquals("a2b2c2", list.get(1).toString());
+    }
+    
+}