2

The following is a cleaned up example to reduce this to a single question. There are 3 class files (with a few class shells bunched in there). What does not work is the first argument casting on each of getTable() and getCreateTableList() in the SpanTable class. I would like to know how to get that argument to have its original Span/SpanTable subclass type and be passed into the DbTable calls? Or really, DbTable doesn't need the extra info, but I would like SpanTable, or any caller, to retain its types.

DbRow:

public class DbRow {
    static class Span extends DbRow {}
}

DbTable:

import java.util.ArrayList;

abstract public class DbTable<R extends DbRow> {  

    static class PairList<L, R> { 
        public void addEntry(L s, R t) {  }
        public R getRightForLeft(L left) { return null; }
    }
    static class DbPlatform {  }
    static class DbSelectStatement {    }
    public static class Span extends DbRow { }
    static class TableList<R extends DbRow, T extends DbTable<R>> extends ArrayList<T> {}
    static class PlatformTableList<R extends DbRow, T extends DbTable<R>> 
                    extends PairList<DbPlatform, TableList<R, T>> {}
    static DbSelectStatement getDefaultQuery(String tableName) { return null; }

    public DbTable(DbPlatform platform, String tableName) { }
    public DbSelectStatement getStatement() { return null; }

    /** Return the matching DbTable with matching DbSelectStatement or null */
    static protected DbTable<DbRow> getTable(
            PlatformTableList<DbRow, DbTable<DbRow>> platformList, 
            DbPlatform platform, DbSelectStatement stmt) {
        // Get the table from the list, or create new
        TableList<DbRow, DbTable<DbRow>> list = 
                getCreateTableList(
                 (PlatformTableList<DbRow, DbTable<DbRow>>) platformList, platform);
        // Search the list for a match
        for(DbTable<DbRow> table : list) 
            if(table.getStatement().equals(stmt))
                return table;
        return null; 
    }

    /** Get or create and return a TableList for the Platform.  */
    static protected TableList<DbRow, DbTable<DbRow>> getCreateTableList(
            PlatformTableList<DbRow, DbTable<DbRow>> platformList, DbPlatform platform) { 

        TableList<DbRow, DbTable<DbRow>> list = (TableList<DbRow, DbTable<DbRow>>) 
                platformList.getRightForLeft(platform);
        if(list == null) {
            list = new TableList<DbRow, DbTable<DbRow>>();
            platformList.addEntry(platform, list); 
        }
        return list;
    }
}

SpanTable:

class SpanTable<R extends DbTable.Span> extends DbTable<R> { 

    static private PlatformTableList<Span, SpanTable<Span>> platformList = 
            new PlatformTableList<Span, SpanTable<Span>>();

    static public SpanTable<Span> getCreateSpanTable(DbPlatform platform, String tableName) {

        SpanTable<Span> table = (SpanTable<Span>) getTable(platformList, platform, 
                getDefaultQuery(tableName));
        if(table == null) {
            table = new SpanTable<Span>(platform, tableName);
            getCreateTableList(platformList, platform).add(table);
        }
        return table;
    }

    private SpanTable(DbPlatform platform, String tableName) {
        super(platform, tableName);
    }
}
6
  • Since i can not compile that, i can not tell exactly what the problem is. Could you please rewrite the question to a compileable state? I mean, its not a question like "why cant I compile", its a question "why have I to use <?>". Commented Feb 20, 2017 at 20:10
  • 1
    @PeterRader Now organized into 3 class files. Commented Feb 20, 2017 at 21:10
  • 1
    @MarkMeyers You cannot say class TableList<T extends DbTable<R extends DbRow>> extends ArrayList<T<R>> {} because you have to list all the type variables first. The way to do it would be: class TableList<R extends DbRow, T extends DbTable<R>> extends ArrayList<T<R>> Commented Feb 20, 2017 at 21:46
  • @JavierMartín, Okay. This seems to work. class TableList<R extends DbRow, T extends DbTable<R>> extends ArrayList<T> {} Commented Feb 20, 2017 at 21:54
  • But no doubt the typing issues cascade from there. Commented Feb 20, 2017 at 22:00

1 Answer 1

1

You can make the factory methods inside of DbTable class generic so that they hold on the specific table type (T) passed to them via the platform list:

abstract public class DbTable<R extends DbRow> {  

    protected DbTable(DbPlatform platform, String tableName) {  }

    static class TableList<T extends DbTable<?>> extends ArrayList<T> {}

    static class PlatformTableList<T extends DbTable<?>> 
                    extends PairList<DbPlatform, TableList<T>> {}

    /** Return the matching DbTable with matching DbSelectStatement or null.
     * Will create/add a new TableList if platform not found. */

    static protected <T extends DbTable<?>> T getTable(PlatformTableList<T> platformList, 
            DbPlatform platform, DbSelectStatement stmt) {

        // Get the table from the list, or create new
        TableList<T> list = getCreateTableList(platformList, platform);
        // Search the list for a match
        for(T table : list) {
            if(table.equals(stmt))
                return table;
        }
        return null; 
    }

    /** Get or create and return a TableList for the Platform.  */
    static protected <T extends DbTable<?>> TableList<T> getCreateTableList(
            PlatformTableList<T> platformList, DbPlatform platform) { 

        TableList<T> list = platformList.getRightForLeft(platform);
        if(list == null) {
            list = new TableList<T>();
            platformList.addEntry(platform, list);            
        }
        return list;
    }

}

Now you can also remove the cast in your getCreateSpanTable() method:

SpanTable<Span> table = getTable(platformList, platform, 
                getDefaultQuery(tableName));

As pointed out in a comment: If you want to hold the specific row type R in your TableList class, you can write class TableList<R extends DbRow, T extends DbTable<R>> extends ArrayList<T> {} Also, I would try to avoid extending ArrayList and create a field that holds an ArrayList instead.

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

2 Comments

Thank you. That works great. I am curious as to why you would avoid extending ArrayList?
@MarkMeyers Generally, I would favor composition over inheritance when it comes to using collections as discussed here. However, it of course depends. Sometimes, (maybe also in your case) it can make sense to extend ArrayList as shown here.

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.