when I Try in Pascal under Debian Jessie
TStringObjectMap2 = class
private
type
TStrObjMap = class(specialize TFPGMap<string, THostHandler>);
private
FObjects: TStrObjMap;
FDefaultObject: THostHandler;
FFreeObjects: boolean;
function GetObject(const AKey: string): THostHandler;
procedure SetDefault(AValue: THostHandler);
procedure SetObject(const AKey: string; AValue: THostHandler);
public
constructor Create(FreeObjects: boolean);
destructor Destroy; override;
procedure RemoveHandler(const AKey: string);
function TryGetObject(const AKey: string; out AObject: THostHandler): boolean;
property DefaultObject: THostHandler read FDefaultObject write SetDefault;
property Objects[const AKey: string]: THostHandler read GetObject write SetObject; default;
end;
the Line
Result := FObjects.TryGetData(AKey, AObject);
can not compiled
But under Win 10 there is no problem.
Whats going wrong?
Related
Below is the output of test code.
Why are the addresss of instance(#a) and the address of Self(#Self) in constructor different?
I think both should be the same.
The addresss of class instance and the address of this in constructor are same in c++.
Is it possible to get the address equal to the addresss of instance(#a) in constructor?
Lazarus 2.2.0 64bit for windows.
#Self=00000000013FFDC8
#a=00000000013FFE38
a.i=3
a_ptr^.i=3
ga_ptr^.i=5872 << invalid value
unit unitmain;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils;
type
ClassA = class
public
constructor Create(i : Integer);
var
i : Integer;
end;
PClassA = ^ClassA;
var
ga_ptr : PClassA;
procedure TestSelfAddr();
implementation
constructor ClassA.Create(i : Integer);
begin
Self.i := i;
ga_ptr := #Self;
Writeln(Format('#Self=%P', [#Self]));
end;
procedure TestSelfAddr();
var
a : ClassA = nil;
a_ptr : PClassA = nil;
begin
a := ClassA.Create(3);
a_ptr := #a;
Writeln(Format('#a=%P', [#a]));
Writeln(Format('a.i=%d', [a.i]));
Writeln(Format('a_ptr^.i=%d', [a_ptr^.i]));
Writeln(Format('ga_ptr^.i=%d', [ga_ptr^.i])); // << invalid value
end;
end.
I am working on my main project and I have to "JSON serialize" a simple class :
TServer = class
public
Host: string;
end;
TServerList = class
public
Servers: TArray<TServer>;
end;
procedure Test;
begin
var SrvLst := TServerList.Create;
SetLength(SrvLst.Servers, 1);
SrvLst.Servers[0] := TServer.Create;
SrvLst.Servers[0].Host := 'TEST';
var Json := TJson.ObjectToJsonString(SrvLst);
// >> Json = '{"servers":[{"host":"TEST"}]}' , it works...
var SrvLst2 := TJson.JsonToObject<TServerList>(Json);
// >> SrvLst2.Server is empty ?? what's wrong ??
// memory leaks.. nevermind
end;
I can't see what is wrong... Any idea ?
Thank you.
You need to either declare the classes this way:
TServer = class
private
FHost: string;
public
property Host: string read FHost write FHost;
end;
TServerList = class
private
FServers: TArray<TServer>;
public
property Servers: TArray<TServer> read FServers write FServers;
end;
or this way:
type
TServer = class
public
[JSONName('Host')]
Host: string;
end;
TServerList = class
public
[JSONName('Servers')]
Servers: TArray<TServer>;
end;
Note that the latter requires to use REST.Json.Types.
I have an object eg.:
TFoo = class(TObject)
private
FConnection : TADOConnection;
public
FName : string;
FSurname : string;
end;
i convert this object in a json string with ObjectToJsonString, eg.:
uses REST.Json;
// ...
var
aFoo : TFoo;
begin
aFoo := TFoo.create;
Memo1.lines.text := TJson.ObjectToJsonString(aFoo);
aFoo.free;
end;
TJson.ObjectToJsonString make a json string with both private and public variables.
i want exclude some variable like FConnection from the json string (it expose also the connection string).
Any suggestion for allow the json conversion only on the public variable?
Use the JSONMarshalled attribute:
Attribute that specifies whether a field or type should be marshalled and unmarshalled.
If JSONMarshalledAttribute is not present in a field or type, that field or type should be marshalled and unmarshalled. If JSONMarshalledAttribute is present but is False, the marshalling and unmarshalling processes skip that field or type.
For example:
type
TFoo = class(TObject)
private
[JSONMarshalled(False)]
FConnection : TADOConnection;
public
FName : string;
FSurname : string;
end;
Also look at the JSONName attribute. By default, if a field name begins with an F character, marshaling strips off the F in the resulting JSON data. In your example above, this is fine, so that FName and FSurname are marshalled as Name and Surname. But this may not always be desirable, so you can use JSONName to specify your own field names in the JSON data, eg:
type
TFoo = class(TObject)
private
[JSONMarshalled(False)]
FConnection : TADOConnection;
public
Name : string;
Surname : string;
[JSONName('FullName')]
FullName : string;
end;
I have a class hierarchy which abstracts the Lockbox crypto components.
Specifically, we are interested in AES-265 with PKCS#5 padding.
The class instance is set correctly with CBC and the encoding explicitly set to ANSI but the resulting output is scrambled, which means that the padding is off.
Alas, CBC supports more than one padding scheme and I think Lockbox isn't using the one we need.
Do you have any ideas where I am going wrong?
This is the class hierarchy's relevant code:
TsmEncryptBase = class(TInterfacedObject, IsmEncryption)
private
FLib: TCryptographicLibrary;
protected
FCodec: TCodec;
function Encrypt: Boolean; virtual; abstract;
function Decrypt: Boolean; virtual; abstract;
public
constructor Create(const APassword: string;
const aCipherId: string = 'native.AES-256';
const aChainModeId:string = 'native.CBC');
destructor Destroy; override;
end;
constructor TsmEncryptBase.Create(const APassword: string; const aCipherId:
string; const aChainModeId: string);
begin
inherited Create;
FLib := TCryptographicLibrary.Create(nil);
// FLib.RegisterBlockChainingModel( TPure_ECB.Create as IBlockChainingModel);
FCodec := TCodec.Create(nil);
FCodec.CryptoLibrary := FLib;
FCodec.StreamCipherId := uTPLb_Constants.BlockCipher_ProgId;
FCodec.BlockCipherId := aCipherId;
FCodec.ChainModeId := uTPLb_Constants.CBC_ProgId;
FCodec.Password := APassword;
end;
TsmFileEncryptAES = class(TsmEncryptBase)
private
FPlainTextFileName: string;
FEncryptedFileName: string;
protected
function Encrypt: boolean; override;
function Decrypt: Boolean; override;
public
constructor Create(const APlainTextFileName, AEncryptedFileName,
APassword: string);
end;
constructor TsmFileEncryptAES.Create(const APlainTextFileName, AEncryptedFileName,
APassword: string);
begin
inherited Create(APassword);
FPlainTextFileName := APlainTextFileName;
FEncryptedFileName := AEncryptedFileName;
FCodec.Encoding := TEncoding.ANSI;
end;
The code is used like so:
procedure TForm1.AESFileDecryptClick(Sender: TObject);
var lEncrypt: IsmEncryption;
begin
lEncrypt := TsmFileEncryptAES.Create(AESFileSaveTo.AsString,
AESSourceFile.AsString, AESFileKey.AsString);
lEncrypt.Decrypt;
end;
Any ideas?
Parameters of Server methods in datasnap supports a number of data type. TArray<string> or array of string shall be basic type, but the following Test method is not working:
type{$M+}
TMyModule = class(TDSServerModule)
public
function ReverseString(Value: string): string;
function Test: TArray<string>;
end;
Is there an alternative way to get array works with server methods?
Yes, there is.
All you need to do is to encapsulate your array in an object.
Here is an example for an array of integers :
`
unit TransferObjects;
interface
type
TIntArray = TArray<Integer>;
TIntegerArray = class(TObject)
private
FValues: TIntArray;
function GetValues: TIntArray;
procedure SetValues(const Value: TIntArray);
public
property Values : TIntArray read GetValues write SetValues;
constructor Create;
function Length : Integer;
procedure Resize(Count : Integer);
end;
implementation
{ TIntegerArray }
constructor TIntegerArray.Create;
begin
inherited create;
Resize(0);
end;
function TIntegerArray.GetValues: TIntArray;
begin
Result := FValues;
end;
function TIntegerArray.Length: Integer;
begin
Result := System.Length(FValues);
end;
procedure TIntegerArray.Resize(Count : Integer);
begin
SetLength(FValues, Count);
end;
procedure TIntegerArray.SetValues(const Value: TIntArray);
begin
FValues := Value;
end;
end.
unit ServerMethodsUnit1;
interface
uses System.SysUtils, System.Classes, Datasnap.DSServer, Datasnap.DSAuth,
TransferObjects;
type
{$METHODINFO ON}
TServerMethods1 = class(TComponent)
private
{ Private declarations }
public
{ Public declarations }
function ReverseArray(Value : TIntegerArray) : TIntegerArray;
end;
{$METHODINFO OFF}
implementation
function TServerMethods1.ReverseArray(Value: TIntegerArray): TIntegerArray;
var
i, l : Integer;
Erg : TIntegerArray;
begin
Erg := TIntegerArray.Create;
Erg.Resize(Value.Length);
for i := 0 to Value.Length-1 do
begin
l := Value.Length-1-i;
Erg.Values[l] := Value.Values[i];
end;
Result := Erg;
end;
end.
`
This may not be very elegant, but it works (tested with XE6).
Like this the object can be (un)marshaled internally with JSON, the same code using interfaces instead does not work.
hth