Feeling like running towards a wall over and over and over. (Java\Delphi)

First of all, this is not a bad meaning towards the team of remobjects and responsible members of Hydra. I have written a few post the last days and weeks and always got a very fast and friendly response with upmost respect and being very helpful and reflective. But I´m running a bit out of time evaluating hydra for a upcoming project and either i discard the idea and start building a delphi rest-server soon or get hydra together with java working.

I want to introduce hydra in our company and no matter how much i evaluate and test the framework towards java it feels like i hit a wall. I know Hydra is very solid in .NET and in communication through delphi platforms but it still feels like java is either not used very much through consumer or I´m doing something fundamental wrong.

About my environment:

I have installed Windows 10 64-Bit latest Updates always included
I have installed Eclipse Version: 2019-09 R (4.13.0)
I have installed Embarcadero® Delphi 10.2 Version 25.0.29899.2631 Enterprise Edition
I have installed RemObjects Hydra - 6.2.101.1239 (beta) since there has been some fixes about interface generation in delphi. I also can try to install last official build to reproduce the issues.

As far it concerns Java i run AdoptOpenJDK 13 64 Bit Hotspot Edition in order to get Eclipse running while Java_Home points to JDK 1.8.0.241 32-Bit. This step were required that Hydra with Delphi can generate interfaces and Eclipse can be executed (they dropped 32-Bit support 2010). I generate JAR-Files via Eclipse using JDK 1.8.0.241 32-Bit as environment.

I followed your Guide https://docs.hydra4.com/Plugins/NonVisualPluginsJava/ and generated a simple plugin:

package xxx.hydra.plugins;

public interface PluginInterface extends com.remobjects.hydra.HYCrossPlatformNonVisualPlugin
{
public boolean GetBoolean();
public String GetString();
public byte GetByte();
public int GetInt();
public long GetLong();
public float GetFloat();
public double GetDouble();
public short GetShort();
public char GetChar();

// TODO : check if there would be possible to pass a Subobject as interface if its based on an Interface?
// public ISubObjectInterface GetInterface();
}

i implemented a Plugin implementation as followed:

package xxx.hydra.plugins;

public class PluginImplementation implements PluginInterface
{

@Override
public void pause() {
}

@Override
public void resume() {

}

@Override
public void start() {

}

@Override
public void stop() {

}

@Override
public boolean GetBoolean() {
return true;
}

@Override
public String GetString() {
return “Hello World”;
}

@Override
public byte GetByte() {
return 0x8;
}

@Override
public int GetInt() {
return 27;
}

@Override
public long GetLong() {
return 250;
}

@Override
public float GetFloat() {
return 29;
}

@Override
public double GetDouble() {
return 15.9;
}

@Override
public short GetShort() {
return 2;
}

@Override
public char GetChar() {
return ‘X’;
}
}

The values are just for testing.

I wrote a simple plugin descriptor as followed :

package xxx.hydra.plugins;

public class PluginDescriptor implements com.remobjects.hydra.PluginDescriptor {

public String getName() {
    return "NonVisualPlugin";
}

@SuppressWarnings("rawtypes")
public Class getPluginClass() {
    return PluginImplementation.class;
}

public String getDescription() {
// TODO Auto-generated method stub
return null;
}

public int getMajorVersion() {
// TODO Auto-generated method stub
return 1;
}

public int getMinorVersion() {
// TODO Auto-generated method stub
return 2;
}

public String getUserData() {
// TODO Auto-generated method stub
return “Test Data”;
}
}

added com.remobjects.hydra as external jar to project and export the file as “xxx.hydra.plugins.jar”.
I added com.remobjects.hydra.jar into same directory as application and plugin is stored.

In Delphi, if i have only one Method (either GetString or GetNumber) as interface it seems to work to generate an interface:

unit xxx_hydra_plugins_Import;

interface

uses
uHYCrossPlatformInterfaces,
uHYJavaTypes,
uHYJavaNonVisualPluginWrapper;

type
{ Forward declarations }
IPluginInterface = interface;
TPluginImplementationWrapper = class;

IPluginInterface = interface(IHYCrossPlatformNonVisualPlugin)
[‘{F8563254-6D04-4699-A843-CD0B71F503B3}’]
function GetNumber: JInt;
end;

