desco.es

  • Aumentar fuente
  • Fuente predeterminada
  • Disminuir fuente
Bienvenidos a la portada

Attributos de la Rtti

E-mail Imprimir PDF

Desde la versión 2010 de Delphi, se agregó a la Rtti los attributos, que corresponden con las anotaciones de otros lenguajes como Java o .Net.

Con esta nueva característica de la Rtti podemos añadir a clases, méodos o propiedades, atributos en tiempo de diseño y desarrollo que después podremos recuperar en tiempo de ejecución a través de la Rtti.

Para nosotros será útil para el desarrollo del framework que tenemos en marcha, ya que las utilizaremos para automatizar muchas cosas.

Como sabemos la Rtti lleva mucho tiempo con nosotros y como característica más importante (por lo menos para nuestro framework) es la de poder recuperar las propiedades de una clase, que se hace de forma sencilla 

function GoGetProperties(const AClass: TClass): TStrings;
var
  cxt: TRttiContext;
  t : TRttiType;
  p  : TRttiProperty;
begin
  Result := TStringList.Create;
  cxt := TRttiContext.Create;
  try
    t := cxt.GetType(AClass);
    for p in t.GetProperties do
    begin
      Result.Add(p.Name);
    end;
  finally
    cxt.Free;
  end;
end;

Si lanzamos la functión sobre la clase TMyClass del articulo Serialización sencilla JSON (II) el resultado sería:

IntegerValue
DoubleValue
StringValue

Respecto a los atributos, descienden de la clase TCustomAttribute alojada en System.Rtti y para asociar el atributo a un tipo, método, campo o propiedad simplemente hay que ponerlo entre [] antes de su definición.

type
  TMyAttribute = class(TCustomAttribute)
  end;
  TMyAttribute2 = class(TCustomAttribute)
  end;
  TMyAttribute3 = class(TCustomAttribute)
  end;

  [TMyAttribute]
  TMyClass = class
    ...
    [TMyAttribute2]
    property IntegerValue: Integer read FIntegerValue write FIntegerValue;
    property DoubleValue: Double read FDoubleValue write FDoubleValue;
    [TMyAttribute3]
    property StringValue: string read FStringValue write FStringValue;
    ...
  end;
  ...


Para acceder en tiempo de ejecución a estos atributos, accederemos a la lista de atributos adjunta al tipo, método, campo o propiedad reflejados en la Rtti.

function GoGetProperties2(const AClass: TClass): TStrings;
var
  cxt: TRttiContext;
  t : TRttiType;
  p  : TRttiProperty;
  Attr: TCustomAttribute;
  s: string;
begin
  Result := TStringList.Create;
  cxt := TRttiContext.Create;
  try
    t := cxt.GetType(AClass);
    s := '';
    for Attr in t.GetAttributes do
    begin
      s := ',' + Attr.ClassName;
      if Attr is TMyAttribute then
      begin
        // Este clase tiene asociado el atributo TMyAttribute
      end;
    end;
    if s'' then
      s := '('+s.Substring(2)+')';
    Result.Add('Type: '+t.Name+' '+s);
    for p in t.GetProperties do
    begin
      s := '';
      for Attr in p.GetAttributes do
      begin
        s := ',' + Attr.ClassName;
        if Attr is TMyAttribute2 then
        begin
          // Este propiedad tiene asociado el atributo TMyAttribute2
        end;
      end;
      if s'' then
        s := '('+s.Substring(2)+')';
      Result.Add('  Property: '+ p.Name+' '+s);
    end;
  finally
    cxt.Free;
  end;
end;

Si pasamos esta función sobre la calse TMyClass

Type: TMyclass (MyAttribute)
  Property: IntegerValue (MyAttribute2)
  Property: DoubleValue
  Property: StringValue (MyAttribute3)

Además podemos crear propiedades a los atributos que después podremos recuperar, para ello los crearemos en la clase del atributo:

   ...
  TMyAttribute2 = class(TCustomAttribute)
  private
    FValue: string;
  public
    property Value: string read FValue write FValue;
    constructor Create(const AValue: string = '');
  end;
  ...
