4

I'm using google's CSVReader which requires a class name to create a parser. Using the parser, I'm reading a CSV file into a list.

Consider this code:

ValueProcessorProvider provider = new ValueProcessorProvider();
    CSVEntryParser<A> entryParser = new AnnotationEntryParser<A>(A.class, provider);

    CSVReader<A> newExternalFileCSVReader = 
            new CSVReaderBuilder<A>(m_NewExternalFile).entryParser((CSVEntryParser<A>) entryParser).strategy(new CSVStrategy(',', '"', '#', true, true)).build();
    List<A> m_NewExternalFileData = newExternalFileCSVReader.readAll();

With this code, I can read a CSV file that is specific to class A.
I have several other classes: B,C,D, which all uses the same code above, just with their respective class.

Can there be a function where I'll pass the class name as String which can instantiate a CSVReader / parser's based on the String input name? where instead of having to create 3 different code sections (for classes B,C,D), I can use the same one, just input the relevant class name?

1
  • 1
    Are A, B, C and D related or similar in any way? Commented Nov 26, 2015 at 9:43

2 Answers 2

4

You can use a factory pattern.

Create an interface and define inside the base methods for A, B, C and D.

Then all A, B, C and D classes must implements that interface.

public interface BaseInterface {
    // your methods
}

Then create a Factory class in which you pass an identifier and it will return your reader properly initiated

package a;

public final class Factory {

    // Not instantiable
    private Factory() {
        throw new AssertionError("Not instantiable");
    }

    public static CSVReader<your interface> getReader(String reader) {

        if ("A".equals(reader)) {
            return new CSVReader<A>();
        } else if ("B".equals(reader)) {
            return new CSVReader<B>();
        }
        // TODO create all your readers
    }
}

Now, you can call the reader through your factory class like this:

ValueProcessorProvider provider = new ValueProcessorProvider();
    CSVEntryParser<A> entryParser = new AnnotationEntryParser<A>(A.class, provider);

    CSVReader<your interface> newExternalFileCSVReader = 
            Factory("your reader type");
    List<your interface> m_NewExternalFileData = newExternalFileCSVReader.readAll();

As you did not post the A, B, C and D classes you have to customize that code, but following that way I think you can accomplish what you want.

Sign up to request clarification or add additional context in comments.

Comments

4

You could do this:

public class MyCSVReader<T> {

    private Class<T> clazz;

    public MyCSVReader(Class<T> clazz) {
        this.clazz = clazz;
    }

    public List<T> readData(File file) {
        ValueProcessorProvider provider = new ValueProcessorProvider();
        CSVEntryParser<T> parser = new AnnotationEntryParser<T>(clazz, provider);
        CSVStrategy strategy = new CSVStrategy(',', '"', '#', true, true);
        CSVReaderBuilder builder = new CSVReaderBuilder<T>(file);
        CSVReader<T> reader = builder.entryParser(parser ).strategy(strategy).build();
        return reader.readAll();
    }
}

Then you would do:

MyCSVReader<A> readerA = new MyCSVReader<>(A.class);
List<A> data = readerA.readData(m_NewExternalFile);

And the same for any other classes.

EDIT: Maybe it would be useful to lookup the type by file extension?

public class MyCSVReaderFactory {

    private static Map<String, MyCSVReader<?>> readersByFileExtension = new HashMap<>();

    // files with data for class A have extension .xta, etc.
    static {
        readersByFileExtension.put(".xta", new MyCSVReader<>(A.class));
        readersByFileExtension.put(".xtb", new MyCSVReader<>(B.class));
    }

    public MyCSVReader<?> create(String fileExtension) {
        MyCSVReader<?> reader = readersByFileExtension.get(fileExtension);
        if (reader == null) {
            throw new IllegalArgumentException("Unknown extension: " + fileExtension);
        }
        return reader;
     }
}

public List<?> doStuff(File file) {
    String fileExtension = getFileExtension(file);
    MyCSVReader<?> reader = MyCSVReaderFactory.create(fileExtension);
    return reader.readAll();
}

private String getFileExtension(File file) { 
    // TODO: implement this
}

If you don't want a List (Objects) then classes A-D should implement a common interface or extend a common superclass which can be used to generalize.

2 Comments

I think you missed to correct the following piece of code, CSVReaderBuilder builder = new CSVReaderBuilder<A>(file); //it still refers to class A
If this answered your question, please accept the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.