TPluginImplementationWrapper = class(THYJavaNonVisualPluginWrapper, IPluginInterface)
public
function GetNumber: JInt;
end;

implementation

uses
uHYCrossPlatformModuleController;

function TPluginImplementationWrapper.GetNumber: JInt;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetNumber’, ‘()I’);
System.SetLength(largs, 0);
result := Self.JVM.Reflection.CallIntMethod(Self.InstanceID, lmethodId, largs);
exit;
end;

initialization
RegisterPlugin(‘xxx/hydra/plugins/PluginImplementation’, nil, TPluginImplementationWrapper);
end.

But if i want to import the functions above i get an exception that PluginImplementation cant be found.

Edit Exception of described issue :

I tried a few times to find the issue but it seems it raises only 9 of 10 cases. One time it worked.

The Result looks like this :

unit xxx_hydra_plugins_Import;

interface

uses
uHYCrossPlatformInterfaces,
uHYJavaTypes,
uHYJavaNonVisualPluginWrapper;

type
{ Forward declarations }
IPluginInterface = interface;
TPluginImplementationWrapper = class;

IPluginInterface = interface(IHYCrossPlatformNonVisualPlugin)
[‘{07FE71D7-11B4-442B-A571-FB4B1D6426C2}’]
function GetBoolean: JBoolean;
function GetDouble: JDouble;
function GetString: UnicodeString;
function GetShort: JShort;
function GetChar: JChar;
function GetInt: JInt;
function GetFloat: JFloat;
function GetByte: JByte;
function GetLong: JLong;
end;

TPluginImplementationWrapper = class(THYJavaNonVisualPluginWrapper, IPluginInterface)
public
function GetBoolean: JBoolean;
function GetDouble: JDouble;
function GetString: UnicodeString;
function GetShort: JShort;
function GetChar: JChar;
function GetInt: JInt;
function GetFloat: JFloat;
function GetByte: JByte;
function GetLong: JLong;
end;

implementation

uses
uHYCrossPlatformModuleController;

function TPluginImplementationWrapper.GetBoolean: JBoolean;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetBoolean’, ‘()Z’);
System.SetLength(largs, 0);
result := Self.JVM.Reflection.CallBooleanMethod(Self.InstanceID, lmethodId, largs);
exit;
end;

function TPluginImplementationWrapper.GetDouble: JDouble;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetDouble’, ‘()D’);
System.SetLength(largs, 0);
result := Self.JVM.Reflection.CallDoubleMethod(Self.InstanceID, lmethodId, largs);
exit;
end;

function TPluginImplementationWrapper.GetString: UnicodeString;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetString’, ‘()Ljava/lang/String;’);
System.SetLength(largs, 0);
result := Self.JVM.ValueConverter.ConvertToString(Self.JVM.Reflection.CallObjectMethod(Self.InstanceID, lmethodId, largs));
exit;
end;

function TPluginImplementationWrapper.GetShort: JShort;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetShort’, ‘()S’);
System.SetLength(largs, 0);
result := Self.JVM.Reflection.CallShortMethod(Self.InstanceID, lmethodId, largs);
exit;
end;

function TPluginImplementationWrapper.GetChar: JChar;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetChar’, ‘()C’);
System.SetLength(largs, 0);
result := Self.JVM.Reflection.CallCharMethod(Self.InstanceID, lmethodId, largs);
exit;
end;

function TPluginImplementationWrapper.GetInt: JInt;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetInt’, ‘()I’);
System.SetLength(largs, 0);
result := Self.JVM.Reflection.CallIntMethod(Self.InstanceID, lmethodId, largs);
exit;
end;

function TPluginImplementationWrapper.GetFloat: JFloat;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetFloat’, ‘()F’);
System.SetLength(largs, 0);
result := Self.JVM.Reflection.CallFloatMethod(Self.InstanceID, lmethodId, largs);
exit;
end;

function TPluginImplementationWrapper.GetByte: JByte;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetByte’, ‘()B’);
System.SetLength(largs, 0);
result := Self.JVM.Reflection.CallByteMethod(Self.InstanceID, lmethodId, largs);
exit;
end;