constructor TMyAttribute2.Create(const AValue: string);
begin
  FValue := AValue;
end;
  ...

Si ponemos una pequeña modificación cuando recuperamos los atributos de las propiedades podemos recuperar estos valores

        ...
        if Attr is TMyAttribute2 then
        begin
          // Este propiedad tiene asociado el atributo TMyAttribute2
          s := s + '{' + TMyAttribute2(Attr).Value + '}';
        end;
       ...

 

 Si añadimos un valor a este atributo en la propiedad del ejemplo

    ...
    [TMyAttribute2('Esto es SPARTA')]
    property IntegerValue: Integer read FIntegerValue write FIntegerValue;
    ...

Ahora el resultado de pasar la función sobre la clase

Type: TMyclass (MyAttribute)
  Property: IntegerValue (MyAttribute2{Esto es SPARTA})
  Property: DoubleValue
  Property: StringValue (MyAttribute3)

Hemos visto como usar los atributos de la Rtti así de como recuperarlos de un tipo, método, campo o propiedad. Esta utilización de la Rtti nos será muy útil para nuestros propósitos.

Última actualización el Lunes, 01 de Junio de 2015 14:56
 

Serialización sencilla JSON (II)

E-mail Imprimir PDF

Vamos a ver de manera sencilla como crear la el objeto JSON personalizado de nuestra clase,

para eso veamos la clase creada:

 

unit Unit1;


interface


uses

  Data.DBXJSON;


type

  TMyclass = class(TObject)

  private

    FIntegerValue: Integer;

    FDoubleValue: Double;

    FStringValue: string;

  public

    class function FromJsonObject(const AJsonObject: TJSONObject): TMyClass;

    class function FromJsonString(const AJsonString: string): TMyClass;

    function ToJsonObject: TJSONObject;

    function ToJsonString: string;

  published

    property IntegerValue: Integer read FIntegerValue write FIntegerValue;

    property DoubleValue: Double read FDoubleValue write FDoubleValue;

    property StringValue: string read FStringValue write FStringValue;

  end;


implementation


uses

  System.SysUtils;


{ TMyclass }


class function TMyclass.FromJsonObject(

  const AJsonObject: TJSONObject): TMyClass;

begin

  Result := TMyclass.Create;

  if Assigned(AJsonObject) then

  begin

    Result.FIntegerValue := TJSONNumber(AJsonObject.Get('I').JsonValue).AsInt;

    Result.FDoubleValue := TJSONNumber(AJsonObject.Get('D').JsonValue).AsDouble;

    Result.FStringValue := TJSONString(AJsonObject.Get('S').JsonValue).Value;

  end;

end;


class function TMyclass.FromJsonString(const AJsonString: string): TMyClass;

var

  AJson: TJSONValue;

begin

  AJson := TJSONObject.ParseJSONValue(AJsonString);

  try

    Result := FromJsonObject(TJSONObject(AJson));

  finally

    if Assigned(AJson) then

      AJson.Free;

  end;

end;


function TMyclass.ToJsonObject: TJSONObject;

begin

  Result := TJSONObject.Create;

  Result.AddPair('I',TJSONNumber.Create(FIntegerValue));

  Result.AddPair('D',TJSONNumber.Create(FDoubleValue));

  Result.AddPair('S',TJSONString.Create(FStringValue));

end;


function TMyclass.ToJsonString: string;

begin

  with ToJsonObject do

  try

    Result := ToString;

  finally

    Free;

  end;

end;


end.

 

 

TMyClass es una ampliación de lo que vimos en el post anterior (Serialización sencilla en JSON), aquí el cotarro está en ToJsonObject y FormJsonObject, donde usamos el método AddPair de TJSONObject para ir añadiendo los campos que queremos serializar. que posteriormente recuperaremos con la función Get

 

Como ejemplo:

function TForm2.Test: string;

