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.
- Fundamento | Documento | Item | Linha | Campo
- Configurando Documento
|
@Document
|@Header
|@Footer
|@Item
- Configurando Linha
|
@Line
|@FieldStr
|@FieldInt
|@FieldDec
|@FieldDtm
- Parâmetros
|
identifier
|position
|length
|align
|fill
|format
|decimal
|separator
|order
- Em ação
|
Mirna.toText()
|Mirna.writeDocument()
|Mirna.fromText()
|Mirna.readDocument()
- Estendendo a funcionalidade
|
Converter
|@FieldCtm
|converter
- Avançado | Subitens | Documentos complexos
<dependencies>
<dependency>
<groupId>com.github.ducoral</groupId>
<artifactId>mirna</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
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 é 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.
@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, 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 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.
@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
}
@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
}
@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 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.
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 |
+------------+------+----+-----+------+-------+----------+-----+------+-------+
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");
}
}
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.
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.
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
.
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
}
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 |
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 |
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 |
A anotação @FieldDtm
é utilizada para configurar campos de data, dando
suporte para o tipo Java java.util.Date
.
Requer | Opcional |
---|---|
position |
format |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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()
.
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)
);
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
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âmetrowriter
.
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
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.
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âmetroreader
.
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.
mirna permite configurar Linha que contenha outra linha relacionada como subitem. Não há limites na quantidade de subitens para configuração de Linhas.
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:
@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 podem ser elaborados compondo items que contém subitens.
Segue exemplo Documento complexo declarado como 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:
@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:
@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:
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
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
.
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
:
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]));
}
}
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;
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.