0

I am really struggling with using wildcards/generics. I'm trying to create a FileManager utility class that can accept custom Java Beans and write read/write the bean to a file. Just to give an example imagine I have an interface called Data that is implemented by RecipeData and DemographicData. I'm using Super CSV to convert a CSV file to a Java Bean. Here is my read method which is based on tutorial code I found from Super CSV.

public interface Data { method declarations }
public class RecipeData implements Data { class stuff goes here }
public class DemographicData implements Data { class stuff goes here }

final public class FileManager {
    public static void parseCsvFile(String filename, CellProcessor[] processors, String[] nameMappings, List<? extends Data> container) { 
        ICsvBeanReader beanReader = null;
        try {
            beanReader = new CsvBeanReader(new FileReader(filename), CsvPreference.STANDARD_PREFERENCE);

            Data data;
            while((data = beanReader.read(Data.class, nameMappings, processors)) != null ) {
                container.add(data);
            }
        } finally {
            if (beanReader != null) {
                beanReader.close();
            }
        }
    }
}

Currently, I'm getting the following error:

The method add(capture#1-of ? extends Data) in the type List is not applicable for the arguments (Data)

I'm not sure what I'm doing is even possible. The idea is, that the container that is passed can be of type RecipeData or DemographicData. So I think one problem is that data should be of those two types.

Can anyone give feedback on how I could potentially fix this or if it'll even work?

EDIT: I'm really not sure this is possible.

Alex Cauthen
  • 497
  • 5
  • 12
  • 32
  • 3
    In your generic you said `extends` - it should instead be `Data` since both `RecipeData` and `DemographicData` implement and NOT extends the `Data` interface. This way, you use "interface as a type" pattern. By the way, you can please show where you call `writeToCsvFile` to see what you are passing to the function? – ishmaelMakitla Jun 13 '16 at 21:06
  • 2
    Also have a look at the PECS principle as explained [here](http://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super). Summary: If you only want to add elements to the collection, use `Collection super Data>`. – Robin Krahl Jun 13 '16 at 21:11
  • Hi, I'm pretty sure you use extends regardless of whether it is a class or interface that is being used. The 'nameMappings' and 'processors' work fine. I've tested it considerably on a non-generic write function so that is not the problem. As far as the 'container' I pass, it is declared in another class as 'List container = new ArrayList();' – Alex Cauthen Jun 13 '16 at 21:11
  • @RobinKrahl that did fix my error. I will test it as soon as I can. – Alex Cauthen Jun 13 '16 at 21:12
  • @AlexCauthen So `container` is a `List`, but the bean reader could return a `DemographicData` that you want to add to the list. Do you see the potential problem? – Robin Krahl Jun 13 '16 at 21:13
  • If I pass a 'List' I would expect it to return that. If I pass a 'List' I would expect it to return that. I'm not sure I understand what you mean. I'm trying to make this as a generic csv parser for any Bean. – Alex Cauthen Jun 13 '16 at 21:18
  • @AlexCauthen Ah, I thought the reader could always return both `RecipeData` and `DemographicData`. Then ignore my second comment. – Robin Krahl Jun 13 '16 at 21:26
  • But I can't get it to work, and I'm not sure that it is even possible in the manner that I am trying to implement it. – Alex Cauthen Jun 13 '16 at 21:28

1 Answers1

0

Instead of using a wildcard for List<? extends Data> container, use List<Data> container.

Zachary Puls
  • 104
  • 1
  • 4