function TPluginImplementationWrapper.GetLong: JLong;
var
lmethodId: JMethodID;
largs: JValueDynArray;
begin
lmethodId := Self.JVM.Reflection.GetMethodId(Self.ClassID, ‘GetLong’, ‘()J’);
System.SetLength(largs, 0);
result := Self.JVM.Reflection.CallLongMethod(Self.InstanceID, lmethodId, largs);
exit;
end;

initialization
RegisterPlugin(‘xxx/hydra/plugins/PluginImplementation’, nil, TPluginImplementationWrapper);
end.

Since this topic is just for education purpose for now until i can display workable results i wrote a simple application in
32-Bit in Delphi.

My Java Modulemanager i have written is a bit bigger to show, but the required snippet for setup looks as followed:

FModuleManager := THYModuleManager.Create(nil);
FModuleManager.AutoLoad := False;
FModuleManager.ResolveInterfacesToOwner := True;
FModuleManager.EnforceSecurity := False;
FModuleManager.LoadJavaModule(AFilePath); // leads to xxx.hydra.plugins.jar
FModuleManager.CreateNonVisualPlugin(APluginName, hPlugin); // Pluginname is
‘NonVisualPlugin’ and hPlugin is IHYNonVisualPlugin

The last Part is that i run the methods through a button that should call the values from java and write them to a memo field.

procedure TMainFrm.btn_java_performClick(Sender: TObject);
var
hText: string;
hRawPlugin: IHYNonVisualPlugin;
hPlugin: IPluginInterface;
hIndex: Integer;
hValue: Integer;
begin
hRawPlugin := FJavaModule.LoadNonVisualPlugin(te_path.Text, te_plugin.Text, hIndex);

if (Supports(hRawPlugin, IPluginInterface)) then
begin
hPlugin := hRawPlugin as IPluginInterface;
if (hPlugin <> nil) then
begin
me_javatext.Text := ‘’;

  me_javatext.Lines.Add('GetBoolean(): ' + Ifthen(hPlugin.GetBoolean(), 'True', 'False'));
  me_javatext.Lines.Add('GetDouble(): ' + FloatToStr(hPlugin.GetDouble()));

  hText := string.copy(hPlugin.GetString());
  me_javatext.Lines.Add('GetString(): ' + hText);

  hValue := hPlugin.GetInt();
  me_javatext.Lines.Add('GetInt(): ' + IntToStr(hValue));
  me_javatext.Lines.Add('GetFloat(): ' + FloatToStr(hPlugin.GetFloat()));
  me_javatext.Lines.Add('GetByte(): ' + IntToStr(hPlugin.GetByte()));
  me_javatext.Lines.Add('GetLong(): ' + FloatToStr(hPlugin.GetLong()));
end;

end;
FJavaModule.UnloadPlugin(hRawPlugin);
hPlugin := nil;
end;

in this case following functions dont work :

function GetShort: JShort; -> Access Violation in module jvm.dll
function GetChar: JChar; -> Access Violation in module jvm.dll
function GetInt: JInt; -> Access Violation in module jvm.dll
function GetFloat: JFloat; -> Access Violation in module jvm.dll
function GetByte: JByte; -> Access Violation in module jvm.dll
function GetLong: JLong; -> Access Violation in module jvm.dll

I had this phenomen before with GetString and GetInt. Sometimes GetInt worked flawless but GetString had this exception… a few renewals of
interface generator then seemed to switch the situation and getInt worked but GetString ended up into an exception.

Also as open question is how i can add Interfaces to my structure like following:

Plugin
→ HeaderInterface
→ Name : string
→ ID : Integer
→ BodyInterface
→ Name: String;
→ ID: Integer;

In case its required i can send the full projects privately as attachment in order that it can be evaluated. But as far i see it, this are fundamental basics. I cant design or handle more complex cases when the described basic cant be used. And i can´t ask my company for invest into hydra and\or other remobject products if it wont help us in our further development. I´m at end of ideas.

Hi,

can you send your full project to support@, pls?
can you specify additional steps if they are required?

Yes i will do. Also add all required steps how i use it, what i do and so on. Will take a bit to prepare.

1 Like