How to create new instance from class name in gwt

后端 未结 3 1647
离开以前
离开以前 2020-12-08 06:13

I have a class int the following name com.test.TestClass

At one point in my code I have to get instance of this class by only having the class name stri

3条回答
  •  南方客
    南方客 (楼主)
    2020-12-08 06:35

    Here is well tested, commented and slightly refactored version of Ashwin Prabhu's code:

    https://bitbucket.org/espinosa/z025-gwt-maven-alternative-setup/src/d35a3fb7e627b5598fb763f480e3f76932cf4232/src/main/java/my/code/z025/util/ClassFromStringFactoryGenerator.java?at=master

    Example of usage:

    String targetEntryPointClass = "my.code.client.Sample3";
    ClassFromStringFactory classFromStringFactory = GWT.create(ClassFromStringFactory.class);
    Object targetEntryPointInstance = classFromStringFactory.instantiate(targetEntryPointClass);
    if (targetEntryPointInstance == null) {
          // throw some exception
    }
    if (targetEntryPointInstance instanceof EntryPoint) {
          ((EntryPoint) targetEntryPointInstance).onModuleLoad();
    } else {
          // throw some exception
    }
    

    See full source code: https://bitbucket.org/espinosa/z025-gwt-maven-alternative-setup/src/d35a3fb7e627b5598fb763f480e3f76932cf4232/src/main/java/my/code/z025/client/Dispatcher.java?at=master

    In my project, I use GWT's own EntryPoint as marker interface. This enables me to run arbitrary EntryPoint just via URL: http://localhost:8080/my.code.client.Sample3; the Dispatcher EntryPoint instantiates my.code.client.Sample3 via my ClassFromStringFactory. Only Dispatcher Entry Point is configured in GWT module descriptor and the deferred binding, everything else is dynamic.

    For curious, here is what GWT (Code Server in DevMode or Compiler for production mode) generates, content of my ClassFromStringFactoryImpl:

    package my.code.client.reflection;
    
    public class ClassFromStringFactoryImpl implements ClassFromStringFactory {
      public ClassFromStringFactoryImpl( ) {}
    
      public Object instantiate(String className) {
        if (className == null) {
          return null
        }
        else if (className.equals("my.code.client.Sample1")) {
          return new my.code.client.Sample1( );
        }
        else if (className.equals("my.code.client.Sample2")) {
          return new my.code.client.Sample2( );
        }
        ..and so on, 3 same lines per every supported type
        return null;
      }
    }
    

    In temporary file like: C:\Users\espinosa\AppData\Local\Temp\my.code.client.reflection.ClassFromStringFactoryImpl4245548251877324156.java. Note: this file is generated only in case of failure, not on successful compilation

    As you can see, it is no real introspection. Deferred binding does not do any special magic. Similar Java code can be generated by a Velocity template as a part of Maven build or special tools like XText, APT-Jelly. Using GWT's Generator is just a convenience.

    It is important to limit number of "supported" classes, otherwise the generated ClassFromStringFactoryImpl would be too huge, impractically huge or even exceeding limits on Java class. Some sort of filtering is necessary, marking interface is just one option, others are marking annotation (see GWT's JClassType#getAnnotation(Class)) or only selected packages. In any case, ensure that number of supported classes by this "reflection" does not exceeds magnitude of hundreds.

    Many thanks Ashwin Prabhu for pointing me to the right direction.

提交回复
热议问题