{"id":909,"date":"2011-01-10T00:04:02","date_gmt":"2011-01-10T03:04:02","guid":{"rendered":"https:\/\/devkico.itexto.com.br\/?p=909"},"modified":"2011-01-10T00:04:02","modified_gmt":"2011-01-10T03:04:02","slug":"grails-entendendo-as-validacoes-constraints","status":"publish","type":"post","link":"https:\/\/devkico.itexto.com.br\/?p=909","title":{"rendered":"Grails: entendendo as valida\u00e7\u00f5es (constraints)"},"content":{"rendered":"<p><a href=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-604\" style=\"margin: 10px;\" title=\"grails_logo\" src=\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\" alt=\"\" width=\"163\" height=\"43\" \/><\/a>No meu \u00faltimo post falei sobre alguns detalhes poucos conhecidos das buscas por crit\u00e9rios. Agora chegou a hora de expor algumas coisas bem legais sobre as valida\u00e7\u00f5es, aka constraints, oferecidas pelo framework.<\/p>\n<h2>O b\u00e1sico<\/h2>\n<p>As constraints nos permitem definir declarativamente as regras de valida\u00e7\u00e3o que devemos aplicar \u00e0s nossas classes de dom\u00ednio. S\u00e3o muito similares ao projeto &#8220;Hibernate Validator&#8221;. A diferen\u00e7a \u00e9 que ao inv\u00e9s de usarmos anota\u00e7\u00f5es, iremos usar uma DSL interna definida pelo framework. Assim como no caso da busca por crit\u00e9rios, a DSL usada \u00e9 baseada no recurso builder presente na linguagem Groovy.<\/p>\n<p>Para declararmos as regras de valida\u00e7\u00e3o, devemos incluir um bloco est\u00e1tico na nossa classe de dom\u00ednio chamado <em>constraints<\/em>, tal como no exemplo abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\nclass DominioBonito {\r\nString nome\r\nInteger codigo\r\nString email\r\n\r\nstatic constraints = {\r\nnome (nullable:false, blank:false, unique:true)\r\ncodigo(min:1)\r\nemail(email:true)\r\n}\r\n}\r\n\r\n<\/pre>\n<p>A sintaxe \u00e9 muito simples: em cada linha voc\u00ea dever\u00e1 incluir o nome do campo a ser validado, seguido de um par de par\u00eanteses contendo as regras a ser aplicadas. Cada regra recebe um ou mais par\u00e2metros, que variam de acordo com a sua implementa\u00e7\u00e3o. N\u00e3o se assuste com isto, pois estes atributos se tornar\u00e3o familiares a voc\u00ea com o tempo.<\/p>\n<p>Todas as constraints default do Grails podem ser acessadas neste link: <a href=\"http:\/\/grails.org\/doc\/latest\/ref\/Constraints\/Usage.html\" target=\"_blank\">http:\/\/grails.org\/doc\/latest\/ref\/Constraints\/Usage.html<\/a> (salve-o em seus bookmarks para refer\u00eancia, pois \u00e9 uma m\u00e3o na roda)<\/p>\n<p>Agora que o b\u00e1sico j\u00e1 foi dito, podemos ver detalhes menos conhecidos deste recurso.<\/p>\n<h2>Constraints e scaffolding<\/h2>\n<p>Eis um detalhe das constraints que n\u00e3o acho bacana: a sua presen\u00e7a influencia o scaffolding. Caso voc\u00ea queira definir a ordem em que os atributos de suas classes de dom\u00ednio s\u00e3o expostos por este recurso, tudo o que voc\u00ea deve fazer \u00e9 alterar a ordem na qual os atributos s\u00e3o definidos no bloco constraints da sua classe de dom\u00ednio.<\/p>\n<p>H\u00e1 inclusive algumas constraints cujo objetivo \u00e9 justamente definir regras para o scaffolding. S\u00e3o elas:<\/p>\n<p><strong>display <\/strong>(true ou false): define se o campo vai aparecer ou n\u00e3o nas p\u00e1ginas geradas pelo scaffolding<br \/>\n<strong>editable<\/strong> (true ou false): define se o campo ser\u00e1 edit\u00e1vel no scaffolding ou n\u00e3o<br \/>\n<strong>format<\/strong> (string): no caso de datas e n\u00fameros, define qual o formato no qual estes ser\u00e3o expostos, digitados pelo usu\u00e1rio (\u00fatil d+!)<br \/>\n<strong>password<\/strong> (true ou false): se voc\u00ea definir como true, ser\u00e1 exposto um input do tipo password na sua interface gr\u00e1fica<br \/>\n<strong>widget <\/strong>(string): define qual widget dever\u00e1 ser renderizado. Voc\u00ea deve apenas fornecer qual o nome da tag usada, como por exemplo textarea<\/p>\n<p>Dica: evite este recurso. A classe de dom\u00ednio deve ser a parte de neg\u00f3cio da sua aplica\u00e7\u00e3o, n\u00e3o a respons\u00e1vel pela visualiza\u00e7\u00e3o.<\/p>\n<h2>Constraints e GORM<\/h2>\n<p>As constraints tamb\u00e9m influenciam o funcionamento do GORM. No caso da cria\u00e7\u00e3o das tabelas do banco de dados estar sendo executada pelo framework, as constraints s\u00e3o usadas para definir o tamanho dos campos, assim como o fato de aceitarem ou n\u00e3o valores nulos. Como exemplos, posso citar as seguintes constraints:<\/p>\n<p><strong>maxSize:<\/strong> no caso de campos do tipo varchar ou char, define qual o seu tamanho<br \/>\n<strong>nullable:<\/strong> define se o campo pode aceitar valores nulos ou n\u00e3o<br \/>\n<strong>unique:<\/strong> cria um \u00edndice de unicidade para a coluna relacionada<\/p>\n<p>No caso de maxSize, caso n\u00e3o seja incluida, ser\u00e1 usado como valor default de tamanho para campos textuais o padr\u00e3o do SGBD que, normalmente, \u00e9 255 caracteres.<\/p>\n<h2>Constraints customizadas<\/h2>\n<p>Ok, Grails te oferece uma s\u00e9rie de constraints \u00fateis, mas e se voc\u00ea quiser criar uma personalizada? Por exemplo: no cadastro de usu\u00e1rios, ter uma classe de dom\u00ednio na qual seja verificada a igualdade das senhas digitadas. Como voc\u00ea faz isto? Neste caso, voc\u00ea usa a constraint <strong>validator<\/strong>. Veja o exemplo abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\nclass Usuario {\r\n\r\nString nome\r\nString login\r\nString senha1\r\nString senha2\r\n\r\nstatic constraints = {\r\nsenha2(validator: \u00a0{valor, objeto -&gt;\r\nobjeto.properties&#x5B;'senha2'] == valor\r\n})\r\n}\r\n\r\n}\r\n\r\n<\/pre>\n<p>A constraint valiator neste caso recebe como valor uma closure que dever\u00e1 possuir dois par\u00e2metros, obrigat\u00f3riamente nesta ordem: valor, objeto. O primeiro representa o valor a ser validado, e o segundo o objeto a ser verificado que, no caso, \u00e9 a sua inst\u00e2ncia da classse de dom\u00ednio a ser validada. O objeto precisa ser passado como par\u00e2metro porque as constraints s\u00e3o um bloco est\u00e1tico. Caso contr\u00e1rio, n\u00e3o haveria como usar este recurso em um ambiente concorrente como aplica\u00e7\u00f5es web.<\/p>\n<p>Se o valor da constraint \u00e9 true, \u00e9 sinal de que o teste passou. No entanto, esta constraint tamb\u00e9m pode retornar uma string. No caso, esta string representa uma mensagem de erro, que \u00e9 definida nos arquivos de mensagens do Grails, presentes no diret\u00f3rio grails-app\/i18n. Eu poderia reescrever o exemplo acima da seguinte maneira portanto:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\nclass Usuario {\r\n\r\nString nome\r\nString login\r\nString senha1\r\nString senha2\r\n\r\nstatic constraints = {\r\n senha2(validator: \u00a0{valor, objeto -&gt;\r\nif (objeto.properties&#x5B;'senha2'] == valor)\r\nreturn true\r\nelse\r\nreturn &quot;erro.senhas.diferentes&quot;\r\n})\r\n}\r\n\r\n}\r\n\r\n<\/pre>\n<p>E esta mensagem seria exposta na minha camada de visualiza\u00e7\u00e3o tirando proveito do recurso de internacionaliza\u00e7\u00e3o do Grails.<\/p>\n<p>Voc\u00ea tamb\u00e9m pode usar esta constraint passando como par\u00e2metro uma closure que possua um \u00fanico par\u00e2metro, tal como neste exemplo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\nclass Testolina {\r\nInteger valor\r\nstatic constraints = {\r\nvalor(validator: {it % 2 == 0}\r\n}\r\n}\r\n\r\n<\/pre>\n<p>Neste caso, apenas o valor \u00e9 verificado, que dever\u00e1 ser um n\u00famero par.<\/p>\n<h2>Constraints globais e compartilhadas<\/h2>\n<p>Um recurso muito \u00fatil e pouco comentado do Grails \u00e9 a possibilidade de se criar regras de valida\u00e7\u00e3o globais e compartilhadas. Imagine a seguinte situa\u00e7\u00e3o: no seu projeto, por default, todos os atributos devem ser n\u00e3o nulos por default. N\u00e3o \u00e9 chato ter de repetir esta regra em todas as suas classes de dom\u00ednio?<\/p>\n<p>Voc\u00ea inclui uma regra de valida\u00e7\u00e3o global no arquivo grails-app\/conf\/Config.groovy. Basta adicionar um c\u00f3digo similar ao abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ngrails.gorm.default.constraints = {\r\n'*'(nullable:false)\r\n}\r\n\r\n<\/pre>\n<p>O * diz que esta regra se aplica a todos os atributos. Hei! Se eu inclui *, eu tamb\u00e9m posso incluir o nome de um atributo padr\u00e3o em minhas classes, como, por exemplo, &#8220;nome&#8221;? Claro! Veja o exemplo abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ngrails.gorm.default.constraints = {\r\n'nome'(nullable:false, maxSize:128)\r\n}\r\n\r\n<\/pre>\n<p>N\u00e3o \u00e9 legal? Bom: esta \u00e9 uma constraint global, mas o que seria uma constraint compartilhada?<\/p>\n<p>Uma constraint compartilhada \u00e9 uma regra de valida\u00e7\u00e3o que pode ser aplicada em mais de um local nas suas classes de dom\u00ednio. Vamos supor que voc\u00ea tenha v\u00e1rios atributos os quais devam, obrigat\u00f3riamente, possuir no m\u00e1ximo 20 caracteres. Voc\u00ea incluiria no mesmo arquivo um c\u00f3digo similar ao abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ngrails.gorm.default.constraints = {\r\ncompartilhada(maxSize:20)\r\n}\r\n\r\n<\/pre>\n<p>E para us\u00e1-la em suas classes de dom\u00ednio, a declararia tal como abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\nclass Testolina {\r\nString rua\r\nstatic constraints = {\r\nrua (shared: &quot;compartilhada&quot;)\r\n}\r\n}\r\n\r\n<\/pre>\n<p>F\u00e1cil e direto ao ponto. Eu amo isto!<\/p>\n<h2>Como validar constraints<\/h2>\n<p>Ok, voc\u00ea sabe como declarar suas regras de valida\u00e7\u00e3o. Agora precisa saber como us\u00e1-las. No caso do Grails, toda classe de dom\u00ednio possui injetado um m\u00e9todo chamado\u00a0<strong>validate<\/strong>. Caso alguma regra de valida\u00e7\u00e3o falhe, a vari\u00e1vel interna <strong>errors<\/strong> da classe de dom\u00ednio ser\u00e1 alterada incluindo os atributos que est\u00e3o com problema. O c\u00f3digo abaixo ilustra bem a situa\u00e7\u00e3o:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ndominio.validate()\r\nif (dominio.hasErrors()) {\r\n\/\/danou-se! H\u00e1 erros aqui!\r\n}\r\n\r\n<\/pre>\n<p>O que pouca gente sabe \u00e9 que <strong>voc\u00ea pode validar apenas alguns campos ao inv\u00e9s de todos se quiser<\/strong>. Como fazer isto? Simples: passe para o m\u00e9todo validate() uma lista contendo os nomes dos campos a serem validados, tal como no c\u00f3digo abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\ndominio.validate(&#x5B;'nome', 'email'])\r\nif (dominio.hasErrors()) {\r\n\/\/danou-se! ou o atributo nome ou o atributo email est\u00e3o ferrados! Droga!\r\n}\r\n\r\n<\/pre>\n<h3>E este atributo errors hein?<\/h3>\n<p>Como mencionei, toda classe de dom\u00ednio possui injetado um atributo chamado errors. Este na realidade \u00e9 uma inst\u00e2ncia da interface <a href=\"http:\/\/static.springsource.org\/spring\/docs\/3.0.x\/javadoc-api\/org\/springframework\/validation\/Errors.html\" target=\"_blank\">Errors<\/a> do Spring. E sabe o que \u00e9 mais legal nesta interface? Ela tem um m\u00e9todo chamado <strong>reject<\/strong> implementado de varias formas.<\/p>\n<p>Se for necess\u00e1rio incluir uma valida\u00e7\u00e3o que v\u00e1 al\u00e9m das constraints, vamos supor, alguma regra de neg\u00f3cio maluca, voc\u00ea poderia incluir uma valida\u00e7\u00e3o AL\u00c9M das constraints. Vamos supor que por alguma raz\u00e3o sinistra da vida, voc\u00ea precise adicionar uma valida\u00e7\u00e3o que n\u00e3o seja feita por constraints (por exemplo, algo a ser validado ANTES do m\u00e9todo save ser executado). Voc\u00ea poderia escrever um c\u00f3digo como o abaixo:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n\r\nclass DominioMaluco {\r\ndef \u00a0beforeQualquerCoisa= {\r\nif (condicaoMaluca) {\r\nerrors.reject(&quot;codigo.do.erro&quot;)\r\n}\r\n}\r\n}\r\n\r\n<\/pre>\n<p>No caso, o m\u00e9todo reject est\u00e1 adicionando ao atributo errors um novo c\u00f3digo de erro. Aquele mesmo tipo de c\u00f3digo de erro que incluimos nas mensagens de internacionaliza\u00e7\u00e3o padr\u00e3o do Grails.<\/p>\n<p>Sugiro que voc\u00ea d\u00ea uma lida nesta interface. Ela vai te possibilitar ir BEM al\u00e9m da valida\u00e7\u00e3o padr\u00e3o oferecida pelo framework.<\/p>\n<h2>Concluindo<\/h2>\n<p>Neste post vimos algo al\u00e9m do feij\u00e3o com arroz que normalmente encontramos sobre o assunto. Como ficou claro, as constraints possuem uma profundidade muito maior que a esperada.<\/p>\n<p>Minha sugest\u00e3o para quem estiver come\u00e7ando no assunto \u00e9 a seguinte: tenha nos seus bookmarks o link que expus acima contendo as constraints default do Grails. Estando habituado com estas, estude seu c\u00f3digo fonte (\u00e9 surpreendentemente simples).<\/p>\n<p>Tendo feito isto, parta para as constraints customizadas e, em seguida, caso alguma coisa <strong>muito<\/strong> sinistra aconte\u00e7a, ai sim use e abuse da API de valida\u00e7\u00e3o do Spring, que \u00e9 a base em cima da qual as constraints s\u00e3o constru\u00eddas.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>No meu \u00faltimo post falei sobre alguns detalhes poucos conhecidos das buscas por crit\u00e9rios. Agora chegou a hora de expor algumas coisas bem legais sobre as valida\u00e7\u00f5es, aka constraints, oferecidas pelo framework. O b\u00e1sico As constraints nos permitem definir declarativamente as regras de valida\u00e7\u00e3o que devemos aplicar \u00e0s nossas classes de dom\u00ednio. S\u00e3o muito similares [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-gradient":""}},"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3,30],"tags":[],"class_list":["post-909","post","type-post","status-publish","format-standard","hentry","category-grails","category-grails-guia-rapido-e-indireto"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.8 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Grails: entendendo as valida\u00e7\u00f5es (constraints) - \/dev\/Kico<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/devkico.itexto.com.br\/?p=909\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Grails: entendendo as valida\u00e7\u00f5es (constraints) - \/dev\/Kico\" \/>\n<meta property=\"og:description\" content=\"No meu \u00faltimo post falei sobre alguns detalhes poucos conhecidos das buscas por crit\u00e9rios. Agora chegou a hora de expor algumas coisas bem legais sobre as valida\u00e7\u00f5es, aka constraints, oferecidas pelo framework. O b\u00e1sico As constraints nos permitem definir declarativamente as regras de valida\u00e7\u00e3o que devemos aplicar \u00e0s nossas classes de dom\u00ednio. S\u00e3o muito similares [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/devkico.itexto.com.br\/?p=909\" \/>\n<meta property=\"og:site_name\" content=\"\/dev\/Kico\" \/>\n<meta property=\"article:published_time\" content=\"2011-01-10T03:04:02+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.itexto.net\/devkico\/wp-content\/uploads\/2010\/02\/grails_logo.png\" \/>\n<meta name=\"author\" content=\"Kico (Henrique Lobo Weissmann)\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@loboweissmann\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kico (Henrique Lobo Weissmann)\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. tempo de leitura\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=909\",\"url\":\"https:\/\/devkico.itexto.com.br\/?p=909\",\"name\":\"Grails: entendendo as valida\u00e7\u00f5es (constraints) - \/dev\/Kico\",\"isPartOf\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=909#primaryimage\"},\"image\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=909#primaryimage\"},\"thumbnailUrl\":\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\",\"datePublished\":\"2011-01-10T03:04:02+00:00\",\"dateModified\":\"2011-01-10T03:04:02+00:00\",\"author\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7\"},\"breadcrumb\":{\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=909#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/devkico.itexto.com.br\/?p=909\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=909#primaryimage\",\"url\":\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\",\"contentUrl\":\"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png\",\"width\":\"163\",\"height\":\"43\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/devkico.itexto.com.br\/?p=909#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/devkico.itexto.com.br\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Grails: entendendo as valida\u00e7\u00f5es (constraints)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/devkico.itexto.com.br\/#website\",\"url\":\"https:\/\/devkico.itexto.com.br\/\",\"name\":\"\/dev\/Kico\",\"description\":\"Desenvolvendo software\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/devkico.itexto.com.br\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7\",\"name\":\"Kico (Henrique Lobo Weissmann)\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g\",\"caption\":\"Kico (Henrique Lobo Weissmann)\"},\"sameAs\":[\"https:\/\/x.com\/loboweissmann\"],\"url\":\"https:\/\/devkico.itexto.com.br\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Grails: entendendo as valida\u00e7\u00f5es (constraints) - \/dev\/Kico","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/devkico.itexto.com.br\/?p=909","og_locale":"pt_BR","og_type":"article","og_title":"Grails: entendendo as valida\u00e7\u00f5es (constraints) - \/dev\/Kico","og_description":"No meu \u00faltimo post falei sobre alguns detalhes poucos conhecidos das buscas por crit\u00e9rios. Agora chegou a hora de expor algumas coisas bem legais sobre as valida\u00e7\u00f5es, aka constraints, oferecidas pelo framework. O b\u00e1sico As constraints nos permitem definir declarativamente as regras de valida\u00e7\u00e3o que devemos aplicar \u00e0s nossas classes de dom\u00ednio. S\u00e3o muito similares [&hellip;]","og_url":"https:\/\/devkico.itexto.com.br\/?p=909","og_site_name":"\/dev\/Kico","article_published_time":"2011-01-10T03:04:02+00:00","og_image":[{"url":"http:\/\/www.itexto.net\/devkico\/wp-content\/uploads\/2010\/02\/grails_logo.png"}],"author":"Kico (Henrique Lobo Weissmann)","twitter_card":"summary_large_image","twitter_creator":"@loboweissmann","twitter_misc":{"Escrito por":"Kico (Henrique Lobo Weissmann)","Est. tempo de leitura":"8 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/devkico.itexto.com.br\/?p=909","url":"https:\/\/devkico.itexto.com.br\/?p=909","name":"Grails: entendendo as valida\u00e7\u00f5es (constraints) - \/dev\/Kico","isPartOf":{"@id":"https:\/\/devkico.itexto.com.br\/#website"},"primaryImageOfPage":{"@id":"https:\/\/devkico.itexto.com.br\/?p=909#primaryimage"},"image":{"@id":"https:\/\/devkico.itexto.com.br\/?p=909#primaryimage"},"thumbnailUrl":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png","datePublished":"2011-01-10T03:04:02+00:00","dateModified":"2011-01-10T03:04:02+00:00","author":{"@id":"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7"},"breadcrumb":{"@id":"https:\/\/devkico.itexto.com.br\/?p=909#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/devkico.itexto.com.br\/?p=909"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/devkico.itexto.com.br\/?p=909#primaryimage","url":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png","contentUrl":"https:\/\/devkico.itexto.com.br\/wp-content\/uploads\/2010\/02\/grails_logo.png","width":"163","height":"43"},{"@type":"BreadcrumbList","@id":"https:\/\/devkico.itexto.com.br\/?p=909#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/devkico.itexto.com.br\/"},{"@type":"ListItem","position":2,"name":"Grails: entendendo as valida\u00e7\u00f5es (constraints)"}]},{"@type":"WebSite","@id":"https:\/\/devkico.itexto.com.br\/#website","url":"https:\/\/devkico.itexto.com.br\/","name":"\/dev\/Kico","description":"Desenvolvendo software","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/devkico.itexto.com.br\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"pt-BR"},{"@type":"Person","@id":"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/502ab8892631bb005d6da2269fe5a3a7","name":"Kico (Henrique Lobo Weissmann)","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/devkico.itexto.com.br\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dd6973d86a689bc63122b2e603f25be3?s=96&d=mm&r=g","caption":"Kico (Henrique Lobo Weissmann)"},"sameAs":["https:\/\/x.com\/loboweissmann"],"url":"https:\/\/devkico.itexto.com.br\/?author=1"}]}},"jetpack_featured_media_url":"","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts\/909"}],"collection":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=909"}],"version-history":[{"count":2,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts\/909\/revisions"}],"predecessor-version":[{"id":911,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=\/wp\/v2\/posts\/909\/revisions\/911"}],"wp:attachment":[{"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=909"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=909"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devkico.itexto.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=909"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}