begin

  with TMyclass.Create do

    try

      IntegerValue := MaxInt;

      DoubleValue := 100728.897;

      StringValue := 'Hola Mundo';

      Result := ToJsonString;

    finally

      Free;

    end;

end;


Result = {"I":2147483647,"D":100728.897,"S":"Hola Mundo"}

 

Ahora vamos a ver como funcionan los arrays, para verlo podemos crear una lista de objetos, como

...

type

  TMyClassList = class(TObjectList<TMyclass>)

  public

    class function FromJsonObject(const AJsonObject: TJSONObject): TMyClassList;

    class function FromJsonString(const AJsonString: string): TMyClassList;

    function ToJsonObject: TJSONObject;

    function ToJsonString: string;

  end;

...

class function TMyClassList.FromJsonObject(const AJsonObject: TJSONObject): TMyClassList;

var

  AJsonArray: TJSONArray;

  i: Integer;

begin

  Result := TMyClassList.Create;

  if Assigned(AJsonObject) then

  begin

    AJsonArray := TJSONArray(AJsonObject);

    for i := 0 to AJsonArray.Size - 1 do

      Result.Add(TMyclass.FromJsonObject(TJSONObject(AJsonArray.Get(i))));

  end;

end;


class function TMyClassList.FromJsonString(const AJsonString: string): TMyClassList;

var

  AJson: TJSONValue;

begin

  AJson := TJSONObject.ParseJSONValue(AJsonString);

  try

    Result := FromJsonObject(TJSONObject(AJson));

  finally

    if Assigned(AJson) then

      AJson.Free;

  end;

end;


function TMyClassList.ToJsonObject: TJSONObject;

var

  AJsonArray: TJSONArray;

  i: Integer;

begin

  AJsonArray := TJSONArray.Create;

  for i := 0 to Count - 1 do

    AJsonArray.AddElement(Items[i].ToJsonObject);

  Result := TJSONObject(AJsonArray);

end;


function TMyClassList.ToJsonString: string;

begin

  with TJSONArray(ToJsonObject) do

    try

      Result := ToString;

    finally

      Free;

    end;

end;

...

 

He usado las mismas pautas que en TMyClass para ver de forma sencilla podemos generarlo. Usamos TJSONArray.AddElement para crear los elementos y Get para recuperarlos.

 

Como ejemplo

function TForm2.Test: string;

var

  a: TMyclass;

  b: TMyClassList;

begin

  b := TMyClassList.Create;

  try

    a := TMyclass.Create;

    with a do

    begin

      IntegerValue := MaxInt;

      DoubleValue := 100728.897;

      StringValue := 'Antonio';

    end;

    b.Add(a);

    a := TMyclass.Create;

    with a do

    begin

      IntegerValue := 0;

      DoubleValue := 827.09;

      StringValue := 'Pedro';

    end;

    b.Add(a);

    a := TMyclass.Create;

    with a do

    begin

      IntegerValue := -MaxInt;

      DoubleValue := -3.141596;

      StringValue := 'Jose';

    end;

    b.Add(a);

    Result := b.ToJsonString;

  finally

    b.Free;

  end;

end;


Result = [{"I":2147483647,"D":100728.897,"S":"Antonio"},{"I":0,"D":827.09,"S":"Pedro"},{"I":-2147483647,"D":-3.141596,"S":"Jose"}]

 

De una forma sencilla podemos crear nuestra propia serialización.

 


Última actualización el Viernes, 29 de Mayo de 2015 09:23
 

Desarrollo de Framework

E-mail Imprimir PDF

Para aprender un poco más sobre Delphi, voy ha realizar una serie de posts a través de los cuales se desarrollará un Framework de trabajo.

 

El objetivo que me planteo es aprender, en la medida de lo posible, sobre:

  • Rtti (Run-Time Type Information)
  • Interfaces
  • Json
  • Persistencia 
  • Integración en el IDE de Delphi
  • Ingeniería inversa
  • Bases de Datos

