{"action":"created","comment":{"url":"https://api.github.com/repos/terasolunaorg/guideline/pulls/comments/67373890","id":67373890,"diff_hunk":"@@ -2678,6 +2678,362 @@ Bean Validationは標準で用意されているチェックルール以外に\n     Hibernate Validatorでは、OR条件を実現するための\\ ``@ConstraintComposition``\\ アノテーションが用意されている。\n     詳細は、\\ `Hibernate Validatorのドキュメント <http://docs.jboss.org/hibernate/validator/5.2/reference/en-US/html/ch11.html#section-boolean-constraint-composition>`_\\ を参照されたい。\n \n+\n+|\n+\n+.. _Validation_for_string_object_in_collection:\n+\n+コレクション型のStringに対する入力チェック\n+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n+\n+複数選択可能な画面項目（チェックボックスや複数選択ドロップダウンなど）に対応した\\ ``@ExistInCodeList``\\ アノテーションの実装例を示す。\n+\n+ここでは、Controller及びJSPの実装で特別な実装が必要ない2つの実装例を紹介する。\n+\n+* :ref:`Validation_exist_in_codelist_converter`\\ \n+* :ref:`Validation_exist_in_codelist_jdk8`\\ \n+\n+\n+.. _Validation_exist_in_codelist_converter:\n+\n+Springの型変換(Converter + ConversionService)による実装\n+\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n+\n+`Springが提供している型変換の仕組み <http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#core-convert>`_\n+を利用して実装を行う。\n+\n+主な手順は以下の通り。\n+\n+* チェック対象に\\ ``@ExistInCodeList``\\ アノテーションを設定する。\n+\n+* 変換用インタフェースであるConverterクラスを実装したクラスを作成する。\n+\n+* ConversionServiceFactoryBeanを使用し、Springに作成したConverterを登録する。\n+\n+実装例\n+\n+* フォームクラス\n+\n+  .. code-block:: java\n+\n+    package com.example.common.validation;\n+\n+    import java.util.List;\n+\n+    import javax.validation.Valid;\n+    import javax.validation.constraints.NotNull;\n+\n+    public class SampleForm {\n+        @Valid // (1)\n+        @NotNull // (2)\n+        private List<Role> roles;\n+\n+        public List<Role> getRoles() {\n+            return roles;\n+        }\n+\n+        public void setRoles(List<Role> roles) {\n+            this.roles = roles;\n+        }\n+    }\n+\n+\n+  .. tabularcolumns:: |p{0.10\\linewidth}|p{0.90\\linewidth}|\n+  .. list-table::\n+     :header-rows: 1\n+     :widths: 10 90\n+\n+     * - 項番\n+       - 説明\n+     * - | (1)\n+       - | BeanのBean Validationを有効にするために、\\ ``javax.validation.Valid``\\ アノテーションを付与する。\n+     * - | (2)\n+       - | 要素の入力を必須とする。\n+\n+|\n+\n+* JavaBeanクラス\n+\n+  .. code-block:: java\n+\n+    package com.example.common.validation;\n+\n+    import org.terasoluna.gfw.common.codelist.ExistInCodeList;\n+\n+    public class Role {\n+        @ExistInCodeList(codeListId = \"CL_ROLE\") // (1)\n+        private String value;\n+\n+        public String getValue() {\n+            return value;\n+        }\n+\n+        public void setValue(String value) {\n+            this.value = value;\n+        }\n+\n+        @Override\n+        public String toString(){\n+            return getValue();\n+        }\n+    }\n+\n+  .. tabularcolumns:: |p{0.10\\linewidth}|p{0.90\\linewidth}|\n+  .. list-table::\n+     :header-rows: 1\n+     :widths: 10 90\n+\n+     * - 項番\n+       - 説明\n+     * - | (1)\n+       - | 入力チェックを行いたいフィールドに対して、 \\ ``@ExistInCodeList``\\ アノテーションを設定し、codeListIdにチェック元となるコードリストを指定する。\n+\n+|\n+\n+型変換を行うConverterクラスを実装し、Springに登録する。\n+\n+* Converterクラス\n+\n+  StringからRoleに変換を行うConverterの実装\n+\n+  .. code-block:: java\n+\n+    package com.example.common.validation;\n+\n+    import org.springframework.core.convert.converter.Converter;\n+\n+    public class StringToRoleConverter implements Converter<String, Role> { // (1)\n+        @Override\n+        public Role convert(String source) {\n+            Role role = new Role();\n+            role.setValue(source);\n+            return role;\n+        }\n+    }\n+\n+\n+  ObjectからStringに変換を行うConverterの実装\n+\n+  .. code-block:: java\n+\n+    package com.example.common.validation;\n+\n+    import org.springframework.core.convert.converter.Converter;\n+\n+    public class ToStringConverter implements Converter<Object, String> { // (2)\n+        @Override\n+        public String convert(Object source) {\n+            return source.toString();\n+        }\n+    }\n+\n+\n+  .. tabularcolumns:: |p{0.10\\linewidth}|p{0.90\\linewidth}|\n+  .. list-table::\n+     :header-rows: 1\n+     :widths: 10 90\n+\n+     * - 項番\n+       - 説明\n+     * - | (1)\n+       - | インタフェース\\ ``org.springframework.core.convert.converter.Converter<T, V>``\\ を実装する。ここではString型→Role型の変換を行う。\n+     * - | (2)\n+       - | インタフェース\\ ``org.springframework.core.convert.converter.Converter<T, V>``\\ を実装する。ここではObject型→String型の変換を行う。\n+\n+|\n+\n+* bean定義の設定\n+\n+  .. code-block:: xml\n+\n+    <!-- (1) -->\n+    <bean id=\"conversionService\"\n+        class=\"org.springframework.format.support.FormattingConversionServiceFactoryBean\"> \n+        <!-- (2) -->\n+        <property name=\"converters\">\n+            <list>\n+                <bean class=\"com.example.common.validation.SampleForm$StringToRoleConverter\"/>\n+                <bean class=\"com.example.common.validation.SampleForm$ToStringConverter\"/>","path":"source/ArchitectureInDetail/WebApplicationDetail/Validation.rst","position":179,"original_position":179,"commit_id":"fa03333de36a32cad23bfd3f992c252023e5d88e","original_commit_id":"fa03333de36a32cad23bfd3f992c252023e5d88e","user":{"login":"ikeyat","id":7290819,"avatar_url":"https://avatars.githubusercontent.com/u/7290819?v=3","gravatar_id":"","url":"https://api.github.com/users/ikeyat","html_url":"https://github.com/ikeyat","followers_url":"https://api.github.com/users/ikeyat/followers","following_url":"https://api.github.com/users/ikeyat/following{/other_user}","gists_url":"https://api.github.com/users/ikeyat/gists{/gist_id}","starred_url":"https://api.github.com/users/ikeyat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ikeyat/subscriptions","organizations_url":"https://api.github.com/users/ikeyat/orgs","repos_url":"https://api.github.com/users/ikeyat/repos","events_url":"https://api.github.com/users/ikeyat/events{/privacy}","received_events_url":"https://api.github.com/users/ikeyat/received_events","type":"User","site_admin":false},"body":"- [ ] 内部クラスっぽくなっていますが、Formの内部クラスにする必要は無いと思いますし、これまでそういう説明になっていない。","created_at":"2016-06-16T16:06:38Z","updated_at":"2016-06-16T16:06:38Z","html_url":"https://github.com/terasolunaorg/guideline/pull/1939#discussion_r67373890","pull_request_url":"https://api.github.com/repos/terasolunaorg/guideline/pulls/1939","_links":{"self":{"href":"https://api.github.com/repos/terasolunaorg/guideline/pulls/comments/67373890"},"html":{"href":"https://github.com/terasolunaorg/guideline/pull/1939#discussion_r67373890"},"pull_request":{"href":"https://api.github.com/repos/terasolunaorg/guideline/pulls/1939"}}},"pull_request":{"url":"https://api.github.com/repos/terasolunaorg/guideline/pulls/1939","id":74020903,"html_url":"https://github.com/terasolunaorg/guideline/pull/1939","diff_url":"https://github.com/terasolunaorg/guideline/pull/1939.diff","patch_url":"https://github.com/terasolunaorg/guideline/pull/1939.patch","issue_url":"https://api.github.com/repos/terasolunaorg/guideline/issues/1939","number":1939,"state":"open","locked":false,"title":"add the support the validation for  String objects in a collection #407","user":{"login":"btyamadasun","id":18542545,"avatar_url":"https://avatars.githubusercontent.com/u/18542545?v=3","gravatar_id":"","url":"https://api.github.com/users/btyamadasun","html_url":"https://github.com/btyamadasun","followers_url":"https://api.github.com/users/btyamadasun/followers","following_url":"https://api.github.com/users/btyamadasun/following{/other_user}","gists_url":"https://api.github.com/users/btyamadasun/gists{/gist_id}","starred_url":"https://api.github.com/users/btyamadasun/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/btyamadasun/subscriptions","organizations_url":"https://api.github.com/users/btyamadasun/orgs","repos_url":"https://api.github.com/users/btyamadasun/repos","events_url":"https://api.github.com/users/btyamadasun/events{/privacy}","received_events_url":"https://api.github.com/users/btyamadasun/received_events","type":"User","site_admin":false},"body":"Please review #407 .","created_at":"2016-06-16T04:32:26Z","updated_at":"2016-06-16T16:06:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"57c6f47a1f30612f3756845c388d102c7e0e5fb9","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/terasolunaorg/guideline/pulls/1939/commits","review_comments_url":"https://api.github.com/repos/terasolunaorg/guideline/pulls/1939/comments","review_comment_url":"https://api.github.com/repos/terasolunaorg/guideline/pulls/comments{/number}","comments_url":"https://api.github.com/repos/terasolunaorg/guideline/issues/1939/comments","statuses_url":"https://api.github.com/repos/terasolunaorg/guideline/statuses/fa03333de36a32cad23bfd3f992c252023e5d88e","head":{"label":"terasolunaorg:issues/407_supportValidationForStringObjectInCollection","ref":"issues/407_supportValidationForStringObjectInCollection","sha":"fa03333de36a32cad23bfd3f992c252023e5d88e","user":{"login":"terasolunaorg","id":2259156,"avatar_url":"https://avatars.githubusercontent.com/u/2259156?v=3","gravatar_id":"","url":"https://api.github.com/users/terasolunaorg","html_url":"https://github.com/terasolunaorg","followers_url":"https://api.github.com/users/terasolunaorg/followers","following_url":"https://api.github.com/users/terasolunaorg/following{/other_user}","gists_url":"https://api.github.com/users/terasolunaorg/gists{/gist_id}","starred_url":"https://api.github.com/users/terasolunaorg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/terasolunaorg/subscriptions","organizations_url":"https://api.github.com/users/terasolunaorg/orgs","repos_url":"https://api.github.com/users/terasolunaorg/repos","events_url":"https://api.github.com/users/terasolunaorg/events{/privacy}","received_events_url":"https://api.github.com/users/terasolunaorg/received_events","type":"Organization","site_admin":false},"repo":{"id":15253684,"name":"guideline","full_name":"terasolunaorg/guideline","owner":{"login":"terasolunaorg","id":2259156,"avatar_url":"https://avatars.githubusercontent.com/u/2259156?v=3","gravatar_id":"","url":"https://api.github.com/users/terasolunaorg","html_url":"https://github.com/terasolunaorg","followers_url":"https://api.github.com/users/terasolunaorg/followers","following_url":"https://api.github.com/users/terasolunaorg/following{/other_user}","gists_url":"https://api.github.com/users/terasolunaorg/gists{/gist_id}","starred_url":"https://api.github.com/users/terasolunaorg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/terasolunaorg/subscriptions","organizations_url":"https://api.github.com/users/terasolunaorg/orgs","repos_url":"https://api.github.com/users/terasolunaorg/repos","events_url":"https://api.github.com/users/terasolunaorg/events{/privacy}","received_events_url":"https://api.github.com/users/terasolunaorg/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/terasolunaorg/guideline","description":"TERASOLUNA Server Framework for Java (5.x)  Development Guideline","fork":false,"url":"https://api.github.com/repos/terasolunaorg/guideline","forks_url":"https://api.github.com/repos/terasolunaorg/guideline/forks","keys_url":"https://api.github.com/repos/terasolunaorg/guideline/keys{/key_id}","collaborators_url":"https://api.github.com/repos/terasolunaorg/guideline/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/terasolunaorg/guideline/teams","hooks_url":"https://api.github.com/repos/terasolunaorg/guideline/hooks","issue_events_url":"https://api.github.com/repos/terasolunaorg/guideline/issues/events{/number}","events_url":"https://api.github.com/repos/terasolunaorg/guideline/events","assignees_url":"https://api.github.com/repos/terasolunaorg/guideline/assignees{/user}","branches_url":"https://api.github.com/repos/terasolunaorg/guideline/branches{/branch}","tags_url":"https://api.github.com/repos/terasolunaorg/guideline/tags","blobs_url":"https://api.github.com/repos/terasolunaorg/guideline/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/terasolunaorg/guideline/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/terasolunaorg/guideline/git/refs{/sha}","trees_url":"https://api.github.com/repos/terasolunaorg/guideline/git/trees{/sha}","statuses_url":"https://api.github.com/repos/terasolunaorg/guideline/statuses/{sha}","languages_url":"https://api.github.com/repos/terasolunaorg/guideline/languages","stargazers_url":"https://api.github.com/repos/terasolunaorg/guideline/stargazers","contributors_url":"https://api.github.com/repos/terasolunaorg/guideline/contributors","subscribers_url":"https://api.github.com/repos/terasolunaorg/guideline/subscribers","subscription_url":"https://api.github.com/repos/terasolunaorg/guideline/subscription","commits_url":"https://api.github.com/repos/terasolunaorg/guideline/commits{/sha}","git_commits_url":"https://api.github.com/repos/terasolunaorg/guideline/git/commits{/sha}","comments_url":"https://api.github.com/repos/terasolunaorg/guideline/comments{/number}","issue_comment_url":"https://api.github.com/repos/terasolunaorg/guideline/issues/comments{/number}","contents_url":"https://api.github.com/repos/terasolunaorg/guideline/contents/{+path}","compare_url":"https://api.github.com/repos/terasolunaorg/guideline/compare/{base}...{head}","merges_url":"https://api.github.com/repos/terasolunaorg/guideline/merges","archive_url":"https://api.github.com/repos/terasolunaorg/guideline/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/terasolunaorg/guideline/downloads","issues_url":"https://api.github.com/repos/terasolunaorg/guideline/issues{/number}","pulls_url":"https://api.github.com/repos/terasolunaorg/guideline/pulls{/number}","milestones_url":"https://api.github.com/repos/terasolunaorg/guideline/milestones{/number}","notifications_url":"https://api.github.com/repos/terasolunaorg/guideline/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/terasolunaorg/guideline/labels{/name}","releases_url":"https://api.github.com/repos/terasolunaorg/guideline/releases{/id}","deployments_url":"https://api.github.com/repos/terasolunaorg/guideline/deployments","created_at":"2013-12-17T12:19:55Z","updated_at":"2016-06-12T16:57:25Z","pushed_at":"2016-06-16T09:14:15Z","git_url":"git://github.com/terasolunaorg/guideline.git","ssh_url":"git@github.com:terasolunaorg/guideline.git","clone_url":"https://github.com/terasolunaorg/guideline.git","svn_url":"https://github.com/terasolunaorg/guideline","homepage":"http://terasolunaorg.github.io/guideline/","size":70011,"stargazers_count":57,"watchers_count":57,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":11,"mirror_url":null,"open_issues_count":124,"forks":11,"open_issues":124,"watchers":57,"default_branch":"master"}},"base":{"label":"terasolunaorg:master","ref":"master","sha":"ebe7cf8cad95aa7a7aa29461934b13203b587003","user":{"login":"terasolunaorg","id":2259156,"avatar_url":"https://avatars.githubusercontent.com/u/2259156?v=3","gravatar_id":"","url":"https://api.github.com/users/terasolunaorg","html_url":"https://github.com/terasolunaorg","followers_url":"https://api.github.com/users/terasolunaorg/followers","following_url":"https://api.github.com/users/terasolunaorg/following{/other_user}","gists_url":"https://api.github.com/users/terasolunaorg/gists{/gist_id}","starred_url":"https://api.github.com/users/terasolunaorg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/terasolunaorg/subscriptions","organizations_url":"https://api.github.com/users/terasolunaorg/orgs","repos_url":"https://api.github.com/users/terasolunaorg/repos","events_url":"https://api.github.com/users/terasolunaorg/events{/privacy}","received_events_url":"https://api.github.com/users/terasolunaorg/received_events","type":"Organization","site_admin":false},"repo":{"id":15253684,"name":"guideline","full_name":"terasolunaorg/guideline","owner":{"login":"terasolunaorg","id":2259156,"avatar_url":"https://avatars.githubusercontent.com/u/2259156?v=3","gravatar_id":"","url":"https://api.github.com/users/terasolunaorg","html_url":"https://github.com/terasolunaorg","followers_url":"https://api.github.com/users/terasolunaorg/followers","following_url":"https://api.github.com/users/terasolunaorg/following{/other_user}","gists_url":"https://api.github.com/users/terasolunaorg/gists{/gist_id}","starred_url":"https://api.github.com/users/terasolunaorg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/terasolunaorg/subscriptions","organizations_url":"https://api.github.com/users/terasolunaorg/orgs","repos_url":"https://api.github.com/users/terasolunaorg/repos","events_url":"https://api.github.com/users/terasolunaorg/events{/privacy}","received_events_url":"https://api.github.com/users/terasolunaorg/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/terasolunaorg/guideline","description":"TERASOLUNA Server Framework for Java (5.x)  Development Guideline","fork":false,"url":"https://api.github.com/repos/terasolunaorg/guideline","forks_url":"https://api.github.com/repos/terasolunaorg/guideline/forks","keys_url":"https://api.github.com/repos/terasolunaorg/guideline/keys{/key_id}","collaborators_url":"https://api.github.com/repos/terasolunaorg/guideline/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/terasolunaorg/guideline/teams","hooks_url":"https://api.github.com/repos/terasolunaorg/guideline/hooks","issue_events_url":"https://api.github.com/repos/terasolunaorg/guideline/issues/events{/number}","events_url":"https://api.github.com/repos/terasolunaorg/guideline/events","assignees_url":"https://api.github.com/repos/terasolunaorg/guideline/assignees{/user}","branches_url":"https://api.github.com/repos/terasolunaorg/guideline/branches{/branch}","tags_url":"https://api.github.com/repos/terasolunaorg/guideline/tags","blobs_url":"https://api.github.com/repos/terasolunaorg/guideline/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/terasolunaorg/guideline/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/terasolunaorg/guideline/git/refs{/sha}","trees_url":"https://api.github.com/repos/terasolunaorg/guideline/git/trees{/sha}","statuses_url":"https://api.github.com/repos/terasolunaorg/guideline/statuses/{sha}","languages_url":"https://api.github.com/repos/terasolunaorg/guideline/languages","stargazers_url":"https://api.github.com/repos/terasolunaorg/guideline/stargazers","contributors_url":"https://api.github.com/repos/terasolunaorg/guideline/contributors","subscribers_url":"https://api.github.com/repos/terasolunaorg/guideline/subscribers","subscription_url":"https://api.github.com/repos/terasolunaorg/guideline/subscription","commits_url":"https://api.github.com/repos/terasolunaorg/guideline/commits{/sha}","git_commits_url":"https://api.github.com/repos/terasolunaorg/guideline/git/commits{/sha}","comments_url":"https://api.github.com/repos/terasolunaorg/guideline/comments{/number}","issue_comment_url":"https://api.github.com/repos/terasolunaorg/guideline/issues/comments{/number}","contents_url":"https://api.github.com/repos/terasolunaorg/guideline/contents/{+path}","compare_url":"https://api.github.com/repos/terasolunaorg/guideline/compare/{base}...{head}","merges_url":"https://api.github.com/repos/terasolunaorg/guideline/merges","archive_url":"https://api.github.com/repos/terasolunaorg/guideline/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/terasolunaorg/guideline/downloads","issues_url":"https://api.github.com/repos/terasolunaorg/guideline/issues{/number}","pulls_url":"https://api.github.com/repos/terasolunaorg/guideline/pulls{/number}","milestones_url":"https://api.github.com/repos/terasolunaorg/guideline/milestones{/number}","notifications_url":"https://api.github.com/repos/terasolunaorg/guideline/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/terasolunaorg/guideline/labels{/name}","releases_url":"https://api.github.com/repos/terasolunaorg/guideline/releases{/id}","deployments_url":"https://api.github.com/repos/terasolunaorg/guideline/deployments","created_at":"2013-12-17T12:19:55Z","updated_at":"2016-06-12T16:57:25Z","pushed_at":"2016-06-16T09:14:15Z","git_url":"git://github.com/terasolunaorg/guideline.git","ssh_url":"git@github.com:terasolunaorg/guideline.git","clone_url":"https://github.com/terasolunaorg/guideline.git","svn_url":"https://github.com/terasolunaorg/guideline","homepage":"http://terasolunaorg.github.io/guideline/","size":70011,"stargazers_count":57,"watchers_count":57,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":11,"mirror_url":null,"open_issues_count":124,"forks":11,"open_issues":124,"watchers":57,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/terasolunaorg/guideline/pulls/1939"},"html":{"href":"https://github.com/terasolunaorg/guideline/pull/1939"},"issue":{"href":"https://api.github.com/repos/terasolunaorg/guideline/issues/1939"},"comments":{"href":"https://api.github.com/repos/terasolunaorg/guideline/issues/1939/comments"},"review_comments":{"href":"https://api.github.com/repos/terasolunaorg/guideline/pulls/1939/comments"},"review_comment":{"href":"https://api.github.com/repos/terasolunaorg/guideline/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/terasolunaorg/guideline/pulls/1939/commits"},"statuses":{"href":"https://api.github.com/repos/terasolunaorg/guideline/statuses/fa03333de36a32cad23bfd3f992c252023e5d88e"}}}}
{"actor":{"display_login":"ikeyat"}}