{******************************************************************}
{ }
{ javadpr - Generates a Delphi project file from a Java class }
{ file. }
{ }
{ javadpr produces an Object Pascal file from a Java class. This }
{ file forms the basis that allow Java and Delphi-produced code }
{ to interact via the Java Native Interface. }
{ }
{ This tool is similar to the javah tool from Sun Microsystems, }
{ Inc., which produces C header files from Java class files. }
{ }
{ Copyright (C) 2001 MMG and Associates }
{ www.pacifier.com/~mmead/jni/delphi }
{ }
{ The contents of this file are used with permission, subject to }
{ the Mozilla Public License Version 1.1 (the "License"); you may }
{ not use this file except in compliance with the License. You may }
{ obtain a copy of the License at }
{ http://www.mozilla.org/NPL/NPL-1_1Final.html }
{ }
{ Software distributed under the License is distributed on an }
{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or }
{ implied. See the License for the specific language governing }
{ rights and limitations under the License. }
{ }
{ History: }
{ 29 Apr 2001 - Created. }
{ }
{******************************************************************}
program javadpr;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes, Contnrs, Windows,
JNI;
const
VERSION_STRING = '1.0.0';
type
TNativeMethods = class(TObjectList)
public
JavaClass: string;
constructor Create(const JavaClassName: string);
procedure EmitCode(const JavaClass: string; const Stream: TextFile);
end;
TNativeMethod = class(TObject)
public
Name: string;
DelphiReturnType: string;
JavaReturnType: string;
PackageName: string;
JavaSignatureTypes: TStringList;
DelphiParamTypes: TStringList;
constructor Create;
destructor Destroy; override;
procedure EmitCode(const JavaClass: string; const Stream: TextFile);
function JNISignature: string;
function JavaSignature: string;
end;
var
JNIEnv: TJNIEnv;
NativeClassCls: JClass;
NativeClassObj: JObject;
NativeMethods: TNativeMethods;
JavaClassFile: string;
OutputFilename: string;
OutputFile: Text;
ClassPath: string;
IncludeNonNativeMethods: Boolean;
VerboseOutput: Boolean;
Platform: string;
//=====================================================================================
// Support functions
function GetEnvironmentString(const Source : string) : string;
const
BUFSIZE = 2000;
var
buffer, variable : PChar;
value : string;
begin
buffer := StrAlloc(BUFSIZE);
variable := StrAlloc(Length(Source) + 1);
StrPCopy(variable, Source);
GetEnvironmentVariable(variable, buffer, BUFSIZE);
value := StrPas(buffer);
StrDispose(buffer);
StrDispose(variable);
Result := value;
end;
function DotsToUnderscores(const Text: string): string;
begin
Result := StringReplace(Text, '.', '_', [rfReplaceAll]);
end;
function SlashesToDots(const Text: string): string;
begin
Result := StringReplace(Text, '/', '.', [rfReplaceAll]);
end;
procedure DisplayVersion;
begin
Writeln('javadpr version "', VERSION_STRING, '"');
end;
procedure DisplayError(const Text: string);
begin
Writeln(Text, ' Try -help.');
end;
procedure DisplayHelp;
begin
Writeln('Usage: javadpr [options] class');
Writeln;
Writeln('where [options] include:');
Writeln;
Writeln(' -help Print this help message');
Writeln(' -classpath <path> Path from which to load classes');
Writeln(' -o <file> Output file (default is stdout)');
Writeln(' -version Print version information then quit');
Writeln(' -verbose Enable verbose output');
Writeln(' -all Include non-native methods (internal debugging)');
Writeln(' -platform <platform> For code generation (Linux|Win32|All)');
Writeln;
Writeln('<classes> are specified with their fully qualified names (for instance, java.awt.Rectangle).');
Writeln;
end;
{***************************** ParseCommandLine ***********************************
s Parse the command line to get the user's options. Quick and dirty, needs work.
***************************** ParseCommandLine ***********************************}
function ParseCommandLine: Boolean;
var
I: Integer;
LastCommand: string;
begin
Result := False;
if ParamCount = 0 then begin
DisplayHelp;
Exit;
end;
// The class file must be the last parameter
LastCommand := ParamStr(ParamCount);
if LastCommand[1] <> '-' then
JavaClassFile := LastCommand;
for I := 1 to ParamCount do begin
if CompareText(ParamStr(I), '-classpath') = 0 then begin
if ParamCount >= I + 1 then
ClassPath := ParamStr(I + 1)
else begin
DisplayError('No classpath specified.');
Exit;
end;
end
else if CompareText(ParamStr(I), '-all') = 0 then begin
IncludeNonNativeMethods := True;
end
else if CompareText(ParamStr(I), '-help') = 0 then begin
DisplayHelp;
Exit;
end
else if CompareText(ParamStr(I), '-version') = 0 then begin
DisplayVersion;
Exit;
end
else if CompareText(ParamStr(I), '-verbose') = 0 then begin
VerboseOutput := True;
end
else if CompareText(ParamStr(I), '-o') = 0 then begin
if ParamCount >= I + 1 then
OutputFilename := ParamStr(I + 1)
else begin
DisplayError('No output file specified.');
Exit;
end;
end
else if CompareText(ParamStr(I), '-platform') = 0 then begin
if ParamCount >= I + 1 then
Platform := UpperCase(ParamStr(I + 1))
else begin
DisplayError('No platform specified.');
Exit;
end;
if (Platform <> 'LINUX') and (Platform <> 'WIN32') and (Platform <> 'ALL') then begin
DisplayError('Unknown platform specified.');
Exit;
end;
end
// Unknown switch
else if ParamStr(I)[1] = '-' then begin
DisplayHelp;
Exit;
end;
end;
Result := True;
end;
{***************************** JNITypeToOPType ***********************************
Maps a JNI type to Object Pascal type.
e.g.:
int -> JInt
[B -> JByteArray
java.lang.Object -> JObject
***************************** JNITypeToOPType ***********************************}
function JNITypeToOPType(const StrType: string): string;
var
Position: Integer;
JType: string;
begin
// Some types have "class" prepended
Position := Pos(' ', StrType);
JType := Copy(StrType, Position + 1, Length(StrType));
if (JType = 'void') then
Result := 'void' // just a placeholder
else if (JType = 'int') then
Result := 'JInt'
else if (JType = 'double') then
Result := 'JDouble'
else if (JType = 'float') then
Result := 'JFloat'
else if (JType = 'char') then
Result := 'JChar'
else if (JType = 'short') then
Result := 'JShort'
else if (JType = 'boolean') then
Result := 'JBoolean'
else if (JType = 'byte') then
Result := 'JByte'
else if (JType = 'long') then
Result := 'JLong'
else if (JType = 'java.lang.String') then
Result := 'JString'
else if (JType = '[Z') then
Result := 'JBooleanArray'
else if (JType = '[B') then
Result := 'JByteArray'
else if (JType = '[C') then
Result := 'JCharArray'
else if (JType = '[S') then
Result := 'JShortArray'
else if (JType = '[I') then
Result := 'JIntArray'
else if (JType = '[J') then
Result := 'JLongArray'
else if (JType = '[F') then
Result := 'JFloatArray'
else if (JType = '[D') then
Result := 'JDoubleArray'
else if Copy(JType, 1, 2) = '[L' then
Result := 'JObjectArray'
else if Copy(JType, 1, 2) = '[[' then
Result := 'JObjectArray'
else if (JType = 'java.lang.Class') then
Result := 'JClass'
// the next two can be handled in the else if you like
else if (JType = 'java.lang.Object') then
Result := 'JObject'
else if Copy(JType, 1, 1) = 'L' then
Result := 'JObject'
else
Result := 'JObject'; // the rest must be derived from JObject
end;
{***************************** JNITypeToJavaType ***********************************
Maps a JNI type into a Java type. Still in development.
e.g.:
V -> void
I -> int
[B -> byte[]
***************************** JNITypeToJavaType ***********************************}
function JNITypeToJavaType(const StrType: string): string;
var
I, Position: Integer;
JType: string;
function LetterToType(const Letter: string): string;
begin
if (Letter = 'V') then
Result := 'void'
else if (Letter = 'I') then
Result := 'int'
else if (Letter = 'D') then
Result := 'double'
else if (Letter = 'F') then
Result := 'float'
else if (Letter = 'C') then
Result := 'char'
else if (Letter = 'S') then
Result := 'short'
else if (Letter = 'Z') then
Result := 'boolean'
else if (Letter = 'B') then
Result := 'byte'
else if (Letter = 'J') then
Result := 'long'
else
Result := '';
end;
begin
// Some types have "class" prepended
Position := Pos(' ', StrType);
JType := Copy(StrType, Position + 1, Length(StrType));
Result := LetterToType(JType[1]);
if Result <> '' then
Exit
else if (JType[1] = 'L') then
Result := SlashesToDots(Copy(JType, 2, Length(JType) - 2))
else if (JType[1] = '[') then begin
Position := LastDelimiter('[', JType);
Result := LetterToType(JType[Position + 1]);
if Result = '' then
Result := Copy(JType, Position + 2, Length(JType) - Position - 2);
for I := 1 to Position do
Result := Result + '[]';
Result := SlashesToDots(Result);
end
else
Result := '****UNKNOWN****';
end;
{***************************** JavaTypeToSigType ***********************************
Maps a Java type into a signature.
e.g.:
int -> I
[B -> [B
Ljava.lang.String -> Ljava/lang/String;
***************************** JavaTypeToSigType ***********************************}
function JavaTypeToSigType(const StrType: string): string;
var
Position: Integer;
JType: string;
begin
// Some types have "class" prepended
Position := Pos(' ', StrType);
JType := Copy(StrType, Position + 1, Length(StrType));
if (JType = 'void') then
Result := 'V'
else if (JType = 'int') then
Result := 'I'
else if (JType = 'double') then
Result := 'D'
else if (JType = 'float') then
Result := 'F'
else if (JType = 'char') then
Result := 'C'
else if (JType = 'short') then
Result := 'S'
else if (JType = 'boolean') then
Result := 'Z'
else if (JType = 'byte') then
Result := 'B'
else if (JType = 'long') then
Result := 'J'
else begin
Result := JType; //type;
Result := StringReplace(Result, '.', '/', [rfReplaceAll]);
// If it's not an array
if (Result[1] <> '[') then
Result := 'L' + Result + ';';
end;
end;
{***************************** GetNativeMethods ***********************************
This does all of the work. The equivalent Java code is significantly shorter.
This is due to the overhead involved in locating classes and methods and invoking
methods.
***************************** GetNativeMethods ***********************************}
function GetNativeMethods(const JavaClassName: string): TNativeMethods;
var
NativeMethod: TNativeMethod;
MID: JMethodID;
ClassLoaderCls: JClass;
ClassLoaderInst: JObject;
JNIMethods, JNIParams: JArray;
JNIMethod, JNIParam: JObject;
I, J, Length, Count: Integer;
theClass, Cls: JClass;
ClassObj: JObject;
JStr: JString;
Str, JType: string;
ModifierCls: JClass;
IsNativeMethod: JMethodID;
IsNative: JBoolean;
Modifiers: Integer;
begin
// Get the isNative method in the java.lang.reflect.Modifier class so we can
// test all the methods to find out if they are native
ModifierCls := JNIEnv.FindClass('java/lang/reflect/Modifier');
IsNativeMethod := JNIEnv.GetStaticMethodID(ModifierCls, 'isNative', '(I)Z');
//***********************************************************************************************
// Find and load the ClassLoader
// We need to use the system loader to load the class we want to process
ClassLoaderCls := JNIEnv.FindClass('java/lang/ClassLoader');
if ClassLoaderCls = nil then
raise Exception.Create('FindClass failed: java/lang/ClassLoader');
// Get the method to load the system class loader
MID := JNIEnv.GetStaticMethodID(ClassLoaderCls, 'getSystemClassLoader', '()Ljava/lang/ClassLoader;');
if MID = nil then
raise Exception.Create('GetStaticMethodID failed: getSystemClassLoader');
// Get the loader instance
ClassLoaderInst := JNIEnv.CallStaticObjectMethod(ClassLoaderCls, Mid, []);
if ClassLoaderInst = nil then
raise Exception.Create('CallStaticObjectMethod failed: getSystemClassLoader');
//***********************************************************************************************
// Get method used to load the class
MID := JNIEnv.GetMethodID(ClassLoaderCls, 'loadClass', '(Ljava/lang/String;)Ljava/lang/Class;');
if MID = nil then
raise Exception.CreateFmt('GetMethodID failed: loadClass', []);
// Load the class
NativeClassObj := JNIEnv.CallObjectMethod(ClassLoaderInst, Mid, [JavaClassName]);
if NativeClassObj = nil then
raise Exception.CreateFmt('CallObjectMethod failed: loadClass(%s)', [JavaClassName]);
// Get the class object's class
NativeClassCls := JNIEnv.GetObjectClass(NativeClassObj);
if NativeClassCls = nil then
raise Exception.CreateFmt('GetObjectClass failed for %s', [JavaClassName]);
//***********************************************************************************************
// Get method to retrieve declared methods
MID := JNIEnv.GetMethodID(NativeClassCls, 'getDeclaredMethods', '()[Ljava/lang/reflect/Method;');
if Mid = nil then
raise Exception.CreateFmt('GetMethodID failed: %s.getDeclaredMethods', [JavaClassName]);
// Get all methods
JNIMethods := JNIEnv.CallObjectMethod(NativeClassObj, Mid, []);
if JNIMethods = nil then
raise Exception.CreateFmt('CallObjectMethod failed: %s.getDeclaredMethods', [JavaClassName]);
// This will hold the parsed methods (name, parameters, return type, etc.)
Result := TNativeMethods.Create(JavaClassName);
// Process each method in the class
Length := JNIEnv.GetArrayLength(JNIMethods);
for I := 0 to Length - 1 do begin
// Next method
JNIMethod := JNIEnv.GetObjectArrayElement(JNIMethods, I);
if JNIMethod = nil then
raise Exception.Create('GetObjectArrayElement failed for JNIMethods');
theClass := JNIEnv.GetObjectClass(JNIMethod);
if theClass = nil then
raise Exception.Create('GetObjectClass failed for array element JNIMethod');
// If -all switch was not used, only get native methods
if not IncludeNonNativeMethods then begin
//***********************************************************************************************
// Only process methods with the 'native' modifier
Mid := JNIEnv.GetMethodID(theClass, 'getModifiers', '()I');
if Mid = nil then
raise Exception.Create('GetMethodID failed: getModifiers');
Modifiers := JNIEnv.CallIntMethod(JNIMethod, Mid, []);
IsNative := JNIEnv.CallStaticBooleanMethod(ModifierCls, IsNativeMethod, [Modifiers]);
if not IsNative then
Continue;
end;
// We have a native method, so create our object to hold it
NativeMethod := TNativeMethod.Create;
//***********************************************************************************************
// Get the method's name
Mid := JNIEnv.GetMethodID(theClass, 'getName', '()Ljava/lang/String;');
if Mid = nil then
raise Exception.Create('GetMethodID failed: getName on JNIMethod');
JStr := JNIEnv.CallObjectMethod(JNIMethod, Mid, []);
NativeMethod.Name := JNIEnv.JStringToString(JStr);
//***********************************************************************************************
// Get the method's return type (as a string)
Mid := JNIEnv.GetMethodID(theClass, 'getReturnType', '()Ljava/lang/Class;');
if Mid = nil then
raise Exception.Create('GetMethodID failed: getReturnType');
ClassObj := JNIEnv.CallObjectMethod(JNIMethod, Mid, []);
if Mid = nil then
raise Exception.Create('CallObjectMethod failed for JNIMethod');
Cls := JNIEnv.GetObjectClass(ClassObj);
if Cls = nil then
raise Exception.Create('GetObjectClass failed on JNIMethod');
Mid := JNIEnv.GetMethodID(Cls, 'toString', '()Ljava/lang/String;');
if Mid = nil then
raise Exception.Create('GetMethodID failed: toString');
JStr := JNIEnv.CallObjectMethod(ClassObj, Mid, []);
Str := JNIEnv.JStringToString(JStr);
// e.g. int -> I
NativeMethod.JavaReturnType := JavaTypeToSigType(Str);
// e.g. int -> JInt
NativeMethod.DelphiReturnType := JNITypeToOPType(Str);
//***********************************************************************************************
// Get method to retrieve parameter types
Mid := JNIEnv.GetMethodID(theClass, 'getParameterTypes', '()[Ljava/lang/Class;');
if Mid = nil then
raise Exception.Create('GetMethodID failed: getParameterTypes');
// Get all parameters (types only, no names)
JNIParams := JNIEnv.CallObjectMethod(JNIMethod, Mid, []);
if JNIParams = nil then
raise Exception.Create('CallObjectMethod failed: getParameterTypes');
// Process each parameter
Count := JNIEnv.GetArrayLength(JNIParams);
for J := 0 to Count - 1 do begin
// Next parameter
JNIParam := JNIEnv.GetObjectArrayElement(JNIParams, J);
if JNIParam = nil then
raise Exception.Create('GetObjectArrayElement failed for JNIParams');
Cls := JNIEnv.GetObjectClass(JNIParam);
if Cls = nil then
raise Exception.Create('GetObjectClass failed on JNIParam');
// The name is actually the type (e.g. int or java.lang.String)
Mid := JNIEnv.GetMethodID(Cls, 'getName', '()Ljava/lang/String;');
if Mid = nil then
raise Exception.Create('GetMethodID failed: getName on JNIParam');
// Get the type (as string)
JStr := JNIEnv.CallObjectMethod(JNIParam, Mid, []);
JType := JNIEnv.JStringToString(JStr);
// Save Java type (e.g. int -> I)
Str := JavaTypeToSigType(JType);
NativeMethod.JavaSignatureTypes.Add(Str);
// Save Delphi type (e.g. int -> JInt)
Str := JNITypeToOPType(JType);
NativeMethod.DelphiParamTypes.Add(Str);
end;
// Add this method to list
Result.Add(NativeMethod);
end;
end;
// End support functions
//=====================================================================================
//=====================================================================================
{ TNativeMethod }
constructor TNativeMethod.Create;
begin
JavaSignatureTypes := TStringList.Create;
DelphiParamTypes := TStringList.Create;
end;
destructor TNativeMethod.Destroy;
begin
JavaSignatureTypes.Free;
DelphiParamTypes.Free;
end;
{******************* TNativeMethod.EmitCode *************************
Generates the code for this method and sends the output to
Stream.
******************* TNativeMethod.EmitCode *************************}
procedure TNativeMethod.EmitCode(const JavaClass: string; const Stream: TextFile);
var
Param: string;
I, Count: Integer;
CallingConvention: string;
begin
// Generate header comment
Writeln(Stream, '(*');
Writeln(Stream, ' * Class: ', DotsToUnderscores(JavaClass));
Writeln(Stream, ' * Method: ', Name);
Writeln(Stream, ' * Signature: ', JNISignature);
Writeln(Stream, ' *)');
// Procedure/function
if DelphiReturnType = 'void' then
Write(Stream, 'procedure ')
else
Write(Stream, 'function ');
// Method name and required parameters
Write(Stream, Format('Java_%s_%s', [DotsToUnderscores(JavaClass), Name]));
// Parameters (first two are required and always the same)
Write(Stream, '(PEnv: PJNIEnv; Obj: JObject');
Count := DelphiParamTypes.Count;
for I := 0 to Count - 1 do begin
Param := Format('; Arg%d: %s', [I + 1, DelphiParamTypes[I]]);
Write(Stream, Param);
end;
Write(Stream, ')');
// Calling convention
if Platform = 'LINUX' then
CallingConvention := '; cdecl;'
else if Platform = 'WIN32' then
CallingConvention := '; stdcall;'
else
CallingConvention := '; {$IFDEF WIN32} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}';
// Return type
if DelphiReturnType = 'void' then
Writeln(Stream, CallingConvention)
else
Writeln(Stream, ': ', DelphiReturnType, CallingConvention);
// Empty method (to be implemented by programmer)
Writeln(Stream, 'begin');
Writeln(Stream, 'end;');
Writeln(Stream);
end;
{******************* TNativeMethod.JavaSignature *************************
Constructs a Java method signature from the JNI signatures of each
method parameter.
e.g.:
(J)[I
long SomeFunction(int[])
([Ljava/lang/String;)Ljava/lang/String;
java.lang.String Function(java.lang.String[])
******************* TNativeMethod.JavaSignature *************************}
function TNativeMethod.JavaSignature: string;
var
I, Count: Integer;
JType: string;
begin
Result := JNITypeToJavaType(JavaReturnType) + ' ' + Name + '(';
Count := JavaSignatureTypes.Count;
for I := 0 to Count - 1 do begin
if I > 0 then
Result := Result + ', ';
JType := JNITypeToJavaType(JavaSignatureTypes[I]);
Result := Result + Format('%s', [JType]);
end;
Result := Result + ')';
end;
{******************* TNativeMethod.JNISignature *************************
Constructs the complete JNI method signature from the JNI signature
of each parameter.
e.g.:
(IIJ)[Ljava/lang/String;
The signature above describes a method takes 3 parameters,
2 integers and a long, and returns an array of Java Strings.
******************* TNativeMethod.JNISignature *************************}
function TNativeMethod.JNISignature: string;
var
I, Count: Integer;
begin
Result := '(';
Count := JavaSignatureTypes.Count;
for I := 0 to Count - 1 do begin
Result := Result + Format('%s', [JavaSignatureTypes[I]]);
end;
Result := Result + ')';
if JavaReturnType = 'void' then
Result := Result + 'V'
else
Result := Result + JavaReturnType;
end;
// End TNativeMethod
//=====================================================================================
//=====================================================================================
{ TNativeMethods }
constructor TNativeMethods.Create(const JavaClassName: string);
begin
JavaClass := JavaClassName;
end;
{******************* TNativeMethods.EmitCode *************************
Generates the code for the Delphi project. Calls the EmitCode
method of each NativeMethod object to generate the code for each
individual method.
******************* TNativeMethods.EmitCode *************************}
procedure TNativeMethods.EmitCode(const JavaClass: string; const Stream: TextFile);
var
I: Integer;
NativeMethod: TNativeMethod;
begin
// Generate module name and uses clause. e.g.:
//
// library JNITest;
//
// uses JNI;
//
Writeln(Stream, 'library ', DotsToUnderscores(JavaClass), ';');
Writeln(Stream);
Writeln(Stream, 'uses JNI;');
Writeln(Stream);
// Call each NativeMethod object to output the function info
for I := 0 to Count - 1 do
TNativeMethod(Items[I]).EmitCode(JavaClass, Stream);
// Generate exports section
Writeln(Stream, 'exports');
for I := 0 to Count - 1 do begin
NativeMethod := TNativeMethod(Items[I]);
Write(Stream, Format(' Java_%s_%s', [DotsToUnderscores(JavaClass), NativeMethod.Name]));
if I < Count - 1 then
Writeln(Stream, ',')
else
Writeln(Stream, ';');
end;
Writeln(Stream);
// End of file
Writeln(Stream, 'end.');
end;
// End TNativeMethods
//=====================================================================================
//=====================================================================================
// Main program
var
vm_args11: JDK1_1InitArgs;
EnvClassPath: string;
Options: array [0..4] of JavaVMOption;
VM_args: JavaVMInitArgs;
JavaVM: TJavaVM;
Errcode: Integer;
begin
JavaClassFile := '';
ClassPath := '';
IncludeNonNativeMethods := False;
VerboseOutput := False;
Platform := 'ALL';
{$IFDEF WIN32}
Platform := 'WIN32';
{$ENDIF}
{$IFDEF LINUX}
Platform := 'LINUX';
{$ENDIF}
try
if not ParseCommandLine then
Exit;
EnvClassPath := GetEnvironmentString('CLASSPATH');
if VerboseOutput then begin
JNI_GetDefaultJavaVMInitArgs(@vm_args11);
Write('[Search path = ');
if vm_args11.classpath <> nil then
Write(vm_args11.classpath);
if EnvClassPath <> '' then
Write(';', EnvClassPath);
Writeln(']');
end;
// Create the JVM (using a wrapper class)
JavaVM := TJavaVM.Create;
// Set the options for the VM
ClassPath := '-Djava.class.path=' + ClassPath + ';' + EnvClassPath;
Options[0].optionString := PChar(ClassPath);
VM_args.version := JNI_VERSION_1_2;
VM_args.options := @Options;
VM_args.nOptions := 1;
// Load the VM
Errcode := JavaVM.LoadVM(VM_args);
if Errcode < 0 then begin
WriteLn(Format('Error loading JavaVM, error code = %d', [Errcode]));
Exit;
end;
// Create a Java environment from the JVM's Env (another wrapper class)
JNIEnv := TJNIEnv.Create(JavaVM.Env);
if JavaClassFile = '' then begin
Writeln('Error: No classes were specified on the command line. Try -help.');
Exit;
end;
// This does all of the JNI work of retrieving the class methods
NativeMethods := GetNativeMethods(JavaClassFile);
// -o <file> was used
if OutputFilename <> '' then begin
AssignFile(OutputFile, OutputFilename);
Rewrite(OutputFile);
if VerboseOutput then
Writeln('Creating file ', OutputFilename, '...');
NativeMethods.EmitCode(JavaClassFile, OutputFile);
Close(OutputFile);
if VerboseOutput then
Writeln('Done.');
end
else
NativeMethods.EmitCode(JavaClassFile, Output);
except
on E : Exception do
WriteLn('Error: ' + E.Message);
end;
end.