Intentaremos implementar un framework para el desarrollo de soluciones de negocio orientadas a objetos. Ya sé que existen soluciones buenas, pero la función es la del aprendizaje.


Se desarrollará sobre Delphi XE5, aunque se intentará dejar la puerta abierta para implementaciones en versiones más antiguas de Delphi.


Usando clases e interfaces crearemos unas estructuras básicas que nos permitan automatizar los procesos como la creación de clases y objetos, la serialización en Json, el almacenamiento en bases de datos, etc. Todos estos procesos automáticos serán parte fundamental de este framework que basaremos en la utilización de las funcionalidades que nos aporta la Rtti.


Según avancemos en el desarrollo generaremos herramientas de desarrollo que integraremos en el IDE de Delphi, como la generación del código de nuevas clases usando este framework.


También tengo en mente centralizar el uso del framework utilizando DataSnap o un servicio web.


Además intentaremos flexibilizar al máximo el framework (lo que nos implicará más complejidad y por tanto aprenderemos más) para poder utilizarlo de manera inversa usando las estructuras de Bases de Datos de las que ya dispongamos. Ya que en el desarrollo de aplicaciones, se usa mucho crear primero la estructura en la base de datos y después la integración en la aplicación software.


Como he dicho, la primordial misión es la de aprender y no la de obtener un rendimiento óptimo ni de abarcar una casuística muy amplia.


Antes de empezar, e incluso, durante el desarrollo del framework, iré publicando posts que nos sirvan para el desarrollo del framework.

 

Serialización sencilla en JSON

E-mail Imprimir PDF

El desarrollo de DataSnap Rest en Delphi (desde XE si no me equivoco) implica que disponemos de unas librerías que nos permiten la serialización de los objetos en JSON. Además se nos ofrecen varios tipos de clases y utilidades que nos permitirá tener estructuras complejas en JSON y poder serializar manualmente cualquier objeto (dentro de la capacidad de la Rtti).

 

Si no queremos complicarnos la vida, existen funciones que directamente nos hacen el trabajo, se encuentran en la unidad REST.Json, a través de su clase TJson:

 

 TJson = class(TObject)

     ...

  public

    class function ObjectToJsonObject(AObject: TObject; AOptions: TJsonOptions = []): TJSOnObject;

    class function ObjectToJsonString(AObject: TObject; AOptions: TJsonOptions = []): string;

    class function JsonToObject class, constructor>(AJsonObject: TJSOnObject): T; overload;

    class function JsonToObject class, constructor>(AJson: string): T; overload;

    class function Format(AJsonValue: TJsonValue): string;

  end;

 

Estas funciones nos permiten convertir cualquier objeto en un objeto o cadena JSON y viceversa, su uso es muy sencillo, sólo debemos indicar el objeto, clase y/o cadena a convertir.

 

Como ejemplo de su simplicidad:

 

...

type

  TMyClass = class(TObject)

  ...

  public

    procedure ToJsonString: string;

    class function CreateFromJsonString(const AJsonString: string): TMyClass;

  end;

...

procedure TMayClass.ToJsonString: string

begin

  Result := REST.Json.TJson.ObjectToJsonString(Self);

end;


class function TMyClass.CreateFromJsonString(const AJsonString: string): TMyClass;

begin

  Result := REST.Json.TJson.JsonToObject(AJsonString);

end;

...

 

En muchas ocasiones, estas funciones nos serán de utilidad, en otras ya tendremos que adentrarnos más en el funcionamiento de los objetos json de Delphi y generar nosotros mismos la conversión .

 

 


Última actualización el Miércoles, 20 de Mayo de 2015 21:57
 

Instalar VMware Server 2.0.2 sobre Ubuntu 10.04 64bits

E-mail Imprimir PDF

Vamos a ver como instalar el VMware Server 2.0.2 sobre Ubuntu 10.04 64bits.

Última actualización el Domingo, 04 de Julio de 2010 20:33 Leer más...
 


Página 1 de 2