Search code examples
javagenericsreflectiondatacontext

Java: Abstract generic data context class


I would like to store all application data in a data context class.

Having application data classes A and B implementing IApplicationData, the non-abstract, non-generic version could look like this:

NonGenericDataContext

private List<A> aList;
private List<B> bList;

public List<A>getAs() {
    return aList;
}

public List<B>getBs() {
    return bList;
}

Now I would like to abstract from the concrete application classes and use a generic data context to use common functionality in multiple applications. The data context class could then look like this:

AbstractGenericDataContext

protected Map<Class<? extends IApplicationData>, List<? extends IApplicationData>> listsByType;

public List<? extends IApplicationData> getListByType(Class<? extends IApplicationData> clazz) {
    return objectListsByType.get(clazz);
}

I would love to use proper generics, but Java erases the type during compilation, hence the construct with Class. Unfortunately, the construct above makes the code cumbersome and return values of getListByType() need to be casted.

Question How could the code be improved to achieve an abstract, generic (not necessarily in a JLS sense, but with similar usability) data context class?

I would like stick with a pure Java solution (so no code generators if possible). Reflection would be ok if it does not slow down data access in a critical way.


Solution

  • You have to parameterize your generic function (the class doesnt't have to be abstract for that):

    public class GenericContext {
    
        protected Map<Class<? extends IApplicationData>, List<? extends IApplicationData>> listsByType = new HashMap<>();
    
        public <T extends IApplicationData> List<T> getListByType(Class<T> clazz) {
            return (List<T>) listsByType.get(clazz);
        }
    
        public static void main(String[] args) {
            GenericContext context = new GenericContext();
    
            context.listsByType.put(ApplicationData.class, Arrays.asList(new ApplicationData()));
            context.listsByType.put(ApplicationData2.class, Arrays.asList(new ApplicationData2()));
    
            List<ApplicationData> list = context.getListByType(ApplicationData.class);
            System.out.println(list);
        }
    }
    

    Output

    [ApplicationData@5ca881b5]