Search code examples
javagenericsshapefilegeotoolsrepast-simphony

Generic type invocation using string class names


Hope you can help me with this: I have ...

  • a string list of class names called classNameList
  • a generic class Geography<T>
  • a static generic method <T> void read(Class<T> cl, Geography<T> geo)

I want to loop through the string class name list and call the generic method for each of these classes.

What I tried but obviously did not work:

for (int i = 0; i < classNameList.length; i++) {
   Class<?> myClass = Class.forName(classNameList[i].getName());
   Geography<myClass.newInstance()> geo;
   read(myClass, geo);
}

Error: myClass.newInstance cannot be resolved to a type

My code runs perfectly for a single call of the generic function:

Geography<ExampleClass> ExampleGeo;
read(ExampleClass.class, ExampleGeo);

Any ideas how I could do this?

UPDATE:

Thanks for the helpful input, still it's hard for me to adopt it to my real code. So this is the non simplyfied problem:

I do ready in shapefile-Data with a shapefileLoader, for each feature of the Shapefile a class (GuadAgent) is initialized with a predifined class (PlantWind). I have shapefiles in my input-directory with the names of the Classes their features do represent. I want Java to read in the shapefiles and create the respective agent class. (the agents are also placed in a context and a geography..) Used classes are: ShapefileLoader, Geography, the other classes can be find at the same website

This part is in the main-method:

Geography<GuadAgent> guadGeography = GeographyFactoryFinder.createGeographyFactory(null).createGeography("guadGeography", context, new GeographyParameters<GuadAgent>());
Context<GuadAgent> context = new DefaultContext<GuadAgent>();

FileFilter filter = new FileFilter() {
    @Override
    public boolean accept(File file) {
        return file.getName().endsWith(".shp"); // return .shp files
    }
};
String shapefileDir = System.getProperty("user.dir")+"\\input\\shp\\";
File folder = new File(shapefileDir);
File[] listOfFiles = folder.listFiles(filter);

for (File classFile : listOfFiles) {
        try {
            readForName(classFile,context,guadGeography);
        } catch (ClassNotFoundException | MalformedURLException
                | FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}

The static Method that reads in the names:

static <T> void readForName(File classFile, Context<GuadAgent> context,Geography<GuadAgent> guadGeography) throws ClassNotFoundException, MalformedURLException, FileNotFoundException {

        String shapefileDir = System.getProperty("user.dir")+"\\input\\shp\\";
        String className = classFile.getName().split("\\.(?=[^\\.]+$)")[0];
        File shapefile = null;
        shapefile = new File(shapefileDir+classFile.getName());

        if (!shapefile.exists()) {
            throw new FileNotFoundException("Could not find the given shapefile: " + shapefile.getAbsolutePath());
        }

        switch (className) {
        case "PlantWind":           
            ShapefileLoader<PlantWind> PlantWindLoader = new ShapefileLoader<PlantWind>(PlantWind.class,shapefile.toURI().toURL() , guadGeography, context);
            PlantWindLoader.load();
            PlantWindLoader.close();
            System.out.println(context.getObjects(PlantWind.class).size());                     
            break;
    // Todo Add other Agent types
    default:
        break;
    }

How can I get rid of the switch? Although their number is finit, there are very many different agents...


Solution

  • Unfortunately, there's no syntax close to your intention (nice idea though).

    The basic problem is that Class.forName() returns an unknown Class<?>, so you need a cast somewhere. It's just a mater of where you put it.

    I suggest this approach (which compiles) that bundles up doing a read() based on a class name:

    static <T> void readForName(String className) throws ClassNotFoundException {
        Class<T> myClass = (Class<T>) Class.forName(className);
        Geography<T> geo = new Geography<T>();  // No code shown. Adjust as required
        read(myClass, geo);
    }
    

    May I also suggest using the foreach loop syntax, for tidier code:

    for (String className : classNameList) {
        readForName(className.getName());
    }