Jump to content

vfbb

Members
  • Content Count

    100
  • Joined

  • Last visited

  • Days Won

    7

vfbb last won the day on June 6 2020

vfbb had the most liked content!

Community Reputation

63 Excellent

Technical Information

  • Delphi-Version
    Delphi 10.4 Sydney

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Virtual interfaces: to create an object that support an interface in run time. See System.Rtti.TVirtualInterface
  2. Sometimes I come across some delphi language enhancements that are undocumented or are poorly documented. In the last few years docwiki has improved a lot, but there are still undocumented cases, such as accessing an item in an array just by declaring a property, without any method: TipGeolocation = record private FCoordinates: array[0..1] of Double; public property Latitude: Double read FCoordinates[0] write FCoordinates[0]; property Longitude: Double read FCoordinates[1] write FCoordinates[1]; end; Share here any enhancements to the delphi language that you have discovered but are not documented.
  3. Although I don't particularly like this design, you can make a descendant of TInterfacedPersistent, your class will not be arc and will be able to implement interfaces. TBaseFrame = class(TInterfacedPersistent)
  4. vfbb

    iPub Refit - REST API in simple way

    @Attila Kovacs You are right about compatibility, thanks for checking this out. I will put this observation. In the future I can do some backwards compatibility, but not now. About the null values serialization, this library is just to consumes one rest api, then the serialization can occur just when you call a Post or Put and have the parameter ABody that is a record or a class or an array. In this specific case, the library will serialize the type as json, and in this case, the values that is null will be written to the json body without skip. The current implementation of System.JSON.Serializers don’t permit to ignore the fields with null values. Sorry i'll make it clearer
  5. vfbb

    iPub Refit - REST API in simple way

    @Attila Kovacs Here one example without TValue.Make<T>, and with the nullables stating with IsNull True: uses System.Rtti, System.TypInfo, System.JSON.Serializers, System.JSON.Readers, System.JSON.Writers, System.JSON.Types, iPub.Rtl.Refit; type TNullable<T> = record strict private FIsNotNull: Boolean; function GetIsNull: Boolean; procedure SetIsNull(AValue: Boolean); public Value: T; property IsNull: Boolean read GetIsNull write SetIsNull; end; TNullableConverter<T> = class(TJsonConverter) public procedure WriteJson(const AWriter: TJsonWriter; const AValue: TValue; const ASerializer: TJsonSerializer); override; function ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; const AExistingValue: TValue; const ASerializer: TJsonSerializer): TValue; override; function CanConvert(ATypeInf: PTypeInfo): Boolean; override; end; { TNullable<T> } function TNullable<T>.GetIsNull: Boolean; begin Result := not FIsNotNull; end; procedure TNullable<T>.SetIsNull(AValue: Boolean); begin FIsNotNull := not AValue; end; { TNullableConverter<T> } function TNullableConverter<T>.CanConvert(ATypeInf: PTypeInfo): Boolean; begin Result := ATypeInf = TypeInfo(TNullable<T>); end; function TNullableConverter<T>.ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; const AExistingValue: TValue; const ASerializer: TJsonSerializer): TValue; var LNullable: TNullable<T>; begin if AReader.TokenType = TJsonToken.Null then begin LNullable.IsNull := True; LNullable.Value := Default(T); end else begin LNullable.IsNull := False; LNullable.Value := AReader.Value.AsType<T>; end; TValue.Make(@LNullable, TypeInfo(TNullable<T>), Result); end; procedure TNullableConverter<T>.WriteJson(const AWriter: TJsonWriter; const AValue: TValue; const ASerializer: TJsonSerializer); var LNullable: TNullable<T>; LValue: TValue; begin LNullable := AValue.AsType<TNullable<T>>; if LNullable.IsNull then AWriter.WriteNull else begin TValue.Make(@LNullable.Value, TypeInfo(T), LValue); AWriter.WriteValue(LValue); end; end; initialization GRestService.RegisterConverters([TNullableConverter<string>, TNullableConverter<Byte>, TNullableConverter<Word>, TNullableConverter<Integer>, TNullableConverter<Cardinal>, TNullableConverter<Single>, TNullableConverter<Double>, TNullableConverter<Int64>, TNullableConverter<UInt64>, TNullableConverter<TDateTime>, TNullableConverter<Boolean>, TNullableConverter<Char>]); end. To test: TUser = record Name: TNullable<string>; Location: string; Id: Integer; Email: TNullable<string>; NonexistentField: TNullable<Integer>; end; [BaseUrl('https://api.github.com')] IGithubApi = interface(IipRestApi) ['{4C3B546F-216D-46D9-8E7D-0009C0771064}'] [Get('/users/{user}')] function GetUser(const AUser: string): TUser; end; procedure TForm1.FormCreate(Sender: TObject); var LGithubApi: IGithubApi; LUser: TUser; begin LGithubApi := GRestService.&For<IGithubApi>; LUser := LGithubApi.GetUser('viniciusfbb'); end;
  6. vfbb

    iPub Refit - REST API in simple way

    Works perfectly in both cases, with the [] or with {..},{..},{..}. In both cases your function result should be a TArray<> of a record or a class. Do you mean what happens with the nullable fields that were not received? Well, all fields are set to the default value before reading the received json, so there are several possible workarounds to ensure that the field not received is considered null. In sydney just add the class operator Initialize to set IsNull true, but in older versions, you can simply change the name of IsNull to IsValid, since the boolean fields started False, then the initial value of IsValid of nullable will be False. But there are other possibilities.
  7. vfbb

    iPub Refit - REST API in simple way

    @Attila Kovacs About the version of delphi supported, according to docwiki, the units System.JSON.XXX was introduced in Delphi 10 Seattle, but again I can’t guarantee it’s compatible as it would need to be tested on these versions.
  8. vfbb

    iPub Refit - REST API in simple way

    @Attila Kovacs I added support to register custom json converters. About the nullables, is very easy to implement the nullable and the converters. See one simple solution: uses System.Rtti, System.TypInfo, System.JSON.Serializers, System.JSON.Readers, System.JSON.Writers, System.JSON.Types, iPub.Rtl.Refit; type TNullable<T> = record IsNull: Boolean; Value: T; end; TNullableConverter<T> = class(TJsonConverter) public procedure WriteJson(const AWriter: TJsonWriter; const AValue: TValue; const ASerializer: TJsonSerializer); override; function ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; const AExistingValue: TValue; const ASerializer: TJsonSerializer): TValue; override; function CanConvert(ATypeInf: PTypeInfo): Boolean; override; end; { TNullableConverter<T> } function TNullableConverter<T>.CanConvert(ATypeInf: PTypeInfo): Boolean; begin Result := ATypeInf = TypeInfo(TNullable<T>); end; function TNullableConverter<T>.ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; const AExistingValue: TValue; const ASerializer: TJsonSerializer): TValue; var LNullable: TNullable<T>; begin if AReader.TokenType = TJsonToken.Null then begin LNullable.IsNull := True; LNullable.Value := Default(T); end else begin LNullable.IsNull := False; LNullable.Value := AReader.Value.AsType<T>; end; TValue.Make<TNullable<T>>(LNullable, Result); end; procedure TNullableConverter<T>.WriteJson(const AWriter: TJsonWriter; const AValue: TValue; const ASerializer: TJsonSerializer); var LNullable: TNullable<T>; LValue: TValue; begin LNullable := AValue.AsType<TNullable<T>>; if LNullable.IsNull then AWriter.WriteNull else begin TValue.Make<T>(LNullable.Value, LValue); AWriter.WriteValue(LValue); end; end; initialization GRestService.RegisterConverters([TNullableConverter<string>, TNullableConverter<Byte>, TNullableConverter<Word>, TNullableConverter<Integer>, TNullableConverter<Cardinal>, TNullableConverter<Single>, TNullableConverter<Double>, TNullableConverter<Int64>, TNullableConverter<UInt64>, TNullableConverter<TDateTime>, TNullableConverter<Boolean>, TNullableConverter<Char>]); end. To use just replace the simple types to the nullable types: TUser = record Name: TNullable<string>; Location: string; Id: Integer; Email: TNullable<string>; end; [BaseUrl('https://api.github.com')] IGithubApi = interface(IipRestApi) ['{4C3B546F-216D-46D9-8E7D-0009C0771064}'] [Get('/users/{user}')] function GetUser(const AUser: string): TUser; end; procedure TForm1.FormCreate(Sender: TObject); var LGithubApi: IGithubApi; LUser: TUser; begin LGithubApi := GRestService.&For<IGithubApi>; LUser := LGithubApi.GetUser('viniciusfbb'); end; You can test the code above and see the user name is not null but the user email is null. The nullable type and the nullable converter code in this example need to be implemented by the developer, I can't put it on the library because each developer has it own implementation os nullable.
  9. vfbb

    iPub Refit - REST API in simple way

    I don't have older versions installed to be able to test, or do backwards compatibility, but it looks like you're right, delphi 10.2 tokyo or newer. What exactly did you want? The json serialization of delphi is very malleable, you do not need to declare all the necessary fields and you can also use all existing attributes in System.Json.Serializers.pas. It's a great option, I will implement it today.
  10. A very simple way to consume one Rest Api, just declaring one interface, based on .Net Refit: https://github.com/viniciusfbb/ipub-refit
  11. vfbb

    Cross-platform messaging system

    Made. It's not worth, it's a very limited system, synchronous, windows support only ...
  12. vfbb

    Cross-platform messaging system

    This is just a simplistic messaging system. Don't compare a simple, lightweight 1k line system with a complete 50k line system (although messages work just as well).
  13. vfbb

    Cross-platform messaging system

    @Andrea Raimondi The full explanation is on the github page. See this part: "The problem Delphi has its own messaging system (System.Messaging.pas) that works well but is totally synchronous and thread unsafe. In multithreaded systems we always need to communicate with other classes, sometimes synchronously, sometimes asynchronously, sometimes synchronizing with the mainthread (in the case of the UI), and doing this without a message system (communicating directly) makes the code large and complex, prone to many bugs."
  14. Making it available to everyone who want a thread safe, asynchronous, cross-platform and simplistic messaging system for communication between classes / layers in delphi applications. https://github.com/viniciusfbb/ipub-messaging
  15. String works exactly like a bitmap (bitmap handle) from firemonkey. When you create a string, through another, s2: = s1, this does not immediately create a copy of the string, but rather increases 1 refcount from a single original string, however when you change the string, internally it will check if the refcount is> 1 , it will create a copy, a new string with refcount 1, to make the changes, and not affect other places that are using that string. This was done to optimize, increase performance, as there are some manipulations of strings that in the end do not change the string, for example s2: = s1.PadLeft (0) will not create a copy, will return the string s1 with 1 more reference . The use of const in the parameter is an optimizer as it avoids operations with the refcount. However Marco Cantu warns of a problem generated when using const in the method argument, because if inside it you indirectly change the original string (for example by calling an event within its method) and the refcount of that string is 1 (which possibly will be ), within its method the argument with const will become invalid.
×