Durante algum tempo em trabalhos diferentes, deparei-me com vários utilitários que não consegui encontrar disponíveis no momento. E vi que precisava deles várias vezes sem parar. Então, escrevi minha própria pequena biblioteca que achei muito útil. Acabei de publicar como uma biblioteca java de código aberto.
Aqui está o link do GithubJavadoc online está disponível aquiAlém disso, esta biblioteca está disponível no Maven Central. Aqui estão os artefatos do Maven (a versão 1.5.0.8 é a mais recente no momento da redação deste artigo, mas pode ser alterada no futuro. Para verificar a versão mais recente, procure o artefato "MgntUtils" em
http: //search.maven. org / ):
<dependency> <groupId>com.github.michaelgantman</groupId> <artifactId>MgntUtils</artifactId> <version>1.5.0.8</version> </dependency> <dependency> <groupId>com.github.michaelgantman</groupId> <artifactId>MgntUtils</artifactId> <version>1.5.0.8</version> <classifier>javadoc</classifier> </dependency> <dependency> <groupId>com.github.michaelgantman</groupId> <artifactId>MgntUtils</artifactId> <version>1.5.0.8</version> <classifier>sources</classifier> </dependency>
Abaixo está apenas uma breve explicação do que está lá. A biblioteca vem com um JavaDoc bem escrito (espero) com uma descrição detalhada. Então, aqui está a lista de recursos:
Filtro de ruído Stacktrace
Na minha experiência, esse recurso foi o mais genérico e útil para mim. O Stacktrace é um salva-vidas ao depurar ou tentar descobrir o que deu errado no seu aplicativo. No entanto, ao trabalhar com logs no lado do servidor, você pode encontrar um enorme stacktrace que contém a cauda inútil mais longa de várias estruturas e pacotes relacionados ao Application Server. E em algum lugar nesta pilha, existem várias linhas de um rastreio relevante e elas podem estar em diferentes segmentos separados por informações inúteis. Torna-se um pesadelo procurar um material relevante. Aqui está um link que descreve o mesmo problema com exemplos da vida real (não para os fracos de coração)
https://dzone.com/articles/filtering-stack-trace-hell . Portanto, na minha biblioteca, existe uma classe chamada
TextUtils e possui o método
getStacktrace () com várias assinaturas sobrecarregadas. É preciso uma instância Throwable e permite definir um prefixo de pacote relevante.
Além disso, o mesmo utilitário (a partir da versão 1.5.0.3) possui o método
getStacktrace () que utiliza a interface CharSequence em vez de Throwable e, portanto, permite filtrar e reduzir o stacktrace armazenado como uma string da mesma maneira que um stacktrace extraído de Throwable. Portanto, essencialmente os rastreamentos de pilha podem ser filtrados "on the fly" no tempo de execução ou posteriormente de qualquer fonte de texto, como um log. (Apenas para esclarecer - o utilitário não suporta a análise e modificação de todo o arquivo de log. Ele suporta a filtragem de apenas um rastreamento de pilha que é passado como uma String. Portanto, se alguém quiser filtrar exceções no arquivo de log, precisará analisá-lo. e extraia o (s) rastreamento (s) de pilha como seqüências de caracteres separadas e, em seguida, pode usar esse utilitário para filtrar cada rastreamento de pilha individual).
Aqui está um exemplo de uso. Digamos que a empresa esteja sempre em pacotes que começam com "com.plain. *". Portanto, você define esse prefixo e faz isso
logger.info(TextUtils.getStacktrace(e,true,"com.plain."));
isso filtrará de maneira muito inteligente todas as partes inúteis do rastreamento, deixando um rastreamento de pilha muito conciso. Além disso, achei muito conveniente predefinir o prefixo e usar o método de conveniência
TextUtils.getStacktrace(e);
Isso fará o mesmo. Para predefinir o prefixo, use o método
setRelevantPackage("com.plain.");
Se você desejar predefinir esse valor por configuração, a partir da versão da biblioteca 1.1.0.1, poderá definir a variável de ambiente "
MGNT_RELEVANT_PACKAGE " ou a propriedade do sistema "
mgnt.relevant.package " para o valor "
com.plain "
. será definido com esse valor sem você chamar o método
TextUtils.setRelevantPackage ("com.plain."); explicitamente no seu código. Observe que o valor da propriedade System terá precedência sobre a variável de ambiente se ambas fossem definidas. Apenas um lembrete de que, com a propriedade System, você pode adicioná-lo na linha de comando usando o sinalizador -D:
"-Dmgnt.relevant.package = com.plain."
Além disso, se você usar uma versão anterior à 1.1.0.1 desta biblioteca ou não quiser usar a variável de ambiente ou a propriedade do sistema mencionada acima e estiver usando o ambiente Spring, poderá predefinir o prefixo adicionando o seguinte segmento à sua configuração Spring:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetClass" value="com.mgnt.utils.TextUtils"/> <property name="targetMethod" value="setRelevantPackage"/> <property name="arguments" value="com.plain."/> </bean>
Javadoc explica tudo em detalhes. Mas aqui está um pequeno teaser: você obterá o seguinte stacktrace:
at com.plain.BookService.listBooks() at com.plain.BookService$$FastClassByCGLIB$$e7645040.invoke() at net.sf.cglib.proxy.MethodProxy.invoke() ... at com.plain.LoggingAspect.logging() at sun.reflect.NativeMethodAccessorImpl.invoke0() ... at com.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks() at com.plain.web.BookController.listBooks()
em vez de
at com.plain.BookService.listBooks() at com.plain.BookService$$FastClassByCGLIB$$e7645040.invoke() at net.sf.cglib.proxy.MethodProxy.invoke() at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed() at com.plain.LoggingAspect.logging() at sun.reflect.NativeMethodAccessorImpl.invoke0() at sun.reflect.NativeMethodAccessorImpl.invoke() at sun.reflect.DelegatingMethodAccessorImpl.invoke() at java.lang.reflect.Method.invoke() at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs() at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod() at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.aop.interceptor.AbstractTraceInterceptor.invoke() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.transaction.interceptor.TransactionInterceptor.invoke() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke() at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept() at com.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks() at com.plain.web.BookController.listBooks()
Silent String analisando em Inteiro, Longo, etc
A mesma classe
TextUtils fornece métodos para analisar String silenciosamente (sem exceção, nunca sendo lançada) em tipos de Duplo, Longo, Inteiro, Curto e Byte. Os métodos são chamados
parseStringToLong () parseStringToInteger () etc. Todos eles recebem 4 argumentos:
- Uma String a ser analisada
- Uma implementação de Number (Double, Long, Integer, Short ou Byte) para servir como valor padrão se ocorrer algum problema de análise
- Uma String a ser impressa como uma mensagem de erro no log se o primeiro argumento for nulo (pode ser nulo e, em seguida, nenhum erro é impresso)
- Uma String a ser impressa como uma mensagem de erro se NumberFormatException ocorreu (pode ser nulo e, em seguida, nenhum erro é impresso)
Analisando String para Intervalo de Tempo
Na mesma classe
TextUtils , existe um método
parseStringToTimeInterval (valor da String) . Esse método analisa uma sequência que espera manter algum valor de intervalo de tempo - um valor numérico com sufixo opcional da unidade de tempo. Por exemplo, a sequência "38s" será analisada como 38 segundos, "24m" - 24 minutos "4h" - 4 horas, "3d" - 3 dias e "45" como 45 milissegundos. Os sufixos suportados são "
s " por segundos, "
m " por minutos, "
h " por horas e "
d " por dias. Considera-se que a sequência sem sufixo contém um valor em milissegundos. Sufixos não diferenciam maiúsculas de minúsculas. Se a String fornecida contiver um sufixo não suportado ou manter um valor numérico negativo ou zero ou manter um valor não numérico - IllegalArgumentException será lançada. Este método retorna a classe TimeInterval - uma classe também definida nesta biblioteca. Essencialmente, ele possui duas propriedades com getters e setters relevantes: long "value" e java.util.concurrent.TimeUnit. Mas, além de getters e setters, essa classe possui métodos
toMillis () ,
toSeconds () ,
toMinutes () ,
toHours () toDays () . Esses métodos retornam um valor longo na escala de tempo especificada (da mesma maneira que os métodos correspondentes na classe
java.util.concurrent.TimeUnit )
Esse método pode ser muito útil para analisar propriedades de intervalo de tempo, como tempos limite ou períodos de espera dos arquivos de configuração. Elimina cálculos desnecessários de diferentes escalas de tempo para milissegundos e para frente e para trás. Considere que você possui uma propriedade
methodInvokingInterval que precisa definir por 5 dias. Portanto, para definir o valor em milissegundos, você precisará calcular que 5 dias são 432000000 milissegundos (obviamente, não é uma tarefa impossível, mas irritante e propensa a erros) e qualquer outra pessoa que visualizar o valor 432000000 precisará calculá-lo de volta para 5 dias que é frustrante. Mas, usando esse método, você terá um valor de propriedade definido como "5d" e invocará o código
long milliseconds = TextUtils.parsingStringToTimeInterval("5d").toMillis();
resolverá seu problema de conversão. Obviamente, esse não é um recurso excessivamente complexo, mas pode adicionar simplicidade e clareza nos arquivos de configuração e salvar algumas frustrações e erros de cálculo "estúpidos" em erros de milissegundos.
Compare Versões
Este utilitário permite converter String em versão e vice-versa e comparar versões e intervalos de versões corretamente. Frequentemente, se você precisar comparar versões, basta comparar Strings. Então, digamos que a versão "1.5.3" será maior que a versão "1.3.1". No entanto, se você comparar as Strings "1.4.2" e "1.12.3", a String "1.4.2" será erroneamente maior. Portanto, este utilitário cuida de um problema desse tipo e, além disso, apresenta a classe VersionRange e permite operações nos intervalos de versão. (Consulte os métodos
compareVersions na classe
TextUtils e na classe
VersionRange )
Conversor Unicode de cadeia
A classe
StringUnicodeEncoderDecoder possui métodos que podem converter uma String (em qualquer idioma) em uma sequência de caracteres Unicode e vice-versa. Por exemplo, uma string "Hello World" será convertida em
"\ u0048 \ u0065 \ u006c \ u006c \ u006f \ u0020 \ u0057 \ u006f \ u0072 \ u006c \ u0064"
e pode ser restaurado de volta.
Gerenciamento do ciclo de vida (fábricas de instanciação automática)
Esse recurso é um pacote que contém algumas pequenas infraestruturas que simplificam e automatizam o trabalho com Fábricas que fornecem implementações concretas de uma Interface. O pacote contém apenas 2 classes:
BaseEntityFactory e
BaseEntity . Resumindo, o que essa infraestrutura faz é que, se você criar uma fábrica que estende
BaseEntityFactory e alguma Interface com todas as suas implementações concretas estendendo
BaseEntity , cada uma das instâncias de classe de classe de implementação concreta será automaticamente inserida em sua fábrica. Você não precisará se preocupar com como e quando preencher sua fábrica. A infraestrutura fará isso por você quando o construtor de sua classe de implementação concreta for chamado. Portanto, tudo o que você precisará fazer é criar qualquer número de classes de implementação concretas e garantir que cada construtor seja chamado. Depois disso, você pode usar sua fábrica para obter qualquer uma das suas classes de implementação concretas em qualquer lugar do seu código. Esta é uma breve explicação. Existem mais alguns detalhes, mas não tantos. Para uma descrição detalhada deste pacote, consulte a API Javadoc da descrição do pacote
com.mgnt.lifecycle.management . Além disso, o código-fonte contém o pacote com.mgnt.lifecycle.management.example que contém um exemplo de código detalhado e bem comentado sobre como usar esse recurso.
Quanto ao uso prático, achei muito útil para o framework Spring. Lembre-se de que o Spring instancia todos os seus grãos definidos durante sua inicialização. Portanto, dentro do contexto do Spring, se simplesmente declarássemos nossas implementações concretas como beans Spring, o Spring as instanciaria para nós, inicializando sua fábrica automaticamente. Isso pode ser muito conveniente. Imagine que você tem algum bean que possui uma propriedade do tipo de interface definida pelo usuário que possui várias implementações, mas qual implementação real seria necessária é determinada em tempo de execução. Portanto, nesse momento, você pode usar o método
getInstance (java.lang.String) da sua fábrica para acessar a implementação necessária. Isso permitirá que você não injete TODAS as suas instanciações concretas no seu bean e não precisará usar o Spring
Bean Factory para acessar um bean definido pelo Spring, pois isso violaria a não intrusão do Spring (o que significa que você pode escrever componentes que não dependem de Primavera). Além disso, se em algum estágio posterior você precisar adicionar implementações mais concretas, tudo o que você precisará fazer é adicionar suas classes de implementação ao seu código e declará-las como Spring beans. O resto será feito pela Spring e essa infraestrutura!
Utilitários de arquivo
Este utilitário permite ler um arquivo como uma String com ou sem especificar o conjunto de caracteres ou apenas lê-lo como uma matriz de bytes. Este utilitário usa o pacote nio e os buffers para obter um desempenho mais rápido. O tamanho máximo do arquivo para este utilitário é 2G.
Utilitário de tempo
Este é apenas um método de conveniência único que fornece a mesma funcionalidade que Thread.sleep (), mas é silencioso. Ou seja, "engole" IterruptedException. Além disso, são necessários 2 argumentos: hora de dormir e unidade de medida. Então, ao invés de
try { Thread.sleep(2000); } catch (InterruptedException ie) { }
Você pode simplesmente escrever:
TimeUtils.sleepFor(2, TimeUnit.SECONDS);
Eu achei fofo
Então é isso. Sinta-se livre para baixar esta biblioteca. Ele vem com a licença MIT - uma das licenças mais permissivas que conheço. O código fonte, o Javadoc e a versão binária estão disponíveis no link acima. O código foi compilado pelo JDK 8, mas não possui recursos da versão 8. Ele deve funcionar com o java 7 definitivamente, eu suspeito que ele funcione com o java 6 e até 5, mas não o testei com essas versões. Sinta-se à vontade para usá-lo como achar melhor, conte para outras pessoas, se quiser, e me mande uma nota para michael_gantman@yahoo.com, se você tiver algum comentário.