{"id":787,"date":"2013-10-18T13:49:59","date_gmt":"2013-10-18T20:49:59","guid":{"rendered":"http:\/\/10kdev.net\/?p=787"},"modified":"2013-10-23T04:59:30","modified_gmt":"2013-10-23T11:59:30","slug":"optional-path-variables-in-spring-web-mvc","status":"publish","type":"post","link":"http:\/\/10kdev.net\/?p=787","title":{"rendered":"Optional Path Variables in Spring Web MVC"},"content":{"rendered":"<p>With a Spring Web MVC controller endpoint in Java you cannot have an optional @PathVariable, so you have to do things old school. In my code I wanted a default sorting mechanism, if the caller of my endpoint didn&#8217;t put in any sort parameters. The sort (orderBy) parameters are the fields, and the direction of the sort is specified in an already provided Spring enumeration that I pass a string value to.<\/p>\n<blockquote><p>The whole *secret* &#8212; just pass the HttpServletRequest object into the controller method. \u00a0That&#8217;s it.<\/p><\/blockquote>\n<p>Note my setup is Spring core libraries (and MVC) 3.2.4, Spring Data JPA 1.4.1, and Hibernate for the dialect version 4.2.1 with JPA Api 1.0.1.<\/p>\n<p>Endpoint in the Controller:<\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\"> <span style=\"color: #646464;\">@ApiOperation<span style=\"color: black;\">(value=<span style=\"color: #2a00ff;\">&#8220;look for list by sorting&#8221;<span style=\"color: black;\">, <\/span><br \/>\n<\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\">\u00a0\u00a0\u00a0\u00a0 notes= <span style=\"color: #2a00ff;\">&#8221; two optional parameters: orderBy = {fieldA, fieldB, fieldC} &#8220;<\/span><br \/>\n<\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + <span style=\"color: #2a00ff;\">&#8220;direction = {ASC,DESC}&#8221;<span style=\"color: black;\">)<\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\"> <span style=\"color: #646464;\">@RequestMapping<span style=\"color: black;\">(method = RequestMethod.<span style=\"color: #0000c0;\"><em>GET<\/em><span style=\"color: black;\">, value = <span style=\"color: #2a00ff;\">&#8220;\/look&#8221;<span style=\"color: black;\">)<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\"> <span style=\"color: #7f0055;\"><strong>public<\/strong><span style=\"color: black;\"><br \/>\n<span style=\"color: #646464;\">@ResponseBody<\/span><br \/>\n<\/span><\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 10pt;\"><span style=\"color: black;\"> List&lt;ObjectDto&gt; findSorted(HttpServletRequest request) {<\/span><br \/>\n<\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\">\u00a0\u00a0\u00a0\u00a0<span style=\"color: #7f0055;\"><strong>return\u00a0<\/strong><span style=\"color: black;\"><span style=\"color: #0000c0; font-size: 10pt;\">dataService<\/span><span style=\"color: black;\">.findSorted (request.getParameter(<span style=\"color: #2a00ff;\">&#8220;orderBy&#8221;<span style=\"color: black;\">), request.getParameter(<span style=\"color: #2a00ff;\">&#8220;direction&#8221;<span style=\"color: black;\">));<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\"> }<\/span><\/p>\n<p>This calls the service, which builds a Pageable object. I haven&#8217;t had a need to refactor the method so I just left the code in the service method for now. There are a few ternaries to check for nulls (note: PMD has a base rule to not reuse method parms as well).<\/p>\n<p>Method in the Service:<\/p>\n<p><span style=\"color: #7f0055; font-family: Consolas; font-size: 10pt;\"><strong>private<\/strong><span style=\"color: black;\"><br \/>\n<span style=\"color: #7f0055;\"><strong>final<\/strong><span style=\"color: black;\"><br \/>\n<span style=\"color: #7f0055;\"><strong>static<\/strong><span style=\"color: black;\"> String <span style=\"color: #0000c0;\"><em>DEFAULT_ORDER<\/em><span style=\"color: black;\"> = <span style=\"color: #2a00ff;\">&#8220;fieldA&#8221;<span style=\"color: black;\">;<\/span><br \/>\n<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: #7f0055; font-family: Consolas;\"><span style=\"font-size: 10pt;\"><strong>private<\/strong><span style=\"color: black;\"><br \/>\n<span style=\"color: #7f0055;\"><strong>final<\/strong><span style=\"color: black;\"><br \/>\n<span style=\"color: #7f0055;\"><strong>static<\/strong><span style=\"color: black;\"> String <span style=\"color: #0000c0;\"><em>DEFAULT_DIRECTION<\/em><span style=\"color: black;\"> = <span style=\"color: #2a00ff;\">&#8220;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><span style=\"font-size: 9pt;\">ASC<\/span><span style=\"color: #2a00ff; font-size: 10pt;\">&#8220;<span style=\"color: black;\">;<br \/>\n<\/span><\/span><\/span><\/p>\n<p><span style=\"color: #7f0055; font-family: Consolas; font-size: 10pt;\"><strong>public<\/strong><span style=\"color: black;\"> List&lt;Object&gt; getEntities(Pageable pageable) {<\/span><br \/>\n<\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\">\u00a0\u00a0\u00a0\u00a0<span style=\"color: #7f0055;\"><strong>return\u00a0<\/strong><span style=\"color: black;\"><span style=\"color: #0000c0; font-size: 10pt;\">objectRepository<\/span><span style=\"color: black;\">.findAll(pageable).getContent();<\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 10pt;\"><span style=\"color: black;\">}<\/span><br \/>\n<\/span><\/p>\n<p><span style=\"color: #7f0055; font-family: Consolas; font-size: 10pt;\"><strong>public<\/strong><span style=\"color: black;\"> List&lt;ObjectDto&gt; getDTOs(Pageable pageable) {<\/span><br \/>\n<\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\">\u00a0\u00a0\u00a0\u00a0<span style=\"color: #7f0055;\"><strong>return\u00a0<\/strong><span style=\"color: black;\"><span style=\"color: #0000c0; font-size: 10pt;\">objectMapper<\/span><span style=\"color: black;\">.toDTOs(getEntities(pageable), ObjectDto.<span style=\"color: #7f0055;\"><strong>class<\/strong><span style=\"color: black;\">);<\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\">}<\/span><\/p>\n<p><span style=\"color: #7f0055; font-family: Consolas; font-size: 10pt;\"><strong>public<\/strong><span style=\"color: black;\"> List&lt; ObjectDto &gt; findSorted (String orderBy, String direction) {<\/span><br \/>\n<\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\"> String order = orderBy == <span style=\"color: #7f0055;\"><strong>null<\/strong><span style=\"color: black;\"> ? <span style=\"color: #0000c0;\"><em>DEFAULT_ORDER<\/em><span style=\"color: black;\"> : orderBy;<\/span><br \/>\n<\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\"> String dir = direction == <span style=\"color: #7f0055;\"><strong>null<\/strong><span style=\"color: black;\"> ? <span style=\"color: #0000c0;\"><em>DEFAULT_DIRECTION<\/em><span style=\"color: black;\"> : direction;<\/span><br \/>\n<\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\"><br \/>\n<span style=\"color: #7f0055;\"><strong>final<\/strong><span style=\"color: black;\"> PageRequest pageable = <span style=\"color: #7f0055;\"><strong>new<\/strong><span style=\"color: black;\"> PageRequest(<\/span><br \/>\n<\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\">\u00a0\u00a0\u00a0\u00a0 0, Paging.<span style=\"color: #0000c0;\"><em>PAGING_SIZE<\/em><span style=\"color: black;\">, <span style=\"color: #7f0055;\"><strong>new<\/strong><span style=\"color: black;\"> Sort(<\/span><br \/>\n<\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\">\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #7f0055;\"><strong>new<\/strong><span style=\"color: black;\"> Order(Direction.<em>fromString<\/em>(dir), order)));<\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\"> <span style=\"color: #7f0055;\"><strong>return\u00a0<\/strong><span style=\"color: black;\"><span style=\"color: #0000c0; font-size: 10pt;\">objectService<\/span><span style=\"color: black;\">.getDTOs (pageable);<\/span><\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 10pt;\">}<\/span><\/p>\n<p>The mapper code is simple, using commons BeanUtils:<\/p>\n<p><span style=\"font-family: Consolas; font-size: 10pt;\"><span style=\"color: black;\">\u00a0\u00a0\u00a0\u00a0BeanUtils.<em>copyProperties<\/em>(fromEntity, toDto);<\/span><br \/>\n<\/span><\/p>\n<p>And the repository code extends JPARepository, so there is already a findAll(pageable) function in the canned interface.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With a Spring Web MVC controller endpoint in Java you cannot have an optional @PathVariable, so you have to do things old school. In my code I wanted a default sorting mechanism, if the caller of my endpoint didn&#8217;t put in any sort parameters. The sort (orderBy) parameters are the fields, and the direction of [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts\/787"}],"collection":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=787"}],"version-history":[{"count":8,"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts\/787\/revisions"}],"predecessor-version":[{"id":806,"href":"http:\/\/10kdev.net\/index.php?rest_route=\/wp\/v2\/posts\/787\/revisions\/806"}],"wp:attachment":[{"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=787"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=787"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/10kdev.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=787"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}