4

How to convert JObject to TJavaArray in DELPHI?

I tried this method but without result

var
  jvObject: JObject;
  jvArray: TJavaArray<byte>;
begin
  jvArray:= TJavaArray<byte>(jvObject);

because result of jvArray is nil.

Have anyone any idea how to solve this conversion?

1 Answers1

0

What you are asking for is, I think, in Java terms referred to as serialising the object.

Here is a unit that does the trick:

unit SerialiseU;

interface

uses
  Androidapi.JNI.JavaTypes,
  Androidapi.JNIBridge;

//References:
//  http://docs.oracle.com/javase/6/docs/platform/serialization/spec/serialTOC.html
//  http://stackoverflow.com/questions/5837698#5837739

type
  TSerialiser = class
  public
    class function Serialise(const Obj: JObject): TJavaArray<Byte>;
    class function Deserialise(Bytes: TJavaArray<Byte>): JObject;
  end;

implementation

// Delphi XE5 and later (all Android-supporting versions) offer an
// import for java.io.ByteArrayOutputStream and java.io.ByteArrayInputStream
// in Androidapi.JNI.JavaTypes.pas.
// However neither java.io.ObjectInputStream nor java.io.ObjectOutputStream
// are imported in any version up to the current (at time of writing) version,
// Delphi 10.1 Berlin, so we import the bits we need here.

type
// ===== Forward declarations =====

  JObjectInputStream = interface;//java.io.ObjectInputStream
  JObjectOutputStream = interface;//java.io.ObjectOutputStream

// ===== Interface declarations =====

  JObjectInputStreamClass = interface(JInputStreamClass)
    ['{443A1BEF-E21F-4012-A28B-4D7735136BD3}']
    {class} function init(input: JInputStream): JObjectInputStream; cdecl;//Deprecated
  end;

  [JavaSignature('java/io/ObjectInputStream')]
  JObjectInputStream = interface(JInputStream)
    ['{C1360ABB-AF58-4607-B43E-C1E1652E8FC2}']
    function readObject: JObject; cdecl;//Deprecated
  end;
  TJObjectInputStream = class(TJavaGenericImport<JObjectInputStreamClass, JObjectInputStream>) end;

  JObjectOutputStreamClass = interface(JOutputStreamClass)
    ['{D43CF30C-1E94-4D2E-A473-91EE54E41F07}']
    {class} function init(output: JOutputStream): JObjectOutputStream; cdecl;//Deprecated
  end;

  [JavaSignature('java/io/ObjectOutputStream')]
  JObjectOutputStream = interface(JOutputStream)
    ['{F4E441F8-B3D0-4463-A052-880F6644FB42}']
    procedure writeObject(&object: JObject); cdecl;
  end;
  TJObjectOutputStream = class(TJavaGenericImport<JObjectOutputStreamClass, JObjectOutputStream>) end;

{ TSerialiser }

class function TSerialiser.Serialise(const Obj: JObject): TJavaArray<Byte>;
var
  b: JByteArrayOutputStream;
  o: JObjectOutputStream;
begin
  b := TJByteArrayOutputStream.Create;
  o := TJObjectOutputStream.JavaClass.init(b);
  o.writeObject(Obj);
  Result := b.toByteArray;
end;

class function TSerialiser.Deserialise(Bytes: TJavaArray<Byte>): JObject;
var
  b: JByteArrayInputStream;
  o: JObjectInputStream;
begin
  b := TJByteArrayInputStream.JavaClass.Init(Bytes);
  o := TJObjectInputStream.JavaClass.init(b);
  Result := o.readObject;
end;

end.

This can be used like this:

uses
  SerialiseU,
  Androidapi.Helpers,
  Androidapi.JNIBridge,
  Androidapi.JNI.JavaTypes;
...
var
  S, S2: String;
  JS, JS2: JString;
  O: JObject;
  Bytes: TJavaArray<Byte>;
...
  // Get some Java object. In this case it is a Java java.lang.String object
  // http://d.android.com/reference/java/lang/String.html
  S := Edit1.Text;
  JS := StringToJString(S);
  // Serialise the string into a byte array
  Bytes := TSerialiser.Serialise(JS);
  // Now de-serialise the byte array back to an object
  O := TSerialiser.Deserialise(Bytes);
  // Prove that the correct object type has been de-serialised
  ShowMessageFmt('Deserialised a %s object',
    [JStringToString(O.getClass.getCanonicalName)]);
  // Cast the generic object back to a Java string
  JS2 := TJString.Wrap(O);
  // Get a Delphi string out, just to dot the 'i's and cross the 't's
  S2 := JStringToString(JS2);
  // Put the extracted string back on the UI so we can prove it all worked
  Edit1.Text := S2;
end;
blong
  • 2,145
  • 13
  • 23