domingo, 4 de setembro de 2011

JSON e Generics - Serializando Objetos


Desta vez vou demonstrar duas novas tecnologias que estão sendo muito melhoradas no Delphi desde a versão 2009 até a ultima versão o Delphi XE. Generics é uma forma de poder

...passar parâmetro de tipos para classes e métodos, possibilitando assim reutilização de código, por exemplo e, JSON (JavaScript Object Notation) é uma forma de troca de dados entre aplicações, semelhante ao XML, porém com uma sintaxe bem mais simples e leve. O Delphi XE, como algumas versões anteriores, dá suporte a implementação usando JSON, e em nosso exemplo vamos criar um método totalmente genêrico que recebe um objeto e um tipo e usaremos o JSON para formatar este objeto e gravar no disco usando a nova classe de IO (input/output) do Delphi, e um método de leitura deste arquivo no formato JSON para retornar o mesmo a um Objeto, novamente passando o tipo do objeto e o caminho onde se encontra o arquivo.

Primeiro vamos criar uma nova classe do tipo TPessoa:

type
  TPessoa = class
  private
    { Private declarations }
    FPessIden: Integer;
    FPessNome: string;

  public
    { Published declarations }
    property PessIden: Integer read FPessIden write FPessIden;
    property PessNome: string read FPessNome write FPessNome;

  end;

Para conseguirmos desenvolver nossos métodos, temos antes que adicionar ao uses as unit’s citadas abaixo. Acima de cada unit tem a descrição de sua função no projeto:

uses
  SysUtils,

  { Unit que contém os novos métodos de I/O }
  IOUtils,

  { Unit's necessárioas para usar JSON }
  DBXJSONReflect, DBXJSON,

  { Unit necessária para usar Generic }
  Generics.Collections;

Agora vamos criar nossa classe que irá conter os métos necessários para carregar e salvar os dados no disco. O class antes da function indica que estes métodos serão estáticos, não sendo necessário instânciar a classe TJSONTools para usar estes métodos, e a descrição T : class, indica que este método recebe um tipo e que a variável obj passada por parâmetro é deste tipo e, na outra função que ela retorna o tipo especificado.

type
  TJSONTools = class
    public
    { Public declarations }
    class function saveFileJSON(obj: T; const filePath: string): Boolean;
    class function loadFileJSON(const filePath: string): T;
  end;

Agora nosso método que irá gravar no disco o objeto da classe descrita acima.:

class function TJSONTools.saveFileJSON(obj: T; const filePath: string): Boolean;
var
  Marshal: TJSONMarshal;

begin
  Marshal := TJSONMarshal.Create(TJSONConverter.Create());
  try
    try
      TFile.WriteAllText(filePath, (Marshal.Marshal(obj) as TObject).ToString);

      Result := True;
    except
      Result := False;
    end;
  finally
    FreeAndNil(Marshal);
  end;
end;

Agora o método responsável por ler o arquivo e carregar novamente os dados para um objeto:

class function TJSONTools.loadFileJSON(const filePath: string): T;
var
  Unmarshal: TJSONUnMarshal;
  obj: TJSONObject;

begin
  Unmarshal := TJSONUnMarshal.Create();
  try
    try
      if not(FileExists(filePath)) then
        Exit(nil);

      obj := TJSONObject.ParseJSONValue(
        TEncoding.ASCII.GetBytes(TFile.ReadAllText(filePath)),
        0) as TJSONObject;

      Result := T(Unmarshal.Unmarshal(obj));
    except
      Exit(nil);
    end;
  finally
    FreeAndNil(Unmarshal);
  end;
end;

Agora uma forma de poder usar nossas classes:

var
  objPessoa: TPessoa;

begin
  objPessoa:= TPessoa.Create();
  objPessoa.PessIden := 1;
  objPessoa.PessNome := 'Active Delphi';

  if (TJSONTools.saveFileJSON&ltTPessoa&gt(objPessoa, 'C:\pessoa.txt')) then
    ShowMessage('Criou o arquivo no caminho: ' + #13 + ' C:\pessoa.txt');

  objPessoa := TJSONTools.loadFileJSON&ltTPessoa&lt('C:\pessoa.txt');
  if (Assigned(objPessoa)) then
  begin
    ShowMessage(
      'PessIden: ' + IntToStr(objPessoa.PessIden) + #13 +
      'PessNome: ' + objPessoa.PessNome
    );
  end
  else
    ShowMessage('Não foi possivel des-serializar o objeto');
end;

Este foi apenas um exemplo didático usando JSON e Generics no Delphi. Estes métodos ainda podem ser refatorados e até criado validações para tratar possíveis erros de parâmetros, que podem ser identificados criando testes unitários sobres estes métodos.

Obrigado pela leitura e até a próxima!

Clique aqui para fazer o download do exemplo, feito com Delphi XE

2 comentários:

  1. Finalmente uma dica prática sobre o assunto! Graças a este post desatolei por aqui.

    Sucesso!

    ResponderExcluir
  2. Parabens pelo artigo, funcionou mas alterando um detalhe.
    Não consegui fazer funcionar usando a funcao saveFileJSON usando o tipo T para obj. eu tive que colocar TPessoa no lugar (em loadFileJSON também). Pois o Delphi fala que o identificador T não foi declarado.

    ResponderExcluir