0

I have a interface named ReportWriter, which write report to OutputStream, the Report class which contains list of reportRow, the is also an abstract class:

public interface ReportWriter<T extends ReportRow> {
    OutputStream writeReport(Report<T> report) throws ReportWriterException;
}

public abstract class Report<T extends ReportRow> {
   private List<T> rows = Lists.newArrayList();
   ...
}

public abstract class ReportRow {...}

Now i have CsvWriter which implement ReportWriter,

public class CsvWriter<T extends ReportRow> implements ReportWriter {
        @Override
        public ByteArrayOutputStream writeReport(Report report) throws ReportWriterException {
        ...
         for (T row : report.getRows()) {  <-- incompatible type
               ..write here..
         }
}

in the above code, it complains incompatible type:

require Object found T. 

I dont' understand in Report class I've specified the T is a subclass of ReportRow, why I got this complain?

Then I tried to update the CsvWriter's writeReport as below:

public class CsvWriter<T extends ReportRow> implements ReportWriter {
   @Override
   public ByteArrayOutputStream writeReport(Report<T> report) throws ReportWriterException {  <--- complain here
...
}

now it complained:

writeReport(Report<T> report) clashes with writeReport(Report report); both methods have same erasure.

How can i fix this? thanks

user468587
  • 4,799
  • 24
  • 67
  • 124
  • The fundamental problem here is that you're mixing parameterized types and raw types. You should probably read [What is a raw type and why shouldn't we use it?](http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it) – Daniel Pryden May 02 '16 at 16:55

3 Answers3

6

You need to specify the interface you're implementing with the generic type:

public class CsvWriter<T extends ReportRow> implements ReportWriter<T> {

(note the ReportWriter<T>)

Darth Android
  • 3,437
  • 18
  • 19
3

I didn't test this yet, but likely it's because you used a raw type when inheriting. Try this for your second code block:

public class CsvWriter<T extends ReportRow> implements ReportWriter<T> {...

Note the extra <T> on ReportWriter.

markspace
  • 10,621
  • 3
  • 25
  • 39
0

Let's talk about this snippet:

public class CsvWriter<T extends ReportRow> implements ReportWriter {
    @Override
    public ByteArrayOutputStream writeReport(Report report) throws ReportWriterException {
        ...
        for (T row : report.getRows()) {  <-- incompatible type
        ..write here..
    }
}

Without a generic type argument, the ReportWriter you are extending becomes a ReportWriter<ReportRow>. That means report.getRows() will return a List<ReportRow>.

But you're trying to assing it's elements to a variable of the type T. Which is T extends ReportRow. So T might be a subclass of ReportRow.

If it is, you're performing an implicit downcast, so the compiler throws an error.


By extending ReportWriter<T> instead, getReport() will now return a List<T>, and it's elements are safe to assign to variables of type T (obviously).

Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93