Skip to content

ducoral/mirna

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mirna

Bem-vindo ao projeto mirna.

Um framework escrito em Java para manipulação de arquivos textos do tipo flat-file, com suporte à subitens e extensão de funcionalidade. A estrutura e conteúdo dos arquivos são mapeados em classes configuradas via anotação.

Documentação

Download

<dependencies>
    <dependency>
        <groupId>com.github.ducoral</groupId>
        <artifactId>mirna</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>

Fundamento

O framework trata o arquivo flat-file como um Documento que contém Itens.

Item representa a instância de única ou múltiplas Linhas.

Linha é identificada e contém Campos.

Documento

Documento é uma classe configurada com a anotação @Document. Cada campo dessa classe é entendido como um Item.

Não há limite para a quantidade de Itens configurados. Além disso, o framework suporta a configuração de subitens.

Um Documento pode conter várias Linhas de vários tipos. Porém, um mesmo tipo de Linha não pode estar configurado em mais de um Item em um mesmo Documento.

Segue abaixo a declaração do Documento de exemplo, MyDocument, utilizado para ilustrar as funcionalidades descritas nessa documentação.

MyDocument
@Document
public class MyDocument {

    @Header
    private HeaderLine header;

    @Item
    private List<DetailLine> details;

    @Footer
    private FooterLine footer;

    public MyDocument() { }

    public MyDocument(HeaderLine header, List<DetailLine> details, FooterLine footer) {
        this.header = header;
        this.details = details;
        this.footer = footer;
    }

    // getters and setters
}

MyDocument é composto por um cabeçalho, do tipo HeaderLine, seguido de uma lista de DetailLine e por um rodapé do tipo FooterLine.

Item

Item, em determinado Documento, representa uma ou várias Linhas, e deve estar configurado com as anotações @Header, @Footer ou @Item.

@Header e @Footer configuram Linha que deve ocorrer uma única vez no Documento. A primeira e a última, respectivamente. Porém, é possível mapear Linha com múltiplas ocorrências declarando item com o tipo java.util.List<Linha>.

Linha

Linha representa a linha de texto no arquivo flat-file, é identificada e contém Campos.

A classe que configura determinada Linha deve estar anotada com @Line. Cada Campo da classe pode ser de um dos tipos Java suportados ou de tipo personalizado, conforme extensão de funcionalidade fornecida pelo usuário.

Segue abaixo a definição das classes HeaderLine, DetailLine e FooterLine, correspondentes às Linhas configuradas como Itens de MyDocument.

HeaderLine
@Line(identifier = "H")
public class HeaderLine {

    @FieldStr(position = 1, length = 14)
    private String fieldStr;

    @FieldInt(position = 2, length = 5, fill = '0')
    private int fieldInt;

    public HeaderLine() { }

    public HeaderLine(String fieldStr, int fieldInt) {
        this.fieldStr = fieldStr;
        this.fieldInt = fieldInt;
    }
    
    // getters and setters
}
DetailLine
@Line(identifier = "D")
public class DetailLine {

    @FieldStr(position = 1, length = 4)
    private String fieldStr;

    @FieldInt(position = 2, length = 5, fill = '0')
    private int fieldInt;

    @FieldDec(position = 3, length = 10, fill = '0')
    private BigDecimal fieldDec;

    public DetailLine() { }

    public DetailLine(String fieldStr, int fieldInt, BigDecimal fieldDec) {
        this.fieldStr = fieldStr;
        this.fieldInt = fieldInt;
        this.fieldDec = fieldDec;
    }

    // getters and setters
}
FooterLine
@Line(identifier = "F")
public class FooterLine {

    @FieldDtm(position = 1)
    private Date fieldDtm;

    @FieldCtm(position = 2, length = 11, align = Align.RIGHT, converter = ColorConverter.class)
    private Color fieldCtm;

    public FooterLine() { }

    public FooterLine(Date fieldDtm, Color fieldCtm) {
        this.fieldDtm = fieldDtm;
        this.fieldCtm = fieldCtm;
    }

    // getters and setters
}

Campo

Campo representa uma substring em determinada linha de arquivo texto, com posições inicial e final fixas. O campo de classe que configura um Campo deve estar anotado com @FieldStr, @FieldInt, @FieldDec, @FieldDtm ou @FieldCtm, para o caso de campo com tipo personalizado.

O valor de determinado campo, dentro do trecho fixo reservado na linha texto, poderá estar formatado à esquerda ou à direita, ter espaço vazio preenchido com determinado caractere configurado, etc, conforme configuração das propriedades: position, length, align, fill, format, decimal e separator.

Relatório de configuração

O metodo estático Mirna.report(Class<?>) imprime no console um relatório de configuração de Documento, conforme classe especificada por parâmetro, formatado em texto.

Segue abaixo a saída do relatório de configuração de MyDocument, resultante da execução da instrução Mirna.report(MyDocument.class):

              _
    _ __ ___ (_)_ __ _ __   __ _
   | '_ ` _ \| | '__| '_ \ / _` |
   | | | | | | | |  | | | | (_| |
   |_| |_| |_|_|_|  |_| |_|\__,_|
   :: flat-file parser ::  (v1.0)

=== configuration report ==========

com.github.ducoral.mirna.sample.MyDocument document
    com.github.ducoral.mirna.sample.HeaderLine header
    com.github.ducoral.mirna.sample.DetailLine list<item>
    com.github.ducoral.mirna.sample.FooterLine footer

+----------------------------------------------------------------------------+
| com.github.ducoral.mirna.sample.HeaderLine                                 |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| field      | from | to | len | fill | align | format | dec | sep  | value  |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| identifier |    1 |  1 |   1 | '\0' | LEFT  |        |   0 | '\0' | H      |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| fieldStr   |    2 | 15 |  14 | ' '  | LEFT  |        |   0 | '\0' | String |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| fieldInt   |   16 | 20 |   5 | '0'  | RIGHT |        |   0 | '\0' | int    |
+------------+------+----+-----+------+-------+--------+-----+------+--------+

+--------------------------------------------------------------------------------+
| com.github.ducoral.mirna.sample.DetailLine                                     |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| field      | from | to | len | fill | align | format | dec | sep  | value      |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| identifier |    1 |  1 |   1 | '\0' | LEFT  |        |   0 | '\0' | D          |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| fieldStr   |    2 |  5 |   4 | ' '  | LEFT  |        |   0 | '\0' | String     |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| fieldInt   |    6 | 10 |   5 | '0'  | RIGHT |        |   0 | '\0' | int        |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| fieldDec   |   11 | 20 |  10 | '0'  | RIGHT |        |   2 | '\0' | BigDecimal |
+------------+------+----+-----+------+-------+--------+-----+------+------------+

+-----------------------------------------------------------------------------+
| com.github.ducoral.mirna.sample.FooterLine                                  |
+------------+------+----+-----+------+-------+----------+-----+------+-------+
| field      | from | to | len | fill | align | format   | dec | sep  | value |
+------------+------+----+-----+------+-------+----------+-----+------+-------+
| identifier |    1 |  1 |   1 | '\0' | LEFT  |          |   0 | '\0' | F     |
+------------+------+----+-----+------+-------+----------+-----+------+-------+
| fieldDtm   |    2 |  9 |   8 | '\0' | LEFT  | ddMMyyyy |   0 | '\0' | Date  |
+------------+------+----+-----+------+-------+----------+-----+------+-------+
| fieldCtm   |   10 | 20 |  11 | ' '  | LEFT  |          |   0 | '\0' | Color |
+------------+------+----+-----+------+-------+----------+-----+------+-------+

Configuração de Documento

@Document

A anotação @Document configura determinada classe Java para ser tratada como Documento pelo framework, conforme a classe MyDocument declarada abaixo:

@Document
public class MyDocument {
    // configuração de linhas
}

A partir do Documento MyDocument definido acima, é possível escrever/ler para arquivo ou converter para string da sequinte forma:

public class Main {
    public static void main(String... args) {
        // converting to text
        Mirna.writeDocument(new MyDocument(), new FileWriter("/path/flat-file.txt"));
        // or
        String text = Mirna.toText(new MyDocument());
        
        // converting from text
        MyDocument document = Mirna.readDocument(MyDocument.class, new FileReader("/path/flat-file.txt"));
        // or
        MyDocument document = Mirna.fromText(MyDocument.class, "flat file text");
    }
}

@Header

A anotação @Header configura a linha que deverá ocorrer primeiro e uma única vez no Documento.

O campo de classe de determinado Documento anotado com @Header deve ser uma classe anotada com @Line.

O campo header da classe MyDocument é um exemplo de cabeçalho configurado com @Header.

@Footer

A anotação @Footer configura a linha que deverá ocorrer uma única vez e por último no Documento.

O campo do Documento anotado com @Footer deve ser uma Linha.

O campo footer da classe MyDocument é um exemplo de rodapé configurado com @Footer.

@Item

Configura qualquer outra Linha do Documento que não seja um @Header ou um @Footer, e que poderá ocorrer no documento uma única ou múltiplas vezes, conforme a declaração do campo na classe.

Não há limites para a quantidade de Linhas anotadas com @Item. Para configurar determinada linha para aceitar múltiplas ocorrências, o campo deve ser declarado com lista, java.util.List<Linha>, conforme exemplo abaixo:

public class MyDocument {
    
    @Item(order = 1)
    private MyLineType1 lineType1;
    
    @Item(order = 2)
    private List<MyLineType2> linesType2;
}

O atributo opcional order permite configurar a ordem em que determinada linha deverá ser escrita, em relação às outras linhas do Documento, quando houver mais de uma linha anotada com @Item.

Configurando Linha

@Line

A anotação @Line configura determinada classe para mapear linha do arquivo texto.

Exemplo:

@Line(identifier = "id")
public class MyLine {

   // field declarations
}

O atributo identifier configura a string que será utilizada como identificador de determinada linha no arquivo texto. O valor especificado em identifier é fixado como primeiro campo da linha texto.

Uma classe anotada com @Line deve ter, obrigatoriamente, um construtor default. Segundo a especificação 8.8.9. Default Constructor , um construtor default será gerado pelo compilador automaticamente se não houver nenhum outro declarado na classe implementada. Portanto, nesse caso, deixar a classe sem nenhum construtor está OK também.

Exemplo de classe com construtora default declarada:

@Line(identifier = "id")
public class MyLine {
   
   // default constructor required
   public MyLine() {
   }
  
   // constructor with params
   public MyLine(String param1, Integer param2) {
   }

   // field declarations
}

@FieldStr

A anotação @FieldStr é utilizada para configurar campos string, dando suporte para os tipos Java char, Character e String.

Requer Opcional
position length align fill

@FieldInt

A anotação @FieldInt é utilizada para configurar campos inteiros, dando suporte para os tipos Java byte, short, int, long, Byte, Short, Integer, Long e BigInteger.

Requer Opcional
position length align fill

@FieldDec

A anotação @FieldDec é utilizada para configurar campos decimais, dando suporte para os tipos Java float, double, Float, Double, e BigDecimal.

Requer Opcional
position length align decimals fill separator

@FieldDtm

A anotação @FieldDtm é utilizada para configurar campos de data, dando suporte para o tipo Java java.util.Date.

Requer Opcional
position format

Parâmetros

identifier

O valor especificado em identifier será utilizado pelo framework para identificar o tipo da linha quando estiver no formato texto. O identificador é o primeiro valor no texto da linha.

Por exemplo, se temos um objeto Linha da sequinte forma:

@Line(identifier = "myidvalue")
public class MyLine {

    // field declarations
}

O texto dessa linha sempre começará com o literal myidvalue:

   "myidvalue<field-1><field-2><field-3>..."

Quando o framework efetuar a conversão de texto para objeto, ao identificar que determinada linha começa com o literal myidvalue, ele saberá que deverá ser criada uma instância de MyLine para carregar os campos dessa linha.

O valor de identifier pode ser qualquer string.

Tipo Valor Utilizado por
String qualquer string @Line

position

Configurando posição do campo na Linha.

Ao converter os Campos de determinada Linha para texto, o framework iniciará uma string com o literal configurado em identifier e, para cada campo declarado na Linha, seguindo a ordem crescente do valor configurado em position, a partir da position com valor 1, irá concatenar à direita dessa string o valor do campo convertido para texto, conforme a sua configuração.

Em vez de ter essa configuração, o framework poderia apenas seguir a ordem de cima para baixo em que os campos fossem declarados na classe. Todavia, a especificação do Java não define, ou garante, a ordem em que os campos recuperados de uma classe via reflection são retornados. Dessa forma essa abordagem ficaria dependente da implementação do JDK. A configuração order existe pelo mesmo motivo.

Portanto, idependentemente da ordem em que os campos são declarados em uma Linha, por exemplo:

@Line(identifier = "A")
public class MyLine {

    @FieldStr(position = 3, length = 10)
    private String strF;

    @FieldInt(position = 1, length = 5)
    private Integer intF;

    @FieldDec(position = 2, length = 8)
    private BigDecimal decF;

    public MyLine() { }
    
    public MyLine(String strF, Integer intF, BigDecimal decF) {
        this.strF = strF;
        this.intF = intF;
        this.decF = decF;
    }   

    // getters and setters
}

Ao converter para texto eles serão concatenados conforme a ordem configurada em position, do menor para o maior, da seguinte forma:

    "A<intF_value><decF_value><strF_value>"
     ||           |           | 
     ||           |           +--> position = 3                                          
     ||           +--------------> position = 2
     |+--------------------------> position = 1
     +---------------------------> identifier (position = 0)
Tipo Valor Utilizado por
int 1, 2, ..., Integer.MAX_VALUE @FieldStr @FieldInt @FieldDec @FieldDtm @FieldCtm

length

Um Campo corresponde a um trecho de texto da linha em determinada posição inicial e final, conforme valor configurado em position, e comprimento em length.

length define a largura em caracateres que o campo irá reservar no texto da linha para o valor formatado.

Tipo Valor Utilizado por
int 1, 2, ..., Integer.MAX_VALUE @FieldStr @FieldInt @FieldDec @FieldCtm

align

A propriedade align define se a string resultante da conversão do valor do campo para texto ficará posicionada à esquerda ou à direita no espaço reservado de determinada linha.

Por exemplo, se um campo string com valor "abc", configurado com comprimento 10 e preenchimento '*', será convertido para texto como o seguinte, conforme configuração de alinhamento:

                1234567890
Align.LEFT  -> "abc*******"
Align.RIGHT -> "*******abc"
Tipo Valor Default Utilizado por
com.github.ducoral.Align LEFT, RIGHT RIGHT nos campos numéricos e LEFT nos demais @FieldStr @FieldInt @FieldDec @FieldDtm @FieldCtm

fill

Provavelmente a string resultante da conversão do valor do campo terá comprimento menor que o configurado em length. Nesse caso, o framework irá concatenar o valor definido em fill ao valor do campo até que a string atinja o comprimento determinado.

Tipo Valor Default Utilizado por
char qualquer char ' ' @FieldStr @FieldInt @FieldDec @FieldCtm

format

Define o formato de data para campo com valor do tipo java.util.Date.

Tipo Valor Default Utilizado por
String "dd/MM/yyyy", "ddMMyy", padrão SimpleDateFormat "ddMMyyyy" @FieldDtm

decimal

Define a quantidade de casas decimais aplicada na formatação do valor de determinado campo decimal.

Tipo Valor Default Utilizado por
int 1, 2, ..., mais do que 6 não é possível que precise 2 @FieldDec

separator

Define o char que será utilizado para separar as casas decimais na formatação do valor de determinado campo decimal. O valor '\0' indica que não será utilizado separador.

Tipo Valor Default Utilizado por
char '.', ',', etc. '\0' @FieldDec

order

Define a ordem em que a Linha corrrespondente de determinado item será gerado no arquivo em relação aos demais itens do Documento.

Ao converter determinado Documento em arquivo texto, o framework esreverá primeiro a Linha correspondente do item anotado com @Header, se existir, depois as linhas dos itens anotados com @Item e, por último, a linha do item anotado com @Footer.

Tipo Valor Default Utilizado por
int 1, 2, ..., Integer.MAX_VALUE 0 @Item

Em ação

A conversão de objeto para texto e vice-versa é efetuada através dos métodos estáticos Mirna.toText(), Mirna.writeDocument(), Mirna.fromText() e Mirna.readDocument().

Segue abaixo declaração de instância de MyDocument, configurada com instâncias de HeaderLine, DetailLine e FooterLine para ser utilizada como caso para explicação abaixo dos métodos Mirna.toText() e Mirna.writeDocument().

myDoc
MyDocument myDoc = new MyDocument(
    new HeaderLine("header", 123),
    Arrays.asList(
            new DetailLine("str1", 10, BigDecimal.valueOf(1.23)),
            new DetailLine("str2", 20, BigDecimal.valueOf(4.56)),
            new DetailLine("str3", 30, BigDecimal.valueOf(7.89))),
    new FooterLine(new GregorianCalendar(2020, Calendar.APRIL, 10).getTime(), Color.MAGENTA)
);

Mirna.toText()

O método Mirna.toText() recebe por parâmetro uma instância de Documento e retorna uma string correspondente ao contendo do arquivo texto gerado a partir dos dados do objeto. Para a instância de MyDocument declarada acima na variável myDoc, ao executar o trecho de código abaixo:

System.out.println(Mirna.toText(myDoc));

Seria impresso o seguinte texto no console:

Hheader        00123
Dstr1000100000000123
Dstr2000200000000456
Dstr3000300000000789
F10042020  255:0:255

Mirna.writeDocument()

O método recebe por parâmetro uma instância de Documento, que será convertida para texto, e uma instância de java.io.Writer, em que o texto resultante será escrito.

Para escrever o documento em arquivo, basta atribuir uma instância de java.io.FileWriter ao parâmetro writer.

Para a instância de MyDocument declarada acima na variável myDoc, ao executar o trecho de código abaixo:

Mirna.writeDocument(myDoc, new PrintWriter(System.out));

Seria impresso o seguinte texto no console:

Hheader        00123
Dstr1000100000000123
Dstr2000200000000456
Dstr3000300000000789
F10042020  255:0:255

Mirna.fromText().

O método Mirna.fromText() recebe por parâmetro uma string correspondente ao conteúdo em texto do documento e retorna instância do objeto configurado com os dados carregados.

Por exemplo, se fosse executado o trecho de código abaixo:

String text =
    "Hheader        00123\n" +
    "Dstr1000100000000123\n" +
    "Dstr2000200000000456\n" +
    "Dstr3000300000000789\n" +
    "F10042020  255:0:255\n";

MyDocument myDocFromText = Mirna.fromText(MyDocument.class, text);

A instância de MyDocument resultante atribuída na variável myDocFromText teria a mesma configuração da instância configurada na variável myDoc.

Mirna.readDocument().

O método Mirna.readDocument() recebe por parâmetro uma instância de java.lang.Class, correspondente ao Documento que será recuperado, e uma instância de java.io.Reader, de onde o framework fará a leitura do texto a ser convertido para objeto.

Para efetuar leitura diretamente de arquivo, basta atribuir uma instância de java.io.FileReader ao parâmetro reader.

Por exemplo, se fosse executado o seguinte trecho de código:

String text =
    "Hheader        00123\n" +
    "Dstr1000100000000123\n" +
    "Dstr2000200000000456\n" +
    "Dstr3000300000000789\n" +
    "F10042020  255:0:255\n";

MyDocument myDocFromReader = Mirna.readDocument(MyDocument.class, new StringReader(text));

A instância de MyDocument resultante atribuída na variável myDocFromReader teria a mesma configuração da instância configurada na variável myDoc.

Avançado

mirna permite configurar Linha que contenha outra linha relacionada como subitem. Não há limites na quantidade de subitens para configuração de Linhas.

Subitens

O subitem pode ser uma única instância como poder uma lista de subitens declarando o campo da classe com List, da seguinte forma: List<TipoSubitem> subitens;

Segue abaixo exemplo de Linha que configura subitem anotando determinado campo com @Item:

WithSubItemLine
@Line(identifier = "S")
public class WithSubItemLine {

    @FieldStr(position = 1, length = 15)
    private String fieldStr;

    @FieldInt(position = 2, length = 4)
    private int fieldInt;

    @Item
    private List<DetailLine> details;

    public WithSubItemLine() { }

    public WithSubItemLine(String fieldStr, int fieldInt, List<DetailLine> details) {
        this.fieldStr = fieldStr;
        this.fieldInt = fieldInt;
        this.details = details;
    }

    // getters and setters
}

O campo details, declarado como List<DetailLine>, está anotado com @Item, que é a mesma anotação utilizada para configurar itens no Documento.

O tipo DetailLine é uma Linha, como pode ser observado na declaração abaixo:

Documentos complexos

Documentos complexos podem ser elaborados compondo items que contém subitens.

Segue exemplo Documento complexo declarado como MyComplexDocument:

MyComplexDocument
@Document
public class MyComplexDocument {

    @Header
    private HeaderLine header;

    @Item(order = 1)
    private List<WithSubItemLine> itemsWithDetails;

    @Item(order = 2)
    private List<AnotherLine> anotherLines;

    @Footer
    private FooterLine footer;

    public MyComplexDocument() { }

    public MyComplexDocument(
            HeaderLine header,
            List<WithSubItemLine> itemsWithDetails,
            List<AnotherLine> anotherLines,
            FooterLine footer) {
        this.header = header;
        this.itemsWithDetails = itemsWithDetails;
        this.anotherLines = anotherLines;
        this.footer = footer;
    }

    // getters and setters
}

AnotherLine também contém subitem, como pode ser observado em sua declaração abaixo:

AnotherLine
@Line(identifier = "A")
public class AnotherLine {

    @FieldDtm(position = 1, format = "yyyyMMdd")
    private Date fieldDtm;

    @FieldDec(position = 2, length = 11, separator = '.', decimals = 4)
    private BigDecimal fieldDec;

    @Item
    private ItemLine item;

    public AnotherLine() { }

    public AnotherLine(Date fieldDtm, BigDecimal fieldDec, ItemLine item) {
        this.fieldDtm = fieldDtm;
        this.fieldDec = fieldDec;
        this.item = item;
    }

    // getters and setters
}

O subitem item é também uma Linha, conforme declaração abaixo:

ItemLine
@Line(identifier = "I")
public class ItemLine {

    @FieldStr(position = 1, length = 7, fill = '*')
    String fieldStr;

    @FieldInt(position = 2, length = 3, fill = '0')
    int fieldInt;

    @FieldDec(position = 3, length = 9, fill = '0', decimals = 4, separator = ',')
    BigDecimal fieldDec;

    public ItemLine() { }

    public ItemLine(String fieldStr, int fieldInt, BigDecimal fieldDec) {
        this.fieldStr = fieldStr;
        this.fieldInt = fieldInt;
        this.fieldDec = fieldDec;
    }

    // getters and setters
}

Ao executar o relatório de configuração para a classe MyComplexDocument, Mirna.report(MyComplexDocument.class), seria impresso no console o seguinte texto:

              _
    _ __ ___ (_)_ __ _ __   __ _
   | '_ ` _ \| | '__| '_ \ / _` |
   | | | | | | | |  | | | | (_| |
   |_| |_| |_|_|_|  |_| |_|\__,_|
   :: flat-file parser ::  (v1.0)

=== configuration report ==========

com.github.ducoral.mirna.sample.MyComplexDocument document
    com.github.ducoral.mirna.sample.HeaderLine header
    com.github.ducoral.mirna.sample.WithSubItemLine list<item>
        com.github.ducoral.mirna.sample.DetailLine list<item>
    com.github.ducoral.mirna.sample.AnotherLine list<item>
        com.github.ducoral.mirna.sample.ItemLine item
    com.github.ducoral.mirna.sample.FooterLine footer

+----------------------------------------------------------------------------+
| com.github.ducoral.mirna.sample.HeaderLine                                 |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| field      | from | to | len | fill | align | format | dec | sep  | value  |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| identifier |    1 |  1 |   1 | '\0' | LEFT  |        |   0 | '\0' | H      |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| fieldStr   |    2 | 15 |  14 | ' '  | LEFT  |        |   0 | '\0' | String |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| fieldInt   |   16 | 20 |   5 | '0'  | RIGHT |        |   0 | '\0' | int    |
+------------+------+----+-----+------+-------+--------+-----+------+--------+

+----------------------------------------------------------------------------+
| com.github.ducoral.mirna.sample.WithSubItemLine                            |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| field      | from | to | len | fill | align | format | dec | sep  | value  |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| identifier |    1 |  1 |   1 | '\0' | LEFT  |        |   0 | '\0' | S      |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| fieldStr   |    2 | 16 |  15 | ' '  | LEFT  |        |   0 | '\0' | String |
+------------+------+----+-----+------+-------+--------+-----+------+--------+
| fieldInt   |   17 | 20 |   4 | ' '  | RIGHT |        |   0 | '\0' | int    |
+------------+------+----+-----+------+-------+--------+-----+------+--------+

+--------------------------------------------------------------------------------+
| com.github.ducoral.mirna.sample.DetailLine                                     |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| field      | from | to | len | fill | align | format | dec | sep  | value      |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| identifier |    1 |  1 |   1 | '\0' | LEFT  |        |   0 | '\0' | D          |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| fieldStr   |    2 |  5 |   4 | ' '  | LEFT  |        |   0 | '\0' | String     |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| fieldInt   |    6 | 10 |   5 | '0'  | RIGHT |        |   0 | '\0' | int        |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| fieldDec   |   11 | 20 |  10 | '0'  | RIGHT |        |   2 | '\0' | BigDecimal |
+------------+------+----+-----+------+-------+--------+-----+------+------------+

+----------------------------------------------------------------------------------+
| com.github.ducoral.mirna.sample.AnotherLine                                      |
+------------+------+----+-----+------+-------+----------+-----+------+------------+
| field      | from | to | len | fill | align | format   | dec | sep  | value      |
+------------+------+----+-----+------+-------+----------+-----+------+------------+
| identifier |    1 |  1 |   1 | '\0' | LEFT  |          |   0 | '\0' | A          |
+------------+------+----+-----+------+-------+----------+-----+------+------------+
| fieldDtm   |    2 |  9 |   8 | '\0' | LEFT  | yyyyMMdd |   0 | '\0' | Date       |
+------------+------+----+-----+------+-------+----------+-----+------+------------+
| fieldDec   |   10 | 20 |  11 | ' '  | RIGHT |          |   4 | '.'  | BigDecimal |
+------------+------+----+-----+------+-------+----------+-----+------+------------+

+--------------------------------------------------------------------------------+
| com.github.ducoral.mirna.sample.ItemLine                                       |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| field      | from | to | len | fill | align | format | dec | sep  | value      |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| identifier |    1 |  1 |   1 | '\0' | LEFT  |        |   0 | '\0' | I          |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| fieldStr   |    2 |  8 |   7 | '*'  | LEFT  |        |   0 | '\0' | String     |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| fieldInt   |    9 | 11 |   3 | '0'  | RIGHT |        |   0 | '\0' | int        |
+------------+------+----+-----+------+-------+--------+-----+------+------------+
| fieldDec   |   12 | 20 |   9 | '0'  | RIGHT |        |   4 | ','  | BigDecimal |
+------------+------+----+-----+------+-------+--------+-----+------+------------+

+-----------------------------------------------------------------------------+
| com.github.ducoral.mirna.sample.FooterLine                                  |
+------------+------+----+-----+------+-------+----------+-----+------+-------+
| field      | from | to | len | fill | align | format   | dec | sep  | value |
+------------+------+----+-----+------+-------+----------+-----+------+-------+
| identifier |    1 |  1 |   1 | '\0' | LEFT  |          |   0 | '\0' | F     |
+------------+------+----+-----+------+-------+----------+-----+------+-------+
| fieldDtm   |    2 |  9 |   8 | '\0' | LEFT  | ddMMyyyy |   0 | '\0' | Date  |
+------------+------+----+-----+------+-------+----------+-----+------+-------+
| fieldCtm   |   10 | 20 |  11 | ' '  | RIGHT |          |   0 | '\0' | Color |
+------------+------+----+-----+------+-------+----------+-----+------+-------+

Considerando o exemplo de determinada variável myComplexDoc do tipo MyComplexDocument contendo a instância:

myComplexDoc
MyComplexDocument myComplexDoc = new MyComplexDocument(
        new HeaderLine("header", 123),
        Arrays.asList(
                new WithSubItemLine(
                        "item1", 10, Arrays.asList(
                        new DetailLine("sub1", 10, BigDecimal.valueOf(1.23)),
                        new DetailLine("sub2", 20, BigDecimal.valueOf(4.56)),
                        new DetailLine("sub3", 30, BigDecimal.valueOf(7.89)))),
                new WithSubItemLine(
                        "item2", 20, Arrays.asList(
                        new DetailLine("sub4", 40, BigDecimal.valueOf(1.23)),
                        new DetailLine("sub5", 50, BigDecimal.valueOf(4.56)),
                        new DetailLine("sub6", 60, BigDecimal.valueOf(7.89))))),
        Arrays.asList(
                new AnotherLine(
                        new GregorianCalendar(2020, Calendar.APRIL, 11).getTime(),
                        BigDecimal.valueOf(123.456),
                        new ItemLine("item1", 100, BigDecimal.valueOf(456.789))),
                new AnotherLine(
                        new GregorianCalendar(2020, Calendar.APRIL, 12).getTime(),
                        BigDecimal.valueOf(34.45),
                        new ItemLine("item2", 200, BigDecimal.valueOf(56.78))),
                new AnotherLine(
                        new GregorianCalendar(2020, Calendar.APRIL, 13).getTime(),
                        BigDecimal.valueOf(987.6543),
                        new ItemLine("item3", 300, BigDecimal.valueOf(555.333)))),
        new FooterLine(new GregorianCalendar(2020, Calendar.APRIL, 10).getTime(), Color.MAGENTA));

Ao executar a instrução System.out.println(Mirna.toText(myComplexDoc)), seria impresso o seguinte texto no console:

Hheader        00123
Sitem1            10
Dsub1000100000000123
Dsub2000200000000456
Dsub3000300000000789
Sitem2            20
Dsub4000400000000123
Dsub5000500000000456
Dsub6000600000000789
A20200411   123.4560
Iitem1**1000456,7890
A20200412    34.4500
Iitem2**2000056,7800
A20200413   987.6543
Iitem3**3000555,3330
F10042020  255:0:255

Estendendo a funcionalidade

mirna permite a extensão de funcionalidade através de especilização da interface Converter, que pode ser utilizada na configuração de campo personalizado anotado com @FieldCtm.

Interface Converter

A interface Converter requer que sejam implementados dois métodos: Converter.toText() e Converter.fromText(). O método Converter.toText() deverá retornar string correspondente da conversão para texto do objeto especificado no parâmetro value. O método Converter.fromText(), por sua, deverá retornar instância do objeto personalizado com valores carregados da string especificada no parâmetro text.

Segue abaixo a declaração de ColorConverter, implementação de Converter utilizada na configuração de campo personalizado em FooterLine, que dá suporte a objeto do tipo java.awt.Color:

ColorConverter
import com.github.ducoral.mirna.Converter;

import java.awt.*;

import static java.lang.Integer.*;

public class ColorConverter implements Converter {

    @Override
    public String toText(Object value) {
        Color color = (Color) value;
        return color.getRed() + ":" + color.getGreen() + ":" + color.getBlue();
    }

    @Override
    public Object fromText(String text) {
        String[] rgb = text.split(":");
        return new Color(parseInt(rgb[0]), parseInt(rgb[1]), parseInt(rgb[2]));
    }
} 

@FieldCtm

Dada a implementação de Converter para determinado tipo personalizado, basta especificar a classe correspondente ao atributo converter da anotação @FieldCtm, ao configurar o campo de tipo específico, da forma com foi utilizado no exemplo FooterLine:

@FieldCtm(position = 2, length = 11, align = Align.RIGHT, converter = ColorConverter.class)
private Color fieldCtm;

converter

O atributo converter, da anotação @FieldCtm, requer a instância de java.lang.Class correspondente à implementação de Converter que deverá ser utilizada pelo framework ao efetuar a conversão objeto/texto para o tipo declarado no campo personalizado.

About

A Flat-File Parser, POJO based, library for Java applications

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages