Biblioteca Java de código aberto com filtragem de rastreamento de pilha, análise Silent String e comparação de versões

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 Github

Javadoc online está disponível aqui

Alé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:

  1. Uma String a ser analisada
  2. Uma implementação de Number (Double, Long, Integer, Short ou Byte) para servir como valor padrão se ocorrer algum problema de análise
  3. 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)
  4. 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.

Source: https://habr.com/ru/post/pt480268/


All Articles