Emulating Java Reflection with deferred binding

289 views
Skip to first unread message

fabio.bozzo

unread,
Aug 9, 2011, 4:32:29 AM8/9/11
to Google Web Toolkit
Here's some of my code:

My module contains:
<generate-with class="com.bilancio.ReflectionGenerator">
<when-type-assignable class="com.bilancio.client.Reflection" />
</generate-with>



public interface Constructable {}



public interface Reflection {
public <T> T instantiate( String className );
}

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

JClassType markerInterface =
oracle.findType( Constructable.class.getName( ) );

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

PropertyOracle propertyOracle = context.getPropertyOracle( );

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

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

ClassSourceFileComposerFactory composer = new
ClassSourceFileComposerFactory( genPackageName, genClassName );

composer.addImplementedInterface( Reflection.class.getCanonicalName( ) );

composer.addImport( "com.bilancio.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( String
className ) {" );

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

sourceWriter.println( );
sourceWriter.indent( );
sourceWriter.println( "if( className.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( );
}
}


I want to use it like that:
GWT.create(Reflection.class)).instantiate("MyPanel")

MyPanel class obviously implement 'Constructable' interface.
I keep getting:
Type mismatch: cannot convert from MyPanel to T

What do you think?

Jens

unread,
Aug 9, 2011, 5:16:50 AM8/9/11
to google-we...@googlegroups.com
I think in your generated method you have to do an unchecked cast into T and its also nice if you let T extend Constructable to get at least some error when you try to assign the returned object to a type that does not implement Constructable, e.g.:

public <T extends Constructable> T instantiate (String className) {
  .....
  .....
  if("MyPanel".equals(className)) {
     return (T) new MyPanel();
  }
  ....
}



-- J.

fabio.bozzo

unread,
Aug 9, 2011, 5:58:16 AM8/9/11
to Google Web Toolkit
Nice idea, thank you but.... the error is still here:

[DEBUG] [main] - Rebinding com.bilancio.client.Reflection
[DEBUG] [main] - Adding '1' new generated units
[DEBUG] [main] - Validating newly compiled units
[ERROR] [main] - Errors in 'generated://
670356D9DA0D417BB8171499B4C4D57B/com/bilancio/client/
ReflectionImpl.java'
[ERROR] [main] - Line 9: This method must return a result of type
T
[INFO] [main] - See snapshot: /tmp/
com.bilancio.client.ReflectionImpl6488844579312624283.java

I added sourceWriter.println( "return (T) new " +
classType.getQualifiedSourceName( ) + "();" );

and modified the interface and implementation as you said.... :-(((

fabio.bozzo

unread,
Aug 9, 2011, 6:06:19 AM8/9/11
to Google Web Toolkit
it has changed from:

Type mismatch: cannot convert from MyPanel to T

to:

This method must return a result of type T

but... I AM returning T via cast... what??

Jens

unread,
Aug 9, 2011, 6:26:44 AM8/9/11
to google-we...@googlegroups.com
Ah its also missing a default return value in your generated method:

public <T extends Constructable> T instantiate (String className) {
  if("MyPanel".equals(className)) {
     return (T) new MyPanel();
  }
  .....
  if("MyPanel2".equals(className)) {
     return (T) new MyPanel2();
  }
  ....

  return null; // no matches
}


You can also always add the "-gen <path/to/output/folder>" option to your compiler args / run configuration. That way GWT will save all generated sources in your specified folder and you can actually see what has been generated.


-- J.

fabio.bozzo

unread,
Aug 9, 2011, 6:36:35 AM8/9/11
to Google Web Toolkit
Jens... you probably saved my life!!! ^__^ Huge thank you!
Reply all
Reply to author
Forward
0 new messages