tags:

views:

91

answers:

1

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 string. I have tried using GWT.create() But it is working only in dev mode. Can any one tell me how to get instance in gwt from class name.

+2  A: 

Since reflection is not possible on the client side, the only solution you have to mimic reflection is using deferred binding.

Use deferred binding to discover all classes you wish to instantiate with the class name during compile time. You may use a marker interface on all such classes to aid TypeOracle to identify these. You dynamically generate a factory class, which takes in the simple name of the class and returns a newly instantiated object of that class. The approach is very straight forward and you will find a good explanation of deferred binding in google's tutorials to boot.

Edit:- Some skeletal code to get you started. (Stripped down version of my production code, check for compiler errors in the generated file! and debug the flow)

First> Add the following blurb into your *.gwt.xml, to so that the compiler invokes our com.package.ReflectionGenerator, which will generate a simple factory class to mimic reflection on the client side.

  <generate-with class="com.package.ReflectionGenerator">
      <when-type-assignable class="com.package.client.Reflection" />
  </generate-with>

Next> Define an interface for our factory class

public interface Reflection {
    public <T> T instantiate( Class<T> clazz );
}

Last> Implement ReflectionGenerator

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.PropertyOracle;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;

public class ReflectionGenerator extends Generator
{    
    @Override
    public String generate( TreeLogger logger, GeneratorContext context, String typeName ) throws UnableToCompleteException
    {
        TypeOracle oracle = context.getTypeOracle( );

        JClassType someMarkerInterfaceType = oracle.findType( MarkerInterface.class.getName( ) );

        List<JClassType> clazzes = new ArrayList<JClassType>( );

        PropertyOracle propertyOracle = context.getPropertyOracle( );

        for ( JClassType classType : oracle.getTypes( ) )
        {
            if ( !classType.equals( someMarkerInterfaceType ) && classType.isAssignableTo( someMarkerInterfaceType ) )
                clazzes.add( classType );
        }

        final String genPackageName = "com.package.client";
        final String genClassName = "ReflectionImpl";

        ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory( genPackageName, genClassName );
        composer.addImplementedInterface( Reflection.class.getCanonicalName( ) );

        composer.addImport( "com.package.client.*" );

        PrintWriter printWriter = context.tryCreate( logger, genPackageName, genClassName );

        if ( printWriter != null )
        {
            SourceWriter sourceWriter = composer.createSourceWriter( context, printWriter );
            sourceWriter.println( "ReflectionImpl( ) {" );
            sourceWriter.println( "}" );

            printFactoryMethod( clazzes, sourceWriter );

            sourceWriter.commit( logger );
        }
        return composer.getCreatedClassName( );
    }

    private void printFactoryMethod( List<JClassType> clazzes, SourceWriter sourceWriter )
    {
        sourceWriter.println( );

        sourceWriter.println( "public <T> T instantiate( Class<T> clazz ) {" );

        for ( JClassType classType : clazzes )
        {
            if ( classType.isAbstract( ) )
                continue;

            sourceWriter.println( );
            sourceWriter.indent( );
            sourceWriter.println( "if( clazz.getSimpleName().equals(\"" + classType.getName( ) + "\")) {" );
            sourceWriter.indent( );
            sourceWriter.println( "return new " + classType.getQualifiedSourceName( ) + "( );" );
            sourceWriter.outdent( );
            sourceWriter.println( "}" );
            sourceWriter.outdent( );
            sourceWriter.println( );
        }
        sourceWriter.println( );
        sourceWriter.outdent( );
        sourceWriter.println( "}" );
        sourceWriter.outdent( );
        sourceWriter.println( );
    }
}

This should generate the factory class ReflectionGenerator in your workspace, check the generated file and tweak the source writer code to generate the code you desire.

Usage GWT.create( Reflection.class ).instantiate( YourClass.class );

I have used a marker interface 'MarkerInterface' in the generator to restrict the number of classes supported by the factory, hence as a result all the participating classes must implement 'MarkerInterface'

Ashwin Prabhu
Thanks a lot.If you can post the sample code it will be very useful for me as well as other users.
BlackPanther
I have edited my response to post a skeletal code demonstrating use of binding. Please go through, and pardon me if you happen to chance upon a compilation error or two, I haven't run the code through the compiler. Am too lazy for that :P
Ashwin Prabhu