Ufilter zum Finden von this-Methoden in Java
Dieser Ufilter gibt alle Methoden aus, die mit dem Zielobjekt »Main.this« aufgerufen werden können.
Der Methodenname wird einmal in geschweiften Klammern ausgegeben, um die Ausgabe sortieren zu können. Danach können diese Klammern gelöscht werden.
Fettgedruckte Programmteile müssen eventuell angepaßt werden.
- (Fragment)
try
{ final java.lang.reflect.Method[] methods = Main.class.getMethods();
final java.lang.StringBuilder builder = new java.lang.StringBuilder();
for( final java.lang.reflect.Method method : methods )
{ builder.setLength( 0 );
builder.append( method.getDeclaringClass() );
builder.append( " {" );
builder.append( method.getName());
builder.append( "} " );
builder.append( method.getReturnType().getName());
builder.append( " " );
builder.append( method.getName());
builder.append( "(" );
final java.lang.Class[] paramTypes = method.getParameterTypes();
boolean first = true;
for( final java.lang.Class c : paramTypes )
builder.append( ( first ?(( first = false )? null : " " ): ", " )+ c.getName() );
builder.append( first ? ")" : " )" );
java.lang.System.out.println( builder.toString() ); }}
catch( final java.lang.Exception exception ) {}
Ein „Ufilter“ ist ein Programm, das eine bestimmte Auswahl von Methoden oder Felder aus einer Bibliothek ausgibt.
- (Notiz, basierend auf Ideen von Ralf Ullrich)
public final class Main implements java.lang.Runnable
{
public static void main( final java.lang.String[] args)
{ Util.withLoggerSetToOffDo( new Main() ); }
/* Dann habe ich die Klasse zum Finden des Archivs, die
Suchbedingungen und die Aktion für gefundenen Methoden aus der
Findeklasse abstrahiert, so daß sie jetzt im
Exemplarerzeugungsausdruck angegeben werden müssen. */
public void run()
{ new Finder
( "java.lang.Object",
new Filter0(),
new PrintConsumer<java.lang.reflect.Method>() ).
run(); }}
/* Ein Filter kann beispielsweise so aussehen: */
class Filter0 implements Filter
{
public boolean passed( final java.util.jar.JarEntry entry )
{ final java.lang.String name = entry.getName();
return
( name.endsWith( ".class" )) &&
! name.startsWith( "sun/" ) &&
! name.startsWith( "sunw/" ) &&
! name.startsWith( "com/sun/" ); }
public boolean passed( final java.lang.Class class_ )
{ return !class_.isAnonymousClass() &&
java.lang.reflect.Modifier.isPublic( class_.getModifiers() ); }
public boolean passed( final java.lang.reflect.Method method )
{ return
java.lang.reflect.Modifier.isPublic( method.getModifiers() ) &&
java.lang.reflect.Modifier.isStatic( method.getModifiers() ) &&
!java.lang.reflect.Modifier.isAbstract( method.getModifiers() )&&
method.getParameterTypes().length == 0 &&
method.getReturnType().isPrimitive() &&
method.getReturnType() != Void.TYPE; }}
/* Gefundene Methoden werden laut Main#run hiermit ausgegeben: */
class PrintConsumer<T>
implements Consumer<T>
{ public boolean consume( final T t )
{ java.lang.System.out.println( t ); return true; }}
/* Nun die eigentliche Finder-Klasse, die den Kern des
Programms darstellt: */
class Finder
{ static java.util.Set<java.lang.String> s;
final java.lang.String classPath;
final Filter filter;
final Consumer<java.lang.reflect.Method> methodConsumer;
public Finder
( final java.lang.String classPath,
final Filter filter,
final Consumer<java.lang.reflect.Method> methodConsumer )
{ s = new java.util.HashSet<java.lang.String>();
this.classPath = classPath.replace( '.', '/' ) + ".class";
this.filter = filter;
this.methodConsumer = methodConsumer; }
public void run(){ this.inspectJar(); }
public void inspectJar()
{ final java.net.URL url = java.lang.ClassLoader.getSystemResource
( this.classPath );
final java.net.JarURLConnection connection = Util.openConnection( url );
final java.util.jar.JarFile jarFile = Util.getJarFile( connection );
Util.iterate
( java.util.Collections.list( jarFile.entries() ), inspectEntry ); }
Consumer<java.util.jar.JarEntry> inspectEntry =
new Consumer<java.util.jar.JarEntry>()
{ public boolean consume( final java.util.jar.JarEntry entry )
{ final java.lang.String name = entry.getName();
if( Finder.this.filter.passed( entry ))
{ try
{ final String clzName = name.substring
( 0, name.length() - 6 ).replace( '/', '.' );
final Class class_ = Class.forName( clzName );
if( Finder.this.filter.passed( class_ ))
Util.iterate( class_.getDeclaredMethods(), inspectMethod ); }
catch( final java.lang.ClassNotFoundException classNotFoundException )
{ throw new java.lang.RuntimeException( classNotFoundException ); }}
return true; }};
Consumer<java.lang.reflect.Method> inspectMethod =
new Consumer<java.lang.reflect.Method>()
{ public boolean consume( final java.lang.reflect.Method method )
{ if( Finder.this.filter.passed( method ))
Finder.this.methodConsumer.consume( method );
return true; }}; }
/* Es fehlt noch die Schnittstelle für den Filter */
interface Filter
{ boolean passed( java.util.jar.JarEntry entry );
boolean passed( final java.lang.Class class_ );
boolean passed( java.lang.reflect.Method method ); }
/* Hier ist eine andere gelegentlich benutzte Schnittstelle: */
interface Consumer<T>{ boolean consume( T t ); }
/* Und die böse Klasse ohne jede Kohäsion: Util */
class Util
{ /* Die Verwendung von solchen Operationen wie »iterate«
ist hier fragwürdig. Was soll daran besser sein als »for«
direkt zu verwenden? Aber sie öffnet vielleicht den Weg
zu darauf aufbauenden Abstraktionen in späteren Versionen. */
public static <T> boolean iterate
( final T[] iterable, final Consumer<T> consumer )
{ for( final T t : iterable )
if( !consumer.consume( t )){ return false; }
return true; }
public static <T> boolean iterate
( final java.lang.Iterable<T> iterable, final Consumer<T> consumer )
{ for( final T t : iterable )
if( !consumer.consume( t )){ return false; }
return true; }
public static void withLoggerSetToOffDo( final java.lang.Runnable runnable )
{ final java.util.logging.Logger logger =
java.util.logging.Logger.getLogger( "" );
java.util.logging.Level old = logger.getLevel();
/* OK, das muß man auch nicht mit »for« formulieren. */
boolean looping = true; for
( logger.setLevel( java.util.logging.Level.OFF ); looping;
logger.setLevel( old ))
{ runnable.run(); looping = false; }}
/* Die beiden nächsten Methoden sollen nur Ausnahmen kapseln,
die sonst nicht durch bestimmte Schnittstellen gereicht werden
können. */
public static java.net.JarURLConnection openConnection
( final java.net.URL url )
{ try
{ return( java.net.JarURLConnection )url.openConnection(); }
catch( final java.io.IOException iOException )
{ throw new java.lang.RuntimeException( iOException ); }}
public static java.util.jar.JarFile getJarFile
( final java.net.JarURLConnection connection )
{ try
{ return connection.getJarFile(); }
catch( final java.io.IOException iOException )
{ throw new java.lang.RuntimeException( iOException ); }}}