<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://feeds.feedblitz.com/feedblitz_rss.xslt"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"  xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><channel><title>Petri Kainulainen</title> <atom:link href="http://www.petrikainulainen.net/feed/" rel="self" type="application/rss+xml" /><link>http://www.petrikainulainen.net</link> <description>Developing Software With Passion</description> <lastBuildDate>Fri, 24 May 2013 09:11:33 +0000</lastBuildDate> <language>en-US</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.5.1</generator>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/</feedburner:origLink><title>Spring from the Trenches: Adding Validation to a REST API</title><link>http://feeds.feedblitz.com/~/41484906/0/petrikainulainen~Spring-from-the-Trenches-Adding-Validation-to-a-REST-API/</link> <comments>http://feeds.feedblitz.com/~/41484906/0/petrikainulainen~Spring-from-the-Trenches-Adding-Validation-to-a-REST-API/#comments</comments> <pubDate>Thu, 23 May 2013 18:03:30 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Spring Framework]]></category> <category><![CDATA[REST]]></category> <category><![CDATA[Spring MVC]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=5335</guid> <description><![CDATA[I am a bit ashamed to admit this but until yesterday, I had no idea that I can add validation to a REST API by using the @Valid and the @RequestBody annotations. This was not working in Spring MVC 3.0 and for some reason I had not noticed that the support for this was added [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-write-clean-assertions-with-jsonpath/&quot;&gt;Integration Testing of Spring MVC Applications: Write Clean Assertions with JsonPath&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-pagination/&quot;&gt;Spring Data Solr Tutorial: Pagination&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/rustymilaryhelmet.jpg" alt="Rusty milary helmet" /></a></p><p>I am a bit ashamed to admit this but until yesterday, I had no idea that I can add validation to a REST API by using the <em>@Valid</em> and the <em>@RequestBody</em> annotations.</p><p>This was not working in Spring MVC 3.0 and for some reason I had not noticed that the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~blog.goyello.com/2011/12/16/enhancements-spring-mvc31/" target="_blank">support for this was added in Spring MVC 3.1</a>.</p><p>I never liked the old approach because I had to</p><ol><li>Inject the <em>Validator</em> and <em>MessageSource</em> beans to my controller so that I can validate the request and fetch the localized error messages if the validation fails.</li><li>Call the validation method in every controller method which input must be validated.</li><li>Move the validation logic into a common base class which is extended by the controller classes.</li></ol><p>When I noticed that I don&#8217;t have to do these things anymore, I decided to write this blog post and share my findings with all of you.</p><p>Let&#8217;s start by taking a look at the DTO class used in this blog post. The source code of the <em>CommentDTO</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.hibernate.validator.constraints.Length</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.hibernate.validator.constraints.NotEmpty</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> CommentDTO <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @<span style="color: #003399;">NotEmpty</span>
<br> &nbsp; &nbsp; @Length<span style="color: #009900;">&#40;</span>max <span style="color: #339933;">=</span> <span style="color: #cc66cc;">140</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> text<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p>Let&#8217;s move on and find out how we can add validation to a REST API with Spring MVC 3.1.</p><h2>Spring MVC 3.1 Is a Good Start</h2><p>We can add validation to our REST API by following these steps:</p><ol><li>Implement a controller method and ensure that its input is validated.</li><li>Implement the logic which handles validation errors.</li></ol><p>Both of the steps are described in the following subsections.</p><h3>Implementing the Controller</h3><p>We can implement our controller by following these steps:</p><ol><li>Create a class called <em>CommentController</em> and annotate this class with the <em>@Controller</em> annotation.</li><li>Add an <em>add()</em> method to the <em>CommentController</em> class which takes the added comment as a method parameter.</li><li>Annotate the method with <em>@RequestMapping</em> and </em>@ResponseBody</em> annotations.</li><li>Apply the <em>@Valid</em> and <em>@RequestBody</em> annotations to the method parameter.</li><li>Return the added comment.</li></ol><p>The source code of the <em>CommentController</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.beans.factory.annotation.Autowired</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.http.HttpStatus</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Controller</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.annotation.*</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.Valid</span><span style="color: #339933;">;</span>
<br> 
<br> @Controller
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> CommentController <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @RequestMapping<span style="color: #009900;">&#40;</span>value <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;/api/comment&quot;</span>, method <span style="color: #339933;">=</span> RequestMethod.<span style="color: #006633;">POST</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @ResponseBody
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> CommentDTO add<span style="color: #009900;">&#40;</span>@Valid @RequestBody CommentDTO comment<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> comment<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p>We have now added a new method to our controller and added validation to it. When the validation fails, the <em>MethodArgumentNotValidException</em> is thrown. Let&#8217;s find out how we can return a meaningful response to the user of our API when the validation fails.</p><h3>Handling Validation Errors</h3><p>We can implement the logic which handles the validation errors by following these steps:</p><ol><li>Implement the data transfer objects which contains the information returned to the user of our REST API.</li><li>Implement the exception handler method.</li></ol><p>These steps are described with more details in the following.</p><h4>Creating the Data Transfer Objects</h4><p>First, we have to create the data transfer objects which contains the information returned to the user of our REST API. We can do this by following these steps:</p><ol><li>Create a DTO which contains the information of a single validation error.</li><li>Create a DTO which wraps those validation errors together.</li></ol><p>Let&#8217;s get started.</p><p>The source code of the first DTO looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> FieldErrorDTO <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> field<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> message<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> FieldErrorDTO<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> field, <span style="color: #003399;">String</span> message<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">field</span> <span style="color: #339933;">=</span> field<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">message</span> <span style="color: #339933;">=</span> message<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Getters are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p>The implementation of the second DTO is rather simple. It contains a list of <em>FieldErrorDTO</em> objects and a method which is used to add new field errors to the list. The source code of the <em>ValidationErrorDTO</em> looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.ArrayList</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ValidationErrorDTO <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> List<span style="color: #339933;">&lt;</span>FieldErrorDTO<span style="color: #339933;">&gt;</span> fieldErrors <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ArrayList<span style="color: #339933;">&lt;&gt;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> ValidationErrorDTO<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> addFieldError<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> path, <span style="color: #003399;">String</span> message<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; FieldErrorDTO error <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> FieldErrorDTO<span style="color: #009900;">&#40;</span>path, message<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; fieldErrors.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>error<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Getter is omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p>The following listing provides an example Json document which is send back to the user of our API when the validation fails:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">{
<br> &nbsp; &nbsp; &quot;fieldErrors&quot;:[
<br> &nbsp; &nbsp; &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;field&quot;:&quot;text&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;message&quot;:&quot;error message&quot;
<br> &nbsp; &nbsp; &nbsp; &nbsp; }
<br> &nbsp; &nbsp; ]
<br> }</div></div><p>Let&#8217;s see how we can implement the exception handler method which creates a new <em>ValidationErrorDTO</em> object and returns created object.</p><h4>Implementing the Exception Handler Method</h4><p>We can add the exception handler method to our controller by following these steps:</p><ol><li>Add a <em>MessageSource</em> field to the <em>CommentController</em> class. The message source is used to fetch localized error message for validation errors.</li><li>Inject the <em>MessageSource</em> bean by using constructor injection.</li><li>Add a <em>processValidationError()</em> method to the <em>CommentController</em> class. This method returns <em>ValidationErrorDTO</em> object and takes a <em>MethodArgumentNotValidException</em> object as a method parameter.</li><li>Annotate the method with the <em>@ExceptionHandler</em> annotation and ensure that the method is called when the <em>MethodArgumentNotValidException</em> is thrown.</li><li>Annotate the method with the <em>@ResponseStatus</em> annotation and ensure that the HTTP status code 400 (bad request) is returned.</li><li>Annotate the method with the <em>@ResponseBody</em> annotation.</li><li>Implement the method.</li></ol><p>Let&#8217;s take a closer look at the implementation of the <em>processValidationError()</em> method. We can implement this method by following these steps:</p><ol><li>Get a list of <em>FieldError</em> objects and process them.</li><li>Process the field errors one field error at the time.</li><li>Try to resolve a localized error message by using the <em>MessageSource</em> object, current locale and the error code of the processed field error.</li><li>Return the resolved error message. If the error message is not found from the properties file, return the most accurate field error code.</li><li>Add a new field error by calling the <em>addFieldError()</em> method of the <em>ValidationErrorDTO</em> class. Pass the name of the field and the resolved error message as method parameters.</li><li>Return the created <em>ValidationErrorDTO</em> object after each field error has been processed.</li></ol><p>The source code of the CommentController class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:1490px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.beans.factory.annotation.Autowired</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.MessageSource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.i18n.LocaleContextHolder</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.http.HttpStatus</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Controller</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.validation.BindingResult</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.validation.FieldError</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.MethodArgumentNotValidException</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.annotation.*</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.Valid</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.Locale</span><span style="color: #339933;">;</span>
<br> 
<br> @Controller
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> CommentController <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> MessageSource messageSource<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Autowired
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> CommentController<span style="color: #009900;">&#40;</span>MessageSource messageSource<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">messageSource</span> <span style="color: #339933;">=</span> messageSource<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//The add() method is omitted.</span>
<br> 
<br> &nbsp; &nbsp; @ExceptionHandler<span style="color: #009900;">&#40;</span>MethodArgumentNotValidException.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @ResponseStatus<span style="color: #009900;">&#40;</span>HttpStatus.<span style="color: #006633;">BAD_REQUEST</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @ResponseBody
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> ValidationErrorDTO processValidationError<span style="color: #009900;">&#40;</span>MethodArgumentNotValidException ex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; BindingResult result <span style="color: #339933;">=</span> ex.<span style="color: #006633;">getBindingResult</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; List<span style="color: #339933;">&lt;</span>FieldError<span style="color: #339933;">&gt;</span> fieldErrors <span style="color: #339933;">=</span> result.<span style="color: #006633;">getFieldErrors</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> processFieldErrors<span style="color: #009900;">&#40;</span>fieldErrors<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> ValidationErrorDTO processFieldErrors<span style="color: #009900;">&#40;</span>List<span style="color: #339933;">&lt;</span>FieldError<span style="color: #339933;">&gt;</span> fieldErrors<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">Locale</span> currentLocale <span style="color: #339933;">=</span> &nbsp;LocaleContextHolder.<span style="color: #006633;">getLocale</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; ValidationErrorDTO dto <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ValidationErrorDTO<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>FieldError fieldError<span style="color: #339933;">:</span> fieldErrors<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> localizedErrorMessage <span style="color: #339933;">=</span> resolveLocalizedErrorMessage<span style="color: #009900;">&#40;</span>fieldError, currentLocale<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dto.<span style="color: #006633;">addFieldError</span><span style="color: #009900;">&#40;</span>fieldError.<span style="color: #006633;">getField</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, localizedErrorMessage<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> dto<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> resolveLocalizedErrorMessage<span style="color: #009900;">&#40;</span>FieldError fieldError, <span style="color: #003399;">Locale</span> locale<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> localizedErrorMessage <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> fieldErrorCodes <span style="color: #339933;">=</span> fieldError.<span style="color: #006633;">getCodes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> index <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> index <span style="color: #339933;">&lt;</span> fieldErrorCodes.<span style="color: #006633;">length</span><span style="color: #339933;">;</span> index<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> fieldErrorCode <span style="color: #339933;">=</span> fieldErrorCodes<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; localizedErrorMessage <span style="color: #339933;">=</span> getMessageForCode<span style="color: #009900;">&#40;</span>fieldErrorCode, fieldError.<span style="color: #006633;">getArguments</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, locale<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>localizedErrorMessage <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//If a message was not found, return the most accurate field error code instead.</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>localizedErrorMessage <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; localizedErrorMessage <span style="color: #339933;">=</span> fieldErrorCodes<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> localizedErrorMessage<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> getMessageForCode<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> code, <span style="color: #003399;">Object</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> params, <span style="color: #003399;">Locale</span> locale<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> message <span style="color: #339933;">=</span> messageSource.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span>code, params, locale<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>message <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #339933;">&amp;&amp;</span> message.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>code<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> message<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p>That is it. Let&#8217;s spend a moment to evaluate what we have just done.</p><h3>We Are Almost There</h3><p>We have now added validation to our REST API with Spring MVC 3.1. This implementation has one major benefit over the old approach:</p><p>We can trigger the validation process by using the <em>@Valid</em> annotation.</p><p>However, the methods annotated with the <em>@ExceptionHandler</em> annotation will be triggered only when the configured exception is thrown from the controller class which contains the exception handler method. This means that if our application has more than one controller, we have to create a common base class for our controllers and move the logic which handles the validation errors to that class. This might not sound like a big deal but we should <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~ron.shoutboot.com/2012/07/27/composition-over-inheritance/" target="_blank">prefer composition over inheritance</a>.</p><p>Spring MVC 3.2 provides the tools which we can use to remove the need of inheritance from our controllers. Let&#8217;s move on and find out how this is done.</p><h2>Spring MVC 3.2 to the Rescue</h2><p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-framework/docs/3.2.x/spring-framework-reference/htmlsingle/#new-in-3.2-webmvc-controller-advice" target="_blank">Spring MVC 3.2 introduced a new <em>@ControllerAdvice</em> annotation</a> which we can use to implement an exception handler component that processes the exceptions thrown by our controllers. We can implement this component by following these steps:</p><ol><li>Remove the logic which handles validation errors from the <em>CommentController</em> class.</li><li>Create a new exception handler class and move the logic which processes validation errors to the created class.</li></ol><p>These steps are explained with more details in the following subsections.</p><h3>Removing Exception Handling Logic from Our Controller</h3><p>We can remove the exception handling logic from our controller by following these steps:</p><ol><li>Remove the <em>MessageSource</em> field from the <em>CommentController</em> class.</li><li>Remove the constructor from our controller class.</li><li>Remove the <em>processValidationError()</em> method and the private methods from our controller class.</li></ol><p>The source code of the <em>CommentController</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Controller</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.annotation.*</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.validation.Valid</span><span style="color: #339933;">;</span>
<br> 
<br> @Controller
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> CommentController <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @RequestMapping<span style="color: #009900;">&#40;</span>value <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;/api/comment&quot;</span>, method <span style="color: #339933;">=</span> RequestMethod.<span style="color: #006633;">POST</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @ResponseBody
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> CommentDTO add<span style="color: #009900;">&#40;</span>@Valid @RequestBody CommentDTO comment<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> comment<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p>Our is next step is to create the exception handler component. Let&#8217;s see how this is done.</p><h3>Creating the Exception Handler Component</h3><p>We can create the exception handler component by following these steps:</p><ol><li>Create a class called <em>RestErrorHandler</em> and annotate it with the <em>@ControllerAdvice</em> annotation.</li><li>Add a <em>MessageSource</em> field to the <em>RestErrorHandler</em> class.</li><li>Inject the <em>MessageSource</em> bean by using constructor injection.</li><li>Add the <em>processValidationError()</em> method and the required private methods to the <em>RestErrorHandler</em> class.</li></ol><p>The source code of the RestErrorHandler class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:1490px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.beans.factory.annotation.Autowired</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.MessageSource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.i18n.LocaleContextHolder</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.http.HttpStatus</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.validation.BindingResult</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.validation.FieldError</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.MethodArgumentNotValidException</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.annotation.ControllerAdvice</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.annotation.ExceptionHandler</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.annotation.ResponseBody</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.annotation.ResponseStatus</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.Locale</span><span style="color: #339933;">;</span>
<br> 
<br> @ControllerAdvice
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RestErrorHandler <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> MessageSource messageSource<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Autowired
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> RestErrorHandler<span style="color: #009900;">&#40;</span>MessageSource messageSource<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006633;">messageSource</span> <span style="color: #339933;">=</span> messageSource<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; @ExceptionHandler<span style="color: #009900;">&#40;</span>MethodArgumentNotValidException.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @ResponseStatus<span style="color: #009900;">&#40;</span>HttpStatus.<span style="color: #006633;">BAD_REQUEST</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @ResponseBody
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> ValidationErrorDTO processValidationError<span style="color: #009900;">&#40;</span>MethodArgumentNotValidException ex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; BindingResult result <span style="color: #339933;">=</span> ex.<span style="color: #006633;">getBindingResult</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; List<span style="color: #339933;">&lt;</span>FieldError<span style="color: #339933;">&gt;</span> fieldErrors <span style="color: #339933;">=</span> result.<span style="color: #006633;">getFieldErrors</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> processFieldErrors<span style="color: #009900;">&#40;</span>fieldErrors<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> ValidationErrorDTO processFieldErrors<span style="color: #009900;">&#40;</span>List<span style="color: #339933;">&lt;</span>FieldError<span style="color: #339933;">&gt;</span> fieldErrors<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">Locale</span> currentLocale <span style="color: #339933;">=</span> LocaleContextHolder.<span style="color: #006633;">getLocale</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; ValidationErrorDTO dto <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ValidationErrorDTO<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>FieldError fieldError<span style="color: #339933;">:</span> fieldErrors<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> localizedErrorMessage <span style="color: #339933;">=</span> resolveLocalizedErrorMessage<span style="color: #009900;">&#40;</span>fieldError, currentLocale<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dto.<span style="color: #006633;">addFieldError</span><span style="color: #009900;">&#40;</span>fieldError.<span style="color: #006633;">getField</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, localizedErrorMessage<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> dto<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> resolveLocalizedErrorMessage<span style="color: #009900;">&#40;</span>FieldError fieldError, <span style="color: #003399;">Locale</span> locale<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> localizedErrorMessage <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> fieldErrorCodes <span style="color: #339933;">=</span> fieldError.<span style="color: #006633;">getCodes</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> index <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> index <span style="color: #339933;">&lt;</span> fieldErrorCodes.<span style="color: #006633;">length</span><span style="color: #339933;">;</span> index<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> fieldErrorCode <span style="color: #339933;">=</span> fieldErrorCodes<span style="color: #009900;">&#91;</span>index<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; localizedErrorMessage <span style="color: #339933;">=</span> getMessageForCode<span style="color: #009900;">&#40;</span>fieldErrorCode, fieldError.<span style="color: #006633;">getArguments</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, locale<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>localizedErrorMessage <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//If a message was not found, return the most accurate field error code instead.</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>localizedErrorMessage <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; localizedErrorMessage <span style="color: #339933;">=</span> fieldErrorCodes<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> localizedErrorMessage<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> getMessageForCode<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> code, <span style="color: #003399;">Object</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> params, <span style="color: #003399;">Locale</span> locale<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> message <span style="color: #339933;">=</span> messageSource.<span style="color: #006633;">getMessage</span><span style="color: #009900;">&#40;</span>code, params, locale<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>message <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span> <span style="color: #339933;">&amp;&amp;</span> message.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>code<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> message<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>We Are Finally There</h3><p>Thanks to Spring MVC 3.2, we have now implemented an elegant solution where the validation is triggered by the <em>@Valid</em> annotation, and the exception handling logic is moved to a separate class. I think that we can call it a day and enjoy the results of our work.</p><h2>Summary</h2><p>This blog post has taught us that</p><ul><li>If we want to add validation to a REST API when we are using Spring 3.0, we have to implement the validation logic ourself.</li><li>Spring 3.1 made it possible to add validation to a REST API by using the <em>@Valid</em> annotation. However, we have to create a common base class which contains the exception handling logic. Each controller which requires validation must extend this base class.</li><li>When we are using Spring 3.2, we can trigger the validation process by using the <em>@Valid</em> annotation and extract the exception handling logic into a separate class.</li></ul><p>The example application of this blog are available at Github (<a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-from-the-trenches/tree/master/rest-validation-3.1" target="_blank">Spring 3.1</a> and <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-from-the-trenches/tree/master/rest-validation-3.2" target="_blank">Spring 3.2</a>)</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/41484906/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/41484906/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-write-clean-assertions-with-jsonpath/&quot;&gt;Integration Testing of Spring MVC Applications: Write Clean Assertions with JsonPath&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-pagination/&quot;&gt;Spring Data Solr Tutorial: Pagination&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/41484906/0/petrikainulainen~Spring-from-the-Trenches-Adding-Validation-to-a-REST-API/feed/</wfw:commentRss> <slash:comments>0</slash:comments></item>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-pagination/</feedburner:origLink><title>Spring Data Solr Tutorial: Pagination</title><link>http://feeds.feedblitz.com/~/41372865/0/petrikainulainen~Spring-Data-Solr-Tutorial-Pagination/</link> <comments>http://feeds.feedblitz.com/~/41372865/0/petrikainulainen~Spring-Data-Solr-Tutorial-Pagination/#comments</comments> <pubDate>Mon, 20 May 2013 19:24:32 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Solr]]></category> <category><![CDATA[spring data]]></category> <category><![CDATA[spring data solr]]></category> <category><![CDATA[Spring Framework]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=5233</guid> <description><![CDATA[In the earlier parts of my Spring Data Solr tutorial, we have implemented a simple search function which is used to search the information of todo entries. The current implementation of our search function shows all search results in a single page. This is not a viable solution for most real life applications because the [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-pagination/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/filecabinetanddrawer.jpg" alt="File cabinet and drawer" /></a></p><p>In the earlier parts of my <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/spring-data-solr-tutorial/">Spring Data Solr tutorial</a>, we have implemented a simple search function which is used to search the information of todo entries. The current implementation of our search function shows all search results in a single page. This is not a viable solution for most real life applications because the number of search results can be so large that search function is no longer usable.</p><p>This blog post provides us the solution to that problem by describing how we can paginate the query results or our search function with Spring Data Solr.</p><p>This blog post is divided into five sections:</p><ul><li>The first section describes how we can request the correct page manually and talks about the different return types of query methods.</li><li>The second section describes how we can obtain the search result count by adding a custom method to our repository.</li><li>The third section describes how we can paginate the search results of query methods.</li><li>The fourth section teaches us to paginate the search results of dynamic queries.</li><li>The fifth and last section describes how we can configure and use a technique called web pagination.</li></ul><p><strong>Note</strong>: These blog posts provides additional information which helps us to understand the concepts of described in this blog post:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/maven/running-solr-with-maven/">Running Solr with Maven</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/">Spring Data Solr Tutorial: Introduction to Solr</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/">Spring Data Solr Tutorial: Configuration</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/">Spring Data Solr Tutorial: Query Methods</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/">Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/">Spring Data Solr Tutorial: Dynamic Queries</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/">Spring Data Solr Tutorial: Sorting</a></li></ul><p>Let&#8217;s get started.</p><h2>Few Minutes of Theory</h2><p>Before we will start making modifications to our example application, we will take a short look at the theory behind pagination. This section is divided in two subsections which are described in the following:</p><ul><li>The first section describes how we can specify the pagination options of our query.</li><li>The second section describes the different return types of a query method.</li></ul><p>Let&#8217;s move on.</p><h3>Specifying the Wanted Page</h3><p>The used pagination options are specified by using the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-commons/docs/current/api/org/springframework/data/domain/PageRequest.html" target="_blank"><em>PageRequest</em></a> class which implements the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-commons/docs/current/api/org/springframework/data/domain/Pageable.html" target="_blank"><em>Pageable</em></a> interface.</p><p>The typical pagination requirements are given in the following:</p><ul><li>Get the query results belonging to a single page.</li><li>Get the query results belonging to a single page when the query results are sorted by using the value of a single field.</li><li>Get the query results belonging to a single page when the query results are sorted by using the values of multiple fields and the sort order of different fields is the same.</li><li>Get the query results belonging to a single page when the query results are sorted by using the values of multiple fields and the sort order of different fields is not the same.</li></ul><p>Let&#8217;s find out how we can create the <em>PageRequest</em> objects which fulfill the given requirements.</p><p>First, we must create a <em>PageRequest</em> object which specifies that we want to get the query results belonging to a single page. We can create the <em>PageRequest</em> object by using the following code:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//Get the query results belonging to the first page when page size is 10.</span>
<br> <span style="color: #000000; font-weight: bold;">new</span> PageRequest<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span></div></div><p>Second, we must create a <em>PageRequest</em> object which specifies that we want to get the results belonging to a single page when query results are sorted by using the value of a single field. We can create the <em>PageRequest</em> object by using the following code:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//Gets the query results belonging to the first page when page size is 10.</span>
<br> <span style="color: #666666; font-style: italic;">//Query results are sorted in descending order by using id field.</span>
<br> <span style="color: #000000; font-weight: bold;">new</span> PageRequest<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">10</span> Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">DESC</span>, <span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span></div></div><p>Third, we must create a <em>PageRequest</em> object which specifies that we want to get the results belonging to a single page when the query results are sorted by using multiple fields and the sort order of different fields is same. We can create the <em>PageRequest</em> object by using the following code:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//Gets the query results belonging to the first page when page size is 10.</span>
<br> <span style="color: #666666; font-style: italic;">//Query results are sorted in descending order by using id and description fields.</span>
<br> <span style="color: #000000; font-weight: bold;">new</span> PageRequest<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">10</span> Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">DESC</span>, <span style="color: #0000ff;">&quot;id&quot;</span>, <span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span></div></div><p>Fourth, we must create a <em>PageRequest</em> object which specifies that want to get the query results belonging to a single page when the query results are sorted by using multiple fields and the sort order of different fields is not same. We can create this object by using the following code:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//Gets the query results belonging to the first page when page size is 10.</span>
<br> <span style="color: #666666; font-style: italic;">//Query results are sorted in descending order order by using the description field</span>
<br> <span style="color: #666666; font-style: italic;">//and in ascending order by using the id field.</span>
<br> Sort sort <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">DESC</span>, <span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">and</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">ASC</span>, <span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> <span style="color: #000000; font-weight: bold;">new</span> PageRequest<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">10</span>, sort<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div><p>We now know how we can create new <em>PageRequest</em> objects. Let&#8217;s move on and talk about the different return types of query methods.</p><h3>Deciding the Return Type of a Query Method</h3><p>When a query method uses pagination, it can have two return types. These return types are described in the following (We will assume that the name of our model class is <em>TodoDocument</em>):</p><ul><li>When we are interested about the pagination metadata, the return type of our query method must be <em>Page&lt;TodoDocument&gt;</em> (Get more information about the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-commons/docs/current/api/org/springframework/data/domain/Page.html" target="_blank"><em>Page</em></a> interface which declares the methods used to obtain the pagination metadata).</li><li>When we are not interested about the pagination metadata, the return type of our query method should be <em>List&lt;TodoDocument&gt;</em>.</li></ul><h2>Getting the Search Result Count</h2><p>Before we can start paginating the search results of our queries, we have to implement a function which is used to get the number of todo entries which matches with given search criteria. This number is required so that we can implement the pagination logic to the frontend.</p><p>We can implement this function by following these steps:</p><ol><li>Add a custom method to our repository. This method is used to return the search result count.</li><li>Create a new service method which uses our custom repository method.</li></ol><p>These steps are described with more details in the following subsections.</p><h3>Adding a Custom Method to Our Repository</h3><p>At the moment it is not possible to create a count query without <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/">adding a custom method to a repository</a>. We can do this by following these steps:</p><ol><li>Create a custom repository interface.</li><li>Implement the custom repository interface.</li><li>Modify the actual repository interface.</li></ol><p>Let&#8217;s move on and find out how this is done.</p><h4>Creating a Custom Repository Interface</h4><p>We can create a custom repository interface by following these steps:</p><ol><li>Create an interface called <em>CustomTodoDocumentRepository</em>.</li><li>Add a <em>count()</em> method to the created interface. This method takes the used search term as a method parameter.</li></ol><p>The source code of the <em>CustomTodoDocumentRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> CustomTodoDocumentRepository <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">long</span> count<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Implementing the Custom Repository Interface</h4><p>We can implement the custom repository interface by following these steps:</p><ol><li>Create a class called <em>TodoDocumentRepositoryImpl</em> and implement the <em>CustomTodoDocumentRepository</em> interface.</li><li>Annotate the class with the <em>@Repository</em> annotation.</li><li>Add <em>SolrTemplate</em> field to the class and annotate the field with the <em>@Resource</em> annotation.</li><li>Implement the <em>count()</em> method.</li></ol><p>Let&#8217;s take a closer look at the implementation of the <em>count()</em> method. We can implement this method by following these steps:</p><ol><li>Get words of the given search term.</li><li>Construct the used search criteria by calling the private <em>constructSearchConditions()</em> method and pass the words of the search term as a method parameter.</li><li>Create the executed query by creating a new <em>SimpleQuery</em> object and pass the created <em>Criteria</em> object as a constructor parameter.</li><li>Get the search result count by calling the <em>count()</em> method of the <em>SolrTemplate</em> class and pass the created <em>SimpleQuery</em> object as a method parameter.</li><li>Return the search result count.</li></ol><p>The source code of the <em>TodoDocumentRepositoryImpl</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:765px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.SolrTemplate</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.query.Criteria</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.query.SimpleQuery</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Repository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @<span style="color: #003399;">Repository</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TodoDocumentRepositoryImpl <span style="color: #000000; font-weight: bold;">implements</span> CustomTodoDocumentRepository <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> SolrTemplate solrTemplate<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">long</span> count<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> words <span style="color: #339933;">=</span> searchTerm.<span style="color: #006633;">split</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot; &quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; Criteria conditions <span style="color: #339933;">=</span> createSearchConditions<span style="color: #009900;">&#40;</span>words<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; SimpleQuery countQuery <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SimpleQuery<span style="color: #009900;">&#40;</span>conditions<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> solrTemplate.<span style="color: #006633;">count</span><span style="color: #009900;">&#40;</span>countQuery<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Criteria createSearchConditions<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> words<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; Criteria conditions <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> word<span style="color: #339933;">:</span> words<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>conditions <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conditions <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;title&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conditions <span style="color: #339933;">=</span> conditions.<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;title&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> conditions<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Modifying the Actual Repository Interface</h4><p>We can make the custom <em>count()</em> method visible to the users of our repository by extending the <em>CustomTodoRepositoryInterface</em>. The source code of the <em>TodoDocumentRepository</em> looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> CustomTodoRepository, SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Repository methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Using the Custom Repository Method</h3><p>We can use the created repository method by following these steps:</p><ol><li>Modify the <em>TodoIndexService</em> interface.</li><li>Implement the modified interface.</li></ol><p>These steps are described with more details in the following.</p><p><strong>Note</strong>: We have to make other changes as well but I will not describe these changes here since they are not related to Spring Data Solr.</p><h4>Modifying the Service Interface</h4><p>We have to modify the <em>TodoIndexService</em> interface by adding a new <em>countSearchResults()</em> method to it. This method takes the used search term as a method parameter and returns the search result count. The source code of the <em>TodoIndexService</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">long</span> countSearchResults<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Implementing the Modified Interface</h4><p>We can implement the <em>countSearchResults()</em> method by following these steps:</p><ol><li>Add the <em>countSearchResults()</em> method to the <em>RepositoryTodoIndexService</em> class.</li><li>Obtain the search result count by calling the custom repository method and return the search result count.</li></ol><p>The relevant part of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.ArrayList</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">long</span> countSearchResults<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">count</span><span style="color: #009900;">&#40;</span>searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Paginate the Query Results of Query Methods</h2><p>When we are creating our queries by using query methods, we can paginate the query results by following these steps:</p><ol><li>Add a new <em>Pageable</em> parameter to the query method. This parameter specifies the details of the fetched page.</li><li>Modify the service layer by adding a new <em>Pageable</em> parameter to the <em>search()</em> method of the <em>TodoIndexService</em> interface.</li></ol><p>Let&#8217;s get started.</p><h3>Modifying the Repository Interface</h3><p>We can add pagination support to our repository by adding a <em>Pageable</em> parameter to the query method which is used to build the executed query. Let&#8217;s take a look at the declarations of our query methods.</p><h4>Query Generation from Method Name</h4><p>When the executed query is created by using the query generation from method name strategy, we have to add a <em>Pageable</em> parameter to the <em>findByTitleContainsOrDescriptionContains()</em> method of the <em>TodoDocumentRepository</em> interface. These source code of our repository interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> CustomTodoDocumentRepository, SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> findByTitleContainsOrDescriptionContains<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> title, <span style="color: #003399;">String</span> description, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Named Queries</h4><p>When are using named queries, we have to add a <em>Pageable</em> parameter to the <em>findByNamedQuery()</em> method of the <em>TodoDocumentRepository</em> interface. The source code of the <em>TodoDocumentRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.Query</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> CustomTodoDocumentRepository, SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Query<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;TodoDocument.findByNamedQuery&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> findByNamedQuery<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>@Query Annotation</h4><p>When the executed query is created by using the <em>@Query</em> annotation, we have to add a <em>Pageable</em> parameter to the <em>findByQueryAnnotation()</em> method of the <em>TodoDocumentRepository</em> interface. The source code of our repository interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.Query</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> CustomTodoDocumentRepository, SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Query<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;title:*?0* OR description:*?0*&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> findByQueryAnnotation<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Modifying the Service Layer</h3><p>We have to the following modifications to the service layer of our example application:</p><ol><li>Add a Pageable parameter to the <em>search()</em> method of the <em>TodoIndexService</em> interface.<li>Implement the new search() method.</li></ol><p><strong>Note</strong>: We have to make other changes as well but I will not describe these changes here since they are not related to Spring Data Solr.</p><p>The source code of the <em>TodoIndexService</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p>We can use the modified query methods by making the following changes to the <em>search()</em> method of the <em>RepositoryIndexService</em> class:</p><ol><li>Get the paginated query results by calling the query method of our repository and pass the used search term and the <em>Pageable</em> object as method parameters.</li><li>Return the query results.</li></ol><p>Let&#8217;s move and take a look at different implementations of the <em>search()</em> method.</p><h4>Query Generation from Method Name</h4><p>When we are building our queries by using the query generation from method name strategy, we can get query results belonging to a specific page by using the <em>findByTitleContainsOrDescriptionContains()</em> method of the <em>TodoDocumentRepository</em> interface.</p><p>The relevant part of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:450px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.beans.factory.annotation.Value</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.ArrayList</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">findByTitleContainsOrDescriptionContains</span><span style="color: #009900;">&#40;</span>searchTerm, searchTerm, page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Named Queries</h4><p>When we are using named query for building the executed query, we can get the search results belonging to a specific page by using the <em>findByNamedQuery()</em> method of the <em>TodoDocumentRepository</em> interface.</p><p>The relevant part of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:450px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.beans.factory.annotation.Value</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.ArrayList</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">findByNamedQuery</span><span style="color: #009900;">&#40;</span>searchTerm, page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>@Query Annotation</h4><p>When we are building our query by using the <em>@Query</em> annotation, we can get the search results which belongs to a specific page by calling the <em>findByQueryAnnotation()</em> method of the <em>TodoDocumentRepository</em> interface.</p><p>The source code of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:450px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.beans.factory.annotation.Value</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.ArrayList</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">findByQueryAnnotation</span><span style="color: #009900;">&#40;</span>searchTerm, page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Paginating the Query Results of Dynamic Queries</h2><p>We can paginate the query results of dynamic queries by following these steps:</p><ol><li>Add a Pageable parameter to the <em>search()</em> method of our custom repository.</li><li>Modify the service layer by adding a <em>Pageable</em> parameter to the search() method of the <em>TodoIndexService</em> interface.</li></ol><p>These steps are described with more details in the following subsections.</p><h3>Changing the Custom Repository</h3><p>We have to add pagination support to our custom repository. We can do this by following these steps:</p><ol><li>Modify the custom repository interface by adding a <em>Pageable</em> parameter to its <em>search()</em> method.</li><li>Change the implementation of the <em>search()</em> method by adding pagination support to it.</li></ol><p>Let&#8217;s move on and find out how this is done.</p><h4>Changing the Custom Repository Interface</h4><p>We have to add a <em>Pageable</em> parameter to the <em>search()</em> method declared in the <em>CustomTodoDocumentRepository</em> interface. The source code of our custom repository interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> CustomTodoDocumentRepository <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Implementing the Custom Repository Method</h4><p>Our next step is to add pagination support to the implementation of the <em>search()</em> method. We can implement the <em>search()</em> method of the <em>TodoDocumentRepositoryImpl</em> class by following these steps:</p><ol><li>Get the words of the search term.</li><li>Construct the used search criteria by calling the private <em>createSearchConditions()</em> method and passing the words of the search term as a method parameter.</li><li>Create the executed query by creating a new <em>SimpleQuery</em> object and pass the created <em>Criteria</em> object as a constructor parameter.</li><li>Set the pagination options of the query by calling the <em>setPageRequest()</em> method of the <em>SimpleQuery</em> class. Pass the <em>Pageable</em> object as a method parameter.</li><li>Get the search results by calling the <em>queryForPage()</em> method of the <em>SolrTemplate</em> class. Pass the created query and the type of the expected return objects as method parameters.</li><li>Return the search results by calling the <em>getContent()</em> method of the <em>Page</em> interface.</li></ol><p>The source code of the <em>TodoDocumentRepositoryImpl</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:900px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Page</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.SolrTemplate</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.query.Criteria</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.query.SimpleQuery</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Repository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.ArrayList</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @<span style="color: #003399;">Repository</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TodoDocumentRepositoryImpl <span style="color: #000000; font-weight: bold;">implements</span> CustomTodoDocumentRepository <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> SolrTemplate solrTemplate<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> words <span style="color: #339933;">=</span> searchTerm.<span style="color: #006633;">split</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot; &quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; Criteria conditions <span style="color: #339933;">=</span> createSearchConditions<span style="color: #009900;">&#40;</span>words<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; SimpleQuery search <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SimpleQuery<span style="color: #009900;">&#40;</span>conditions<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; search.<span style="color: #006633;">setPageRequest</span><span style="color: #009900;">&#40;</span>page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; Page results <span style="color: #339933;">=</span> solrTemplate.<span style="color: #006633;">queryForPage</span><span style="color: #009900;">&#40;</span>search, TodoDocument.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> results.<span style="color: #006633;">getContent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Criteria createSearchConditions<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> words<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; Criteria conditions <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> word<span style="color: #339933;">:</span> words<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>conditions <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conditions <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;title&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conditions <span style="color: #339933;">=</span> conditions.<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;title&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> conditions<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Using the Custom Repository</h3><p>Before we can use the modified repository method, we have to make the following changes to the service layer of our example application:</p><ol><li>Add a <em>Pageable</em> parameter to the <em>search()</em> method of the <em>TodoIndexService</em> interface.</li><li>Implement the <em>search()</em> method.</li></ol><p>These steps are described with more details in following.</p><p><strong>Note</strong>: We have to make other changes as well but I will not describe these changes here since they are not related to Spring Data Solr.</p><h4>Modifying the Service Interface</h4><p>We have to add a <em>Pageable</em> parameter to the <em>search()</em> method of the <em>TodoIndexService</em> interface. The source code of the <em>TodoIndexService</em> looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Implementing the Service Interface</h4><p>When we are building our by using the criteria API of Spring Data Solr, we can get the query results by calling the <em>search()</em> method of our custom repository and passing the user search term and the <em>Pageable</em> object as method parameters.</p><p>The source code of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">search</span><span style="color: #009900;">&#40;</span>searchTerm, page<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Using Web Pagination</h2><p>One question is still left unanswered. That is question is:</p><blockquote><p>Where the pagination options used to paginate the query results of our queries are specified?</p></blockquote><p>We will create the pagination options of our queries by using a technique called <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/reference/htmlsingle/#web-pagination" target="_blank">web pagination</a>. This technique is based on a custom argument resolver class called <em>PageableArgumentResolver</em>. This class parses pagination information from HTTP request and makes it possible to add a <em>Pageable</em> method parameter to controller methods.</p><p>This section describes how we can configure and use this technique in our example application. It is divided into three subsections:</p><ul><li>The first subsection describes how we can configure the <em>PageableArgumentResolver</em> class.</li><li>The second subsection describes how we can use it.</li><li>The last subsection talks about the pros and cons of web pagination.</li></ul><p>Let&#8217;s find out how we can use this technique in our example application.</p><h3>Configuration</h3><p>This subsection describes how we can configure the <em>PageableArgumentResolver</em> class which is to used extract pagination options from HTTP requests. Let&#8217;s find out how we do this by using Java configuration and XML configuration.</p><h4>Java Configuration</h4><p>We can add a custom argument argument resolver by making the following changes to the <em>ExampleApplicationContext</em> class:</p><ol><li>Override the <em>addArgumentResolvers()</em> method of the <em>WebMvcConfigurerAdapter</em> class.</li><li>Implement the <em>addArgumentResolvers()</em> method by creating new <em>PageableArgumentResolver</em> object and adding the created object to the list of argument resolvers which is given as a method parameter.</li></ol><p>The relevant part of the <em>ExampleApplicationContext</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.web.PageableArgumentResolver</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.method.support.HandlerMethodArgumentResolver</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.servlet.mvc.method.annotation.ServletWebArgumentResolverAdapter</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #666666; font-style: italic;">//Annotations are omitted.</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ExampleApplicationContext <span style="color: #000000; font-weight: bold;">extends</span> WebMvcConfigurerAdapter <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> addArgumentResolvers<span style="color: #009900;">&#40;</span>List<span style="color: #339933;">&lt;</span>HandlerMethodArgumentResolver<span style="color: #339933;">&gt;</span> argumentResolvers<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; PageableArgumentResolver pageableArgumentResolver <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PageableArgumentResolver<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; argumentResolvers.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> ServletWebArgumentResolverAdapter<span style="color: #009900;">&#40;</span>pageableArgumentResolver<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>XML Configuration</h4><p>We can configure a custom argument resolver by making the following changes to the <em>exampleApplicationContext.xml</em> file:</p><ol><li>Use the <em>argument-resolvers</em> element of the <em>mvc</em> namespace for configuring the custom argument resolvers.</li><li>Configure the <em>PageableArgumentResolver</em> bean inside the <em>argument-resolvers</em> element.</li></ol><p>The relevant part of the <em>exampleApplicationContext.xml</em> file looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;beans</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:mvc</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/mvc&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:context</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/context&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;mvc:annotation-driven<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;mvc:argument-resolvers<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bean</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;pageagleArgumentResolver&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.springframework.data.web.PageableArgumentResolver&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/mvc:argument-resolvers<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/mvc:annotation-driven<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configuration is omitted. --&gt;</span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/beans<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><h3>Usage</h3><p>After we have configured the <em>PageableArgumentResolver</em> class by using one of methods which were described earlier, we can add <em>Pageable</em> method parameters to our controller methods. The <em>search()</em> method the <em>TodoController</em> class is a good example of this. The relevant part of its source code looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Pageable</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Controller</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.web.bind.annotation.*</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Controller
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TodoController <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Fields are omitted.</span>
<br> 
<br> &nbsp; &nbsp; @RequestMapping<span style="color: #009900;">&#40;</span>value <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;/api/todo/search/{searchTerm}&quot;</span>, method <span style="color: #339933;">=</span> RequestMethod.<span style="color: #006633;">GET</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @ResponseBody
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDTO<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span>@PathVariable<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;searchTerm&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #003399;">String</span> searchTerm, <span style="color: #003399;">Pageable</span> page<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Implementation is omitted.</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p>However, adding the <em>Pageable</em> argument to the controller method is not enough. We still have to add the pagination options to the HTTP request. This is done by adding special request parameters to the request. These request parameters are described in the following:</p><ul><li>The <em>page.page</em> request parameter specifies the requested page.</li><li>The <em>page.size</em> request parameter specifies the page size.</li><li>The <em>page.sort</em> request parameter specifies the property which is used to sort the query results.</li><li>The <em>page.sort.dir</em> request parameter specifies the sort order.</li></ul><p>Let&#8217;s spend a moment and think about the pros and cons of web pagination.</p><h3>Pros and Cons</h3><p>The web pagination has both pros and cons which we should be aware of before making the decision to use it in our applications.  Let&#8217;s find out what these are.</p><h4>Pros</h4><p>Using web pagination has one major benefit:</p><p>It is an easy and simple to transfer pagination options from the web layer to the repository layer. All we have to do is to configure a custom argument resolver, add a <em>Pageable</em> parameter to a controller method and send the pagination options by using specific request parameters. This is a lot simpler than processing pagination options in our code and manually creating a <em>PageRequest</em> object.</p><h4>Cons</h4><p>The cons of using web pagination are described in the following:</p><ul><li>Web pagination creates a dependency between the web layer and Spring Data. This means that the implementation details of the repository layer leaks into to the upper layers of our application. Although purists will probably claim that this is huge mistake, I don&#8217;t share their opinion. I think that abstractions should make our life easier, not harder. We must also remember that <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.joelonsoftware.com/articles/LeakyAbstractions.html" target="_blank">the law of leaky abstractions</a> states that all-non trivial abstractions, to some degree, are leaky.</li><li>One real disadvantage of web pagination is that we can use it only if our search results are sorted by using a single field. Although this is perfectly fine for most use cases, there are situations when this becomes a problem. If this happens, we have to process pagination options manually.</li></ul><h2>Summary</h2><p>We have now added the pagination of search results to our example application. This tutorial has taught us the following things:</p><ul><li>We learned to create new <em>PageRequest</em> objects.</li><li>We learned that we can select the return type of our query method from two different options.</li><li>We learned to paginate the query results of query methods and dynamic queries.</li><li>We know how we can use web pagination, and we are aware of its pros and cons.</li></ul><p>The next part of my Spring Data Solr Tutorial describes how we can add custom methods to all Spring Data Solr repositories.</p><p>P.S. The example applications of this blog post are available at Github (<a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/query-methods-pagination" target="_blank">query methods</a> and <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/criteria-pagination" target="_blank">dynamic queries</a>).</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/41372865/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/41372865/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/41372865/0/petrikainulainen~Spring-Data-Solr-Tutorial-Pagination/feed/</wfw:commentRss> <slash:comments>0</slash:comments></item>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-write-clean-assertions-with-jsonpath/</feedburner:origLink><title>Integration Testing of Spring MVC Applications: Write Clean Assertions with JsonPath</title><link>http://feeds.feedblitz.com/~/41231345/0/petrikainulainen~Integration-Testing-of-Spring-MVC-Applications-Write-Clean-Assertions-with-JsonPath/</link> <comments>http://feeds.feedblitz.com/~/41231345/0/petrikainulainen~Integration-Testing-of-Spring-MVC-Applications-Write-Clean-Assertions-with-JsonPath/#comments</comments> <pubDate>Thu, 16 May 2013 19:56:58 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Spring Framework]]></category> <category><![CDATA[Integration Testing]]></category> <category><![CDATA[Spring MVC]]></category> <category><![CDATA[spring-test-mvc]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=5175</guid> <description><![CDATA[The previous parts of my Spring MVC Test tutorial have described how we can write integration tests for a REST API. Although the techniques described in those blog posts are useful, the problem is that our assertions were not very elegant. Our assertions were basically ensuring that the body of the HTTP response contained the [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-migrating-to-spring-3-2/&quot;&gt;Integration Testing of Spring MVC Applications: Migrating to Spring 3.2&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-security/&quot;&gt;Integration Testing of Spring MVC Applications: Security&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-rest-api-part-two/&quot;&gt;Integration Testing of Spring MVC Applications: REST API, Part Two&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-write-clean-assertions-with-jsonpath/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/labyrinth_on_blackboard.jpg" alt="Labyrinth on a blackboard" /></a></p><p>The previous parts of my <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/spring-mvc-test-tutorial/">Spring MVC Test tutorial</a> have described how we can write integration tests for a REST API. Although the techniques described in those blog posts are useful, the problem is that our assertions were not very elegant. Our assertions were basically ensuring that the body of the HTTP response contained the &#8220;right&#8221; strings.</p><p>This approach has two problems:</p><ul><li>It is not very readable, especially if the returned JSON is large. Since our tests should act as a documentation for our code, this is a huge problem.</li><li>It is very hard to write tests which ensure that the ordering of collections is correct without sacrificing readability.</li></ul><p>Luckily for us, there is a better way to do this. <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~goessner.net/articles/JsonPath/" target="_blank">JsonPath</a> is to JSON what XPath is to XML. It provides an easy and readable way to extract parts of a JSON document. This blog post describes how we can write assertions by using the Spring MVC Test and the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~code.google.com/p/json-path/" target="_blank">Java implementation of JsonPath</a>.</p><p><strong>Note</strong>: These blog posts describe the structure of our example application and teaches us to write integration tests to it without using the JsonPath library (This blog post skips the details described in these blog posts):</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-rest-api-part-one/">Integration Testing of Spring MVC Applications: REST API, Part One</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-rest-api-part-two/">Integration Testing of Spring MVC Applications: REST API, Part Two</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-security/">Integration Testing of Spring MVC Applications: Security</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-migrating-to-spring-3-2/">Integration Testing of Spring MVC Applications: Migrating to Spring 3.2</a></li></ul><p>Let&#8217;s get started and find out how we can get the required dependencies with Maven.</p><h2>Getting Required Dependencies with Maven</h2><p>We can get the required dependencies with Maven by following these steps:</p><ol><li>Declare the Hamcrest dependency (version 1.3) in the <em>pom.xml</em> file.</li><li>Declare the JUnit dependency (version 4.11) in the <em>pom.xml</em> file and exclude the hamcrest dependencies.</li><li>Declare the Spring Test (version 3.2.2.RELEASE) dependency in the <em>pom.xml</em> file.</li><li>Add JsonPath dependencies (version 0.8.1) to the <em>pom.xml file</em>.</li></ol><p>The relevant dependency declarations looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:665px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.hamcrest<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>hamcrest-all<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1.3<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>junit<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>junit<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>4.11<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;exclusions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;exclusion<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>hamcrest-core<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.hamcrest<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/exclusion<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/exclusions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.springframework<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>spring-test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>3.2.2.RELEASE<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>com.jayway.jsonpath<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>json-path<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>0.8.1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>com.jayway.jsonpath<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>json-path-assert<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>0.8.1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>test<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/scope<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><p>Let&#8217;s move and find out how we can write assertions by using JsonPath.</p><h2>Writing Integration Tests</h2><p>We can write integration tests by executing the tested operation and making assertions against the returned JSON document. We can create a new assertion by following these steps:</p><ol><li>Create a JsonPath expession which fetches the preferred part from the returned JSON document (<a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~goessner.net/articles/JsonPath/" target="_blank">Get more information about the JsonPath notation</a>).</li><li>Make an assertion against the fetched part by using a Hamcrest matcher.</li><li>Use the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/test/web/servlet/result/MockMvcResultMatchers.html#jsonPath%28java.lang.String,%20java.lang.Object...%29" target="_blank">jsonPath() method of MockMvcResultMatchers class</a> to verify that the assertion is true and pass the objects created in phases one and two as method parameters.</li></ol><p>Enough with theory. Let’s move on and find out how we can write assertions against JSON documents. The following subsections describe how we can write assertions against JSON documents which contains either the information of a single object or the information of multiple objects.</p><h3>Single Object</h3><p>This subsection describes how we can ensure that the JSON document which contains the information of a single object is correct. As an example we will write an integration test for a controller method which is used to delete the information of an existing todo entry. After the todo entry has been deleted successfully, its information is returned back to the client. The returned JSON looks as follows:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">{
<br> &nbsp; &nbsp; &quot;id&quot;:1,
<br> &nbsp; &nbsp; &quot;description&quot;:&quot;Lorem ipsum&quot;,
<br> &nbsp; &nbsp; &quot;title&quot;:&quot;Foo&quot;
<br> }</div></div><p>We can write the integration test by following these steps:</p><ol><li>Use the <em>@ExpectedDatabase</em> annotation to ensure that the todo entry is deleted.</li><li>Perform a DELETE request to url &#8216;/api/todo/1&#8242;. Set the logged in user.</li><li>Verify that the returned HTTP status code is 200.</li><li>Verify that the content type of the response is &#8216;application/json&#8217; and its character set is &#8216;UTF-8&#8242;.</li><li>Get the id of the deleted todo entry by using the JsonPath expression <em>$.id</em> and verify that the id is 1.</li><li>Get the description of the deleted todo entry by using the JsonPath expression <em>$.description</em> and verify that the description is is &#8220;Lorem ipsum&#8221;.</li><li>Get the title of the deleted todo entry by using the JsonPath expression <em>$.title</em> and verify that the title is &#8220;Foo&#8221;.</li></ol><p>The source code of our integration test looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:920px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.github.springtestdbunit.DbUnitTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.github.springtestdbunit.annotation.DatabaseSetup</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.github.springtestdbunit.annotation.ExpectedDatabase</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.Test</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.runner.RunWith</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.ContextConfiguration</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.TestExecutionListeners</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.junit4.SpringJUnit4ClassRunner</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.support.DependencyInjectionTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.support.DirtiesContextTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.transaction.TransactionalTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.web.server.MockMvc</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.web.server.samples.context.WebContextLoader</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">hamcrest</span>.<span style="color: #006633;">Matchers</span>.<span style="color: #339933;">*;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">samples</span>.<span style="color: #006633;">context</span>.<span style="color: #006633;">SecurityRequestPostProcessors</span>.<span style="color: #006633;">userDetailsService</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">request</span>.<span style="color: #006633;">MockMvcRequestBuilders</span>.<span style="color: #339933;">*;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">result</span>.<span style="color: #006633;">MockMvcResultMatchers</span>.<span style="color: #006633;">content</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">servlet</span>.<span style="color: #006633;">result</span>.<span style="color: #006633;">MockMvcResultMatchers</span>.<span style="color: #006633;">jsonPath</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">result</span>.<span style="color: #006633;">MockMvcResultMatchers</span>.<span style="color: #006633;">status</span><span style="color: #339933;">;</span>
<br> 
<br> @RunWith<span style="color: #009900;">&#40;</span>SpringJUnit4ClassRunner.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>
<br> @ContextConfiguration<span style="color: #009900;">&#40;</span>loader <span style="color: #339933;">=</span> WebContextLoader.<span style="color: #000000; font-weight: bold;">class</span>, classes <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>ExampleApplicationContext.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<br> @TestExecutionListeners<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>DependencyInjectionTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; DirtiesContextTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; TransactionalTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; DbUnitTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<br> @DatabaseSetup<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;toDoData.xml&quot;</span><span style="color: #009900;">&#41;</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ITTodoControllerTest <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Add data source and web application context here</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> MockMvc mockMvc<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Add setUp() method here</span>
<br> 
<br> &nbsp; &nbsp; @Test
<br> &nbsp; &nbsp; @ExpectedDatabase<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;toDoData-delete-expected.xml&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> deleteById<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; mockMvc.<span style="color: #006633;">perform</span><span style="color: #009900;">&#40;</span>delete<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/api/todo/{id}&quot;</span>, 1L<span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">with</span><span style="color: #009900;">&#40;</span>userDetailsService<span style="color: #009900;">&#40;</span>IntegrationTestUtil.<span style="color: #006633;">CORRECT_USERNAME</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>status<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">isOk</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>content<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">mimeType</span><span style="color: #009900;">&#40;</span>IntegrationTestUtil.<span style="color: #006633;">APPLICATION_JSON_UTF8</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$.id&quot;</span>, is<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$.description&quot;</span>, is<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Lorem ipsum&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$.title&quot;</span>, is<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Foo&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Collection of Objects</h3><p>This subsection describes how we can write assertions which ensure that the JSON document containing a collection of objects is correct. We will take a look at two different situations:</p><ul><li>The objects are always returned in the same order.</li><li>The objects are returned in a random order.</li></ul><p>Let&#8217;s continue our journey.</p><h4>Objects Returned in the Same Order</h4><p>When the user wants to get all todo entries which are stored in the database, the entries are always returned in the same order. The returned JSON looks as follows:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[
<br> &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;id&quot;:1,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;description&quot;:&quot;Lorem ipsum&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;title&quot;:&quot;Foo&quot;
<br> &nbsp; &nbsp; },
<br> &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;id&quot;:2,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;description&quot;:&quot;Lorem ipsum&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;title&quot;:&quot;Bar&quot;
<br> &nbsp; &nbsp; }
<br> ]</div></div><p>We can write our integration test by following these steps:</p><ol><li>Use the <em>@ExpectedDatabase</em> annotation to verify that no changes is made to the database.</li><li>Perform a GET request to url &#8216;/api/todo&#8217;. Set the logged in user.</li><li>Verify that the returned HTTP status code is 200.</li><li>Verify that the content type of the response is &#8216;application/json&#8217; and its character set &#8216;UTF-8&#8242;.</li><li>Fetch the collection of todo entries by using JsonPath expression <em>$</em> and ensure that two todo entries are returned.</li><li>Use the JsonPath expressions <em>$[0].id</em>, <em>$[0].description</em> and <em>$[0].title</em> to get the id, description and title of the first todo entry. Verify that its information is correct.</li><li>Use the JsonPath expressions <em>$[1].id</em>, <em>$[1].description</em> and <em>$[1].title</em> to get the id, description and title of the second todo entry. Verify that its information is correct.</li></ol><p>The source code of our integration test looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:1000px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.github.springtestdbunit.DbUnitTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.github.springtestdbunit.annotation.DatabaseSetup</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.github.springtestdbunit.annotation.ExpectedDatabase</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.Test</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.runner.RunWith</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.ContextConfiguration</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.TestExecutionListeners</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.junit4.SpringJUnit4ClassRunner</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.support.DependencyInjectionTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.support.DirtiesContextTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.transaction.TransactionalTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.web.server.MockMvc</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.web.server.samples.context.WebContextLoader</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">hamcrest</span>.<span style="color: #006633;">Matchers</span>.<span style="color: #339933;">*;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">samples</span>.<span style="color: #006633;">context</span>.<span style="color: #006633;">SecurityRequestPostProcessors</span>.<span style="color: #006633;">userDetailsService</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">request</span>.<span style="color: #006633;">MockMvcRequestBuilders</span>.<span style="color: #339933;">*;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">result</span>.<span style="color: #006633;">MockMvcResultMatchers</span>.<span style="color: #006633;">content</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">servlet</span>.<span style="color: #006633;">result</span>.<span style="color: #006633;">MockMvcResultMatchers</span>.<span style="color: #006633;">jsonPath</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">result</span>.<span style="color: #006633;">MockMvcResultMatchers</span>.<span style="color: #006633;">status</span><span style="color: #339933;">;</span>
<br> 
<br> @RunWith<span style="color: #009900;">&#40;</span>SpringJUnit4ClassRunner.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>
<br> @ContextConfiguration<span style="color: #009900;">&#40;</span>loader <span style="color: #339933;">=</span> WebContextLoader.<span style="color: #000000; font-weight: bold;">class</span>, classes <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>ExampleApplicationContext.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<br> @TestExecutionListeners<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> DependencyInjectionTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; DirtiesContextTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; TransactionalTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; DbUnitTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<br> @DatabaseSetup<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;toDoData.xml&quot;</span><span style="color: #009900;">&#41;</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ITTodoControllerTest <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Add data source and web application context here</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> MockMvc mockMvc<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Add setUp() method here</span>
<br> 
<br> &nbsp; &nbsp; @Test
<br> &nbsp; &nbsp; @ExpectedDatabase<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;toDoData.xml&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> findAll<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; mockMvc.<span style="color: #006633;">perform</span><span style="color: #009900;">&#40;</span>get<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/api/todo&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">with</span><span style="color: #009900;">&#40;</span>userDetailsService<span style="color: #009900;">&#40;</span>IntegrationTestUtil.<span style="color: #006633;">CORRECT_USERNAME</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>status<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">isOk</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>content<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">mimeType</span><span style="color: #009900;">&#40;</span>IntegrationTestUtil.<span style="color: #006633;">APPLICATION_JSON_UTF8</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$&quot;</span>, hasSize<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$[0].id&quot;</span>, is<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$[0].description&quot;</span>, is<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Lorem ipsum&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$[0].title&quot;</span>, is<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Foo&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$[1].id&quot;</span>, is<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$[1].description&quot;</span>, is<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Lorem ipsum&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$[1].title&quot;</span>, is<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Bar&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Objects Returned in a Random Order</h4><p>When a validation of an added or updated todo entry fails, our example application returns the field errors back to the client of our REST API. The problem is that we cannot guarantee the order in which the fields are validated. This means that the field errors are returned in a random order. One JSON document which contains the returned field errors looks as follows:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">{
<br> &nbsp; &nbsp; &quot;fieldErrors&quot;:[
<br> &nbsp; &nbsp; &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;path&quot;:&quot;description&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;message&quot;:&quot;The maximum length of the description is 500 characters.&quot;
<br> &nbsp; &nbsp; &nbsp; &nbsp; },
<br> &nbsp; &nbsp; &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;path&quot;:&quot;title&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;message&quot;:&quot;The maximum length of the title is 100 characters.&quot;
<br> &nbsp; &nbsp; &nbsp; &nbsp; }
<br> &nbsp; &nbsp; ]
<br> }</div></div><p>We can write an write an integration test, which verifies that field errors are returned when a new todo entry which contains invalid information is added, by following these steps:</p><ol><li>Use the <em>@ExpectedDatabase</em> annotation to verify that no changes are made to the database.</li><li>Create the title and description of the todo entry. Ensure that both the title and description are too long.</li><li>Create a new <em>TodoDTO</em> object and set its title and description.</li><li>Perform a POST request to the url &#8216;/api/todo&#8217;. Set the content type of the request to &#8216;application/json&#8217;. Set the character set of the request to &#8216;UTF-8&#8242;.  Transform the created object into a correct format and send it in the body of the request. Set the logged in user.</li><li>Verify that the content type of the response is &#8216;application/json&#8217; and its character set is &#8216;UTF-8&#8242;.</li><li>Fetch the field errors by using the JsonPath expression <em>$.fieldErrors</em> and ensure that two field errors are returned.</li><li>Use the JsonPath expression <em>$.fieldErrors[*].path</em> to fetch all available paths. Ensure that field errors about title and description fields are available.</li><li>Use the JsonPath expression <em>$.fieldErrors[*].message</em> to fetch all available error messages. Ensure that error messages concerning title and description fields are returned.</li></ol><p>The source code of our integration test looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:1090px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.github.springtestdbunit.DbUnitTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.github.springtestdbunit.annotation.DatabaseSetup</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">com.github.springtestdbunit.annotation.ExpectedDatabase</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.Test</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.junit.runner.RunWith</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.ContextConfiguration</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.TestExecutionListeners</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.junit4.SpringJUnit4ClassRunner</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.support.DependencyInjectionTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.support.DirtiesContextTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.context.transaction.TransactionalTestExecutionListener</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.web.server.MockMvc</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.test.web.server.samples.context.WebContextLoader</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">hamcrest</span>.<span style="color: #006633;">Matchers</span>.<span style="color: #339933;">*;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">samples</span>.<span style="color: #006633;">context</span>.<span style="color: #006633;">SecurityRequestPostProcessors</span>.<span style="color: #006633;">userDetailsService</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">request</span>.<span style="color: #006633;">MockMvcRequestBuilders</span>.<span style="color: #339933;">*;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">result</span>.<span style="color: #006633;">MockMvcResultMatchers</span>.<span style="color: #006633;">content</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">servlet</span>.<span style="color: #006633;">result</span>.<span style="color: #006633;">MockMvcResultMatchers</span>.<span style="color: #006633;">jsonPath</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">springframework</span>.<span style="color: #006633;">test</span>.<span style="color: #006633;">web</span>.<span style="color: #006633;">server</span>.<span style="color: #006633;">result</span>.<span style="color: #006633;">MockMvcResultMatchers</span>.<span style="color: #006633;">status</span><span style="color: #339933;">;</span>
<br> 
<br> @RunWith<span style="color: #009900;">&#40;</span>SpringJUnit4ClassRunner.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>
<br> @ContextConfiguration<span style="color: #009900;">&#40;</span>loader <span style="color: #339933;">=</span> WebContextLoader.<span style="color: #000000; font-weight: bold;">class</span>, classes <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>ExampleApplicationContext.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<br> @TestExecutionListeners<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>DependencyInjectionTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; DirtiesContextTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; TransactionalTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; DbUnitTestExecutionListener.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<br> @DatabaseSetup<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;toDoData.xml&quot;</span><span style="color: #009900;">&#41;</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ITTodoControllerTest <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Add data source and web application context here</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> MockMvc mockMvc<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Add setUp() method here</span>
<br> 
<br> &nbsp; &nbsp; @Test
<br> &nbsp; &nbsp; @ExpectedDatabase<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;toDoData.xml&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> addTodoWhenTitleAndDescriptionAreTooLong<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> title <span style="color: #339933;">=</span> TodoTestUtil.<span style="color: #006633;">createStringWithLength</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">101</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span> description <span style="color: #339933;">=</span> TodoTestUtil.<span style="color: #006633;">createStringWithLength</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">501</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; TodoDTO added <span style="color: #339933;">=</span> TodoTestUtil.<span style="color: #006633;">createDTO</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">null</span>, description, title<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; mockMvc.<span style="color: #006633;">perform</span><span style="color: #009900;">&#40;</span>post<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/api/todo&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">contentType</span><span style="color: #009900;">&#40;</span>IntegrationTestUtil.<span style="color: #006633;">APPLICATION_JSON_UTF8</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">body</span><span style="color: #009900;">&#40;</span>IntegrationTestUtil.<span style="color: #006633;">convertObjectToJsonBytes</span><span style="color: #009900;">&#40;</span>added<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">with</span><span style="color: #009900;">&#40;</span>userDetailsService<span style="color: #009900;">&#40;</span>IntegrationTestUtil.<span style="color: #006633;">CORRECT_USERNAME</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>status<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">isBadRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>content<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">mimeType</span><span style="color: #009900;">&#40;</span>IntegrationTestUtil.<span style="color: #006633;">APPLICATION_JSON_UTF8</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$.fieldErrors&quot;</span>, hasSize<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$.fieldErrors[*].path&quot;</span>, containsInAnyOrder<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;title&quot;</span>, <span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">andExpect</span><span style="color: #009900;">&#40;</span>jsonPath<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;$.fieldErrors[*].message&quot;</span>, containsInAnyOrder<span style="color: #009900;">&#40;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">&quot;The maximum length of the description is 500 characters.&quot;</span>,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">&quot;The maximum length of the title is 100 characters.&quot;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Summary</h2><p>We have now written integration tests to a REST API by using Spring MVC Test and JsonPath. This blog post has taught us four things:</p><ul><li>We learned how we can get the required JsonPath dependencies with Maven.</li><li>We learned how we can write assertions against the JSON representation of a single object.</li><li>We learned how we can write assertions against the JSON representation of a collection of objects.</li><li>We learned that writing assertions with JsonPath improves the readability of our tests.</li></ul><p>The example application of this blog post is available at <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-mvc-test-examples/tree/master/rest-jsonpath" target="_blank">Github</a>.</p><p>P.S. You might want to read the other parts of my <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/spring-mvc-test-tutorial/">Spring MVC Test tutorial</a>.</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/41231345/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/41231345/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-migrating-to-spring-3-2/&quot;&gt;Integration Testing of Spring MVC Applications: Migrating to Spring 3.2&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-security/&quot;&gt;Integration Testing of Spring MVC Applications: Security&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-rest-api-part-two/&quot;&gt;Integration Testing of Spring MVC Applications: REST API, Part Two&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/41231345/0/petrikainulainen~Integration-Testing-of-Spring-MVC-Applications-Write-Clean-Assertions-with-JsonPath/feed/</wfw:commentRss> <slash:comments>0</slash:comments></item>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/</feedburner:origLink><title>Spring Data Solr Tutorial: Sorting</title><link>http://feeds.feedblitz.com/~/40569905/0/petrikainulainen~Spring-Data-Solr-Tutorial-Sorting/</link> <comments>http://feeds.feedblitz.com/~/40569905/0/petrikainulainen~Spring-Data-Solr-Tutorial-Sorting/#comments</comments> <pubDate>Sun, 28 Apr 2013 16:06:56 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Solr]]></category> <category><![CDATA[spring data]]></category> <category><![CDATA[spring data solr]]></category> <category><![CDATA[Spring Framework]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=5095</guid> <description><![CDATA[When we are implementing a word search function, we typically want to sort the search results in descending order by using the relevancy of each search result. This is also the default behaviour of Solr. However, there are situations when it makes to sense to specify the sort order manually. One such situation is an [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/&quot;&gt;Spring Data Solr Tutorial: Query Methods&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/sortedcardcatalog.jpg" alt="Sorted card catalog" /></a></p><p>When we are implementing a word search function, we typically want to sort the search results in descending order by using the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/SolrRelevancyFAQ" target="_blank">relevancy of each search result</a>. This is also the default behaviour of Solr.</p><p>However, there are situations when it makes to sense to specify the sort order manually. One such situation is an implementation of a &#8220;regular&#8221; search function which was discussed in the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/">previous part of my Spring Data Solr tutorial</a>.</p><p>This blog post describes how we can sort our query results with Spring Data Solr. To be more specific, we have to modify the search function of our example application to sort the search results in descending order by using the value of the <em>id</em> field.</p><p>This blog post is divided into three sections:</p><ul><li>The first section describes how we can specify the sorting options used in our queries.</li><li>The second section describes how we can sort our query results when we are building our queries by using query methods.</li><li>The third section teaches us to sort the query results of dynamic queries.</li></ul><p>Let&#8217;s get started.</p><p><strong>Note:</strong> These blog posts provide additional information which helps us to understand the concepts described in this blog post:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/maven/running-solr-with-maven/">Running Solr with Maven</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/">Spring Data Solr Tutorial: Introduction to Solr</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/">Spring Data Solr Tutorial: Configuration</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/">Spring Data Solr Tutorial: Query Methods</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/">Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/">Spring Data Solr Tutorial: Dynamic Queries</a></li></ul><h2>Specifying the Sort Options of a Query</h2><p>The sort options of a query are specified by using the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-commons/docs/current/api/org/springframework/data/domain/Sort.html" target="_blank"><em>Sort</em></a> class. The typical requirements for sorting query results are given in the following:</p><ul><li>Sort the query results by using the value of a single field.</li><li>Sort the query results by using the values of multiple fields when the sort order of different fields is the same.</li><li>Sort the query results by using the values of multiple fields when sort order of different fields is not the same.</li></ul><p>Let’s take a look how we can create a <em>Sort</em> object which fulfills the given requirements.</p><p>First, we must create a <em>Sort</em> object which specifies that query results are sorted by using a single field. Lets assume that we want to sort the query results in ascending order by using the <em>id</em> field. We can create the <em>Sort</em> object by using the following code:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">ASC</span>, <span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span></div></div><p>Second, we must create a <em>Sort</em> object which states that query results are sorted by using the values of multiple fields when the sort order of different fields is the same. Lets assume that we have to sort the query results in descending order by using the <em>id</em> and <em>description</em> fields. We can create the <em>Sort</em> object by using the following code:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">DESC</span>, <span style="color: #0000ff;">&quot;id&quot;</span>, <span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span></div></div><p>Third, we want to sort the query results by using the values of multiple fields when the sort order of different fields is not the same. Lets assume that we want to sort the query results in descending order by using the <em>description</em> field and in ascending order by using the <em>id</em> field. We can create the <em>Sort</em> object by using the following code:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">DESC</span>, <span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">and</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">ASC</span>, <span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></div></div><p>We now know how we can create new <em>Sort</em> objects. Let&#8217;s move on and put this theory into practice.</p><h2>Sorting the Query Results of Query Methods</h2><p>When we are building our queries by using query methods, we can sort the query results by following these steps:</p><ol><li>Add a new <em>Sort</em> parameter to the query method. This method parameter specifies the used sort options.</li><li>Create a new <em>Sort</em> object in the service layer and pass it as a method parameter when the query method is called.</li></ol><p>Let&#8217;s move on and find out how this is done.</p><h3>Modifying the Repository Interface</h3><p>We can sort the query results of our query by adding a new <em>Sort</em> parameter to the our query method. This method parameter specifies the sort options of the executed query. Let&#8217;s move on and take a look at the declarations of our query methods.</p><h4>Query Generation From Method Name</h4><p>When the executed query is created by using the query generation from method name strategy, we have to add a <em>Sort</em> parameter to the <em>findByTitleContainsOrDescriptionContains()</em> method of the <em>TodoDocumentRepository</em> interface. The source code of our repository interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.Query</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> PartialUpdateRepository, SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> findByTitleContainsOrDescriptionContains<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> title, <span style="color: #003399;">String</span> description, Sort sort<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Named Queries</h4><p>When the executed query is created by using named queries, we have to add a <em>Sort</em> parameter to the <em>findByNamedQuery()</em> method of the <em>TodoDocumentRepository</em> interface. The source code of our repository interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.Query</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> PartialUpdateRepository, SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Query<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;TodoDocument.findByNamedQuery&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> findByNamedQuery<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, Sort sort<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p><strong>Note:</strong> This approach does not work if we are using Spring Data Solr RC1 because of a <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://jira.springsource.org/browse/DATASOLR-63" target="_blank">known bug</a>. We have to either use the build snapshot dependency or wait for the release of RC2.</p><h4>The @Query Annotation</h4><p>When the executed query is created by using the <em>@Query</em> annotation, we have to add a <em>Sort</em> parameter to the <em>findByQueryAnnotation()</em> method of the <em>TodoDocumentRepository</em> interface. The source code of our repository interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.Query</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> PartialUpdateRepository, SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Query<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;title:*?0* OR description:*?0*&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> findByQueryAnnotation<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm, Sort sort<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p><strong>Note:</strong> This approach does not work if we are using Spring Data Solr RC1 because of a <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://jira.springsource.org/browse/DATASOLR-62" target="_blank">known bug</a>. We have to either use the build snapshot dependency or wait for the release of RC2.</p><h3>Using the Query Method</h3><p>We can use the modified query method by making the following changes to the <em>search()</em> method of the <em>RepositoryIndexService</em> class:</p><ol><li>Create a private <em>sortByIdDesc()</em> method which specifies that the query results are sorted in descending order by using the <em>id</em> of the document.</li><li>Get the sorted query results by calling the query method declared in the <em>TodoDocumentRepository</em> interface.</li><li>Return the query results.</li></ol><p>Let&#8217;s move on and take a look at the different implementations of the <em>search()</em> method.</p><h4>Query Generation From Method Name</h4><p>When we are building our queries by using the query generation from method name strategy, we can get the query results by using the <em>findByTitleContainsOrDescriptionContains()</em> method of the <em>TodoDocumentRepository</em> interface.</p><p>The source code of the relevant part of <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:425px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">findByTitleContainsOrDescriptionContains</span><span style="color: #009900;">&#40;</span>searchTerm, searchTerm, sortByIdDesc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Sort sortByIdDesc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">DESC</span>, <span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Named Queries</h4><p>When we are building our queries by using named queries, we can get the query results by using the <em>findByNamedQuery()</em> method of the <em>TodoDocumentRepository</em> interface.</p><p>The relevant part of the <em>RepositoryTodoIndexService</em> looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:425px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">findByNamedQuery</span><span style="color: #009900;">&#40;</span>searchTerm, sortByIdDesc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Sort sortByIdDesc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">DESC</span>, <span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>The @Query annotation</h4><p>When we are building our queries by using the <em>@Query</em> annotation, we can get the query results by using the <em>findByQueryAnnotation()</em> method of the <em>TodoDocumentRepository</em> interface.</p><p>The relevant part of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:425px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">findByQueryAnnotation</span><span style="color: #009900;">&#40;</span>searchTerm, sortByIdDesc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Sort sortByIdDesc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">DESC</span>, <span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Sorting the Query Results of Dynamic Queries</h2><p>Because <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/">dynamic queries</a> are created by <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/">adding a custom method to a repository interface</a>, the steps required to sort the query results of a dynamic query have no effect to the service layer of our example application.</p><p>We can sort the query results of dynamic queries by making the following changes to the implementation of our custom repository interface:</p><ol><li>Add a private <em>sortByIdDesc()</em> method to the <em>TodoDocumentRepositoryImpl</em> class. This method returns a <em>Sort</em> object which specifies that the query results are sorted in descending order by using the <em>id</em> of the document.</li><li>Modify the <em>search()</em> method of the <em>TodoDocumentRepositoryImpl</em> class. Set the sort options to the executed query by using the <em>addSort()</em> method of the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/solr/docs/1.0.0.RC1/api/org/springframework/data/solr/core/query/Query.html" target="_blank"><em>Query</em></a> interface and pass the created <em>Sort</em> object as a method parameter.</li></ol><p>The relevant part of the <em>TodoDocumentRepositoryImpl</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:975px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Page</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Sort</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.SolrTemplate</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.query.Criteria</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.query.SimpleQuery</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Repository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @<span style="color: #003399;">Repository</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TodoDocumentRepositoryImpl <span style="color: #000000; font-weight: bold;">implements</span> CustomTodoDocumentRepository <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> SolrTemplate solrTemplate<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> words <span style="color: #339933;">=</span> searchTerm.<span style="color: #006633;">split</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot; &quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; Criteria conditions <span style="color: #339933;">=</span> createSearchConditions<span style="color: #009900;">&#40;</span>words<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; SimpleQuery search <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SimpleQuery<span style="color: #009900;">&#40;</span>conditions<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//SET SORT OPTIONS</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; search.<span style="color: #006633;">addSort</span><span style="color: #009900;">&#40;</span>sortByIdDesc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; Page results <span style="color: #339933;">=</span> solrTemplate.<span style="color: #006633;">queryForPage</span><span style="color: #009900;">&#40;</span>search, TodoDocument.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> results.<span style="color: #006633;">getContent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Criteria createSearchConditions<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> words<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; Criteria conditions <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> word<span style="color: #339933;">:</span> words<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>conditions <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conditions <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conditions <span style="color: #339933;">=</span> conditions.<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;description&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> conditions<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Sort sortByIdDesc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> Sort<span style="color: #009900;">&#40;</span>Sort.<span style="color: #006633;">Direction</span>.<span style="color: #006633;">DESC</span>, <span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Summary</h2><p>We have now learned how we can sort query results with Spring Data Solr. This tutorial has taught us three things:</p><ul><li>We know that we can specify the used sort options by using the <em>Sort</em> class.</li><li>We learned that we can sort the query result of query methods by adding a new method parameter to the query method.</li><li>We learned that we can set the sort options to a dynamic query by using the <em>addSort()</em> method of the <em>Query</em> interface.</li></ul><p>The next part of my Spring Data Solr tutorial describes <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-pagination/">how we can paginate the query results of our queries</a>.</p><p>P.S. The example applications of this blog posts are available at Github (<a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/query-methods" target="_blank">query methods</a> and <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/criteria" target="_blank">dynamic queries</a>).</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/40569905/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/40569905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/&quot;&gt;Spring Data Solr Tutorial: Query Methods&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/40569905/0/petrikainulainen~Spring-Data-Solr-Tutorial-Sorting/feed/</wfw:commentRss> <slash:comments>1</slash:comments></item>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/</feedburner:origLink><title>Spring Data Solr Tutorial: Dynamic Queries</title><link>http://feeds.feedblitz.com/~/39365475/0/petrikainulainen~Spring-Data-Solr-Tutorial-Dynamic-Queries/</link> <comments>http://feeds.feedblitz.com/~/39365475/0/petrikainulainen~Spring-Data-Solr-Tutorial-Dynamic-Queries/#comments</comments> <pubDate>Sun, 24 Mar 2013 17:03:51 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Solr]]></category> <category><![CDATA[spring data]]></category> <category><![CDATA[spring data solr]]></category> <category><![CDATA[Spring Framework]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=5027</guid> <description><![CDATA[Solr is often referred as a search server which we can use when we are implementing full-text search functions. However, it is often wise to leverage the performance of Solr when we are implementing a search function which takes its input from a search form. In this scenario, the executed search query depends from the [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/&quot;&gt;Spring Data Solr Tutorial: Query Methods&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/multipleopendrawers.jpg" alt="Multiple open drawers of wooden catalogue" /></a></p><p>Solr is often referred as a search server which we can use when we are implementing full-text search functions. However, it is often wise to leverage the performance of Solr when we are implementing a search function which takes its input from a search form.</p><p>In this scenario, the executed search query depends from the received input. This means that the number of  query parameters depends from the input entered to the search form. In other words, the executed search query is dynamic.</p><p>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/">previous part of my Spring Data Solr tutorial</a> taught us how we can add custom methods to a single repository. It is time put this information in to use and find out how we can create dynamic queries with Spring Data Solr.</p><p>Let&#8217;s get started.</p><p><strong>Note:</strong> These blog entries provide additional information which helps us to understand the concepts described in this blog post:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/maven/running-solr-with-maven/">Running Solr with Maven</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/">Spring Data Solr Tutorial: Introduction to Solr</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/">Spring Data Solr Tutorial: Configuration</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-crud-almost/">Spring Data Solr Tutorial: CRUD (Almost)</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/">Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository</a></li></ul><h2>Creating Dynamic Queries</h2><p>This section describes how we can create dynamic queries with Spring Data Solr. It is divided into two subsections which are described in the following:</p><ul><li>The first subsection describes the basics which we need to know before we can start working on the actual search function.</li><li>The second subsection describes how we can implement the search function of our example application by adding a custom method to our Spring Data Solr repository.</li></ul><h3>Learning the Basics</h3><p>Before we can start implementing the search function of our example application, we need to know how we can create queries &#8220;manually&#8221; by using Spring Data Solr. We can create a query &#8220;manually&#8221; by following these steps:</p><ol><li>Create the search criteria.</li><li>Create the query which holds the used search criteria.</li><li>Execute the created query.</li></ol><p>These steps are described with more details in the following.</p><h4>Creating the Search Criteria</h4><p>First, we have to create the search criteria for our query. We can do this by using the criteria classes which are described in the following:</p><ul><li>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/solr/docs/1.0.0.RC1/api/org/springframework/data/solr/core/query/SimpleStringCriteria.html" target="_blank"><em>org.springframework.data.solr.core.query.SimpleStringCriteria</em></a> class is a basic criteria class which is used to specify the executed query by using already formatted query string. The query string specified in this class is executed as is. Thus, this class cannot be used to build dynamic queries.</li><li>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/solr/docs/1.0.0.RC1/api/org/springframework/data/solr/core/query/Criteria.html" target="_blank"><em>org.springframework.data.solr.core.query.Criteria</em></a> is a criteria class which is used to build dynamic queries. It has a fluent API which supports the chaining of multiple <em>Criteria</em> objects.</li></ul><h4>Creating the Executed Query</h4><p>Second, we have to create the executed query. The query classes of Spring Data Solr are described in the following:</p><ul><li>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/solr/docs/1.0.0.RC1/api/org/springframework/data/solr/core/query/SimpleQuery.html" target="_blank"><em>org.springframework.data.solr.core.query.SimpleQuery</em></a> class is a query class which supports both pagination and grouping.</li><li>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/solr/docs/1.0.0.RC1/api/org/springframework/data/solr/core/query/SimpleFacetQuery.html" target="_blank"><em>org.springframework.data.solr.core.query.SimpleFacetQuery</em></a> class is a query class supporting <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/SolrFacetingOverview" target="_blank">faceted search</a>.</li><li>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/solr/docs/1.0.0.RC1/api/org/springframework/data/solr/core/query/SimpleFilterQuery.html" target="_blank"><em>org.springframework.data.solr.core.query.SimpleFilterQuery</em></a> class is query class which supports <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/CommonQueryParameters#fq" target="_blank">filter queries</a>.</li></ul><h4>Executing the Created Query</h4><p>Third, we have to execute the created query. The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/solr/docs/1.0.0.RC1/api/org/springframework/data/solr/core/SolrTemplate.html" target="_blank"><em>SolrTemplate</em></a> class implements several methods which we can use for this purpose. These methods are described in the following:</p><ul><li>The <em>long count(final SolrDataQuery query)</em> method returns the number of documents found with the query given as a method parameter.</li><li>The <em>UpdateResponse delete(SolrDataQuery query)</em> method deletes the documents which match with the query given as a method parameter and returns an <em>UpdateResponse</em> object.</li><li>The <em>T queryForObject(Query query, Class&lt;T&gt; clazz)</em> method returns a single document which matches with the query given as a method parameter.</li><li>The <em>FacetPage&lt;T&gt; queryForFacetPage(FacetQuery query, Class&lt;T&gt; clazz)</em> method executes a facet query against Solr index and returns the query results as a <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/solr/docs/1.0.0.RC1/api/org/springframework/data/solr/core/query/result/FacetPage.html" target="_blank"><em>FacetPage</em></a> object.</li><li>The <em>Page&lt;T&gt; queryForPage(Query query, Class&lt;T&gt; clazz)</em> method executes the query against Solr index and returns the query results as an implementation of the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-commons/docs/current/api/org/springframework/data/domain/Page.html" target="_blank">Page</a> interface.</li></ul><p>Let’s move on and put this theory into practice.</p><h3>Implementing the Search Function</h3><p>The requirements of our search function are following:</p><ul><li>The search function must return all todo entries which name or description contains some word of the given search term. In other words, if the search term is &#8220;Foo Bar&#8221;, our search function must return todo entries which title or description contains either &#8220;Foo&#8221; or &#8220;Bar&#8221;.</li><li>The search must be case insensitive.</li></ul><p>Because our search function is not static, we have to create it by using a dynamic query. We can create dynamic queries with Spring Data Solr by adding custom method to our Spring Data Solr repository. In other words, we have to follow these steps:</p><ol><li>Create a custom interface which declares the added method.</li><li>Implement the created interface.</li><li>Modify the repository interface to extend the created interface.</li></ol><p>These steps are described with more details in the following.</p><h4>Creating the Custom Interface</h4><p>First, we have to create a custom interface which declares our custom search method. We can do this by following these steps:</p><ol><li>Create an interface called <em>CustomTodoDocumentRepository</em>.</li><li>Declare the <em>search()</em> method. This method takes the used search term as a method parameter and returns a list of <em>TodoDocument</em> objects.</li></ol><p>The source code of the <em>CustomTodoDocumentRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> CustomTodoDocumentRepository <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Implementing the Created Interface</h4><p>Second, we have to implement the custom interface which we created earlier. We can do this by following these steps:</p><ol><li>Create a class called <em>TodoDocumentRepositoryImpl</em> and implement the <em>CustomTodoDocumentRepository</em> interface.</li><li>Annotate the class with the <em>@Repository</em> annotation.</li><li>Add <em>SolrTemplate</em> field to the class and annotate it with the <em>@Resource</em> annotation.</li><li>Implement the <em>search()</em> method.</li></ol><p>The implementation of the <em>search()</em> method requires a more detailed description which is given here. We can implement the <em>search()</em> method by following these steps:</p><ol><li>Get the words of the search term.<li>Construct the used search criteria by calling the private <em>createSearchConditions()</em> method and passing the words of the search term as a method parameter. This method creates the used search criteria by using the API of the <em>Criteria</em> class.</li><li>Create the executed query by creating a new <em>SimpleQuery</em> object and pass the created <em>Criteria</em> object as a constructor parameter.</li><li>Get the search results by calling the <em>queryForPage()</em> method of the <em>SolrTemplate</em> class. Pass the created query and the type of the expected result objects as method parameters.</li><li>Return the search results by calling the <em>getContent()</em> method of the <em>Page</em> interface.</li></ol><p>The source code of the <em>TodoDocumentRepositoryImpl</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:815px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.domain.Page</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.SolrTemplate</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.query.Criteria</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.query.SimpleQuery</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Repository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @<span style="color: #003399;">Repository</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TodoDocumentRepositoryImpl <span style="color: #000000; font-weight: bold;">implements</span> CustomTodoDocumentRepository <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> SolrTemplate solrTemplate<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> words <span style="color: #339933;">=</span> searchTerm.<span style="color: #006633;">split</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot; &quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; Criteria conditions <span style="color: #339933;">=</span> createSearchConditions<span style="color: #009900;">&#40;</span>words<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; SimpleQuery search <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> SimpleQuery<span style="color: #009900;">&#40;</span>conditions<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; Page results <span style="color: #339933;">=</span> solrTemplate.<span style="color: #006633;">queryForPage</span><span style="color: #009900;">&#40;</span>search, TodoDocument.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> results.<span style="color: #006633;">getContent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> Criteria createSearchConditions<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> words<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; Criteria conditions <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> word<span style="color: #339933;">:</span> words<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>conditions <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conditions <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span>“title”<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span>“description”<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conditions <span style="color: #339933;">=</span> conditions.<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span>“title”<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">or</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span>“description”<span style="color: #009900;">&#41;</span>.<span style="color: #006633;">contains</span><span style="color: #009900;">&#40;</span>word<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> conditions<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Modifying the Repository Interface</h4><p>Third, we have to make our custom <em>search()</em> method visible to the users of our repository. We can do this by extending the <em>CustomTodoDocumentRepository</em> interface. The source code of the <em>TodoDocumentRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> CustomTodoDocumentRepository, SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> <span style="color: #009900;">&#125;</span></div></div><p>We have now added a custom <em>search()</em> method to our Spring Data Solr repository. Let&#8217;s find out how we can use this method.</p><h2>Using the Custom Method</h2><p>We can use the custom method by modifying the <em>search()</em> method of the <em>RepositoryTodoIndexService</em> class. The new implementation of this method is very simple. It gets the search results by calling the <em>search()</em> method of our Spring Data Solr repository and returns the search results.</p><p>The source code of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">search</span><span style="color: #009900;">&#40;</span>searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Summary</h2><p>We have now implemented a dynamic search function with Spring Data Solr. Although our search function was rather simple, we should now be able to implement more complex queries as well.</p><p>This tutorial has taught us two things:</p><ul><li>We learned how we can create queries &#8220;manually&#8221; by using Spring Data Solr.</li><li>We learned that we have to implement dynamic search methods by adding custom method to a single repository.</li></ul><p>The next part of my Spring Data Solr tutorial describes how we can sort our query results.</p><p>P.S. The example application of this blog post is available <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/criteria" target="_blank">at Github</a>.</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/39365475/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/39365475/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/&quot;&gt;Spring Data Solr Tutorial: Query Methods&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/39365475/0/petrikainulainen~Spring-Data-Solr-Tutorial-Dynamic-Queries/feed/</wfw:commentRss> <slash:comments>2</slash:comments></item>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/</feedburner:origLink><title>Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository</title><link>http://feeds.feedblitz.com/~/39108108/0/petrikainulainen~Spring-Data-Solr-Tutorial-Adding-Custom-Methods-to-a-Single-Repository/</link> <comments>http://feeds.feedblitz.com/~/39108108/0/petrikainulainen~Spring-Data-Solr-Tutorial-Adding-Custom-Methods-to-a-Single-Repository/#comments</comments> <pubDate>Sat, 16 Mar 2013 20:08:34 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Solr]]></category> <category><![CDATA[spring data]]></category> <category><![CDATA[spring data solr]]></category> <category><![CDATA[Spring Framework]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=4974</guid> <description><![CDATA[The previous part of my Spring Data Solr tutorial taught us how we can create static queries by using query methods. The natural next step would be describe how we can create dynamic queries with Spring Data Solr. However, before we can move on to that subject, we have to understand how we can add [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/&quot;&gt;Spring Data Solr Tutorial: Query Methods&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/special-folder.jpg" alt="Custom folder" /></a></p><p>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/">previous part of my Spring Data Solr tutorial</a> taught us how we can create static queries by using query methods. The natural next step would be describe how we can create dynamic queries with Spring Data Solr. However, before we can move on to that subject, we have to understand how we can add custom methods to a single repository.</p><p>This blog entry will help us to understand how that is done.</p><p>During this blog entry we will modify our <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/query-methods" target="_blank">example application</a> to update the information of a todo entry to the Solr index by using a technique called partial update.</p><p>Let&#8217;s start by taking a closer look at Solr&#8217;s partial update feature.</p><p><strong>Note:</strong> These blog entries provide additional information which helps us the understand the concepts described in this blog entry:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/maven/running-solr-with-maven/">Running Solr with Maven</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/">Spring Data Solr Tutorial: Introduction to Solr</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/">Spring Data Solr Tutorial: Configuration</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-crud-almost/">Spring Data Solr Tutorial CRUD (Almost)</a></li></ul><h2>What is Partial Update?</h2><p>The partial update feature was introduced in Solr 4.0 and it gives us the possibility to select the fields which are updated. This can be very useful if it is slow to index the content of the whole document.</p><p>However, the partial update function has its limitations. If we want to use the partial update function, we have to store all fields of the document which increases the size of the Solr index. The reason for this is that it is not possible to do a partial update to Lucene index. Lucene always deletes the old document before indexing the new one. This means that if the fields which are not updated are not stored, the values of these fields are lost when a partial update is done to a document.</p><p>It is our job to decide which one is more important to us: speed or the size of the index.</p><p>We can get more information about partial update by checking out the following resources:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~solr.pl/en/2012/07/09/solr-4-0-partial-documents-update/" target="_blank">Solr 4.0: Partial documents update</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~stackoverflow.com/questions/15161903/partial-update-of-documents" target="_blank">Solr &#8211; Partial Update of Documents @ StackOverflow</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~stackoverflow.com/questions/11791803/update-a-new-field-to-existing-document" target="_blank">Solr &#8211; update a new field to existing document @ StackOverflow</a></li></ul><p>Let&#8217;s move and learn how we can add custom methods to a single Spring Data Solr repository.</p><h2>Adding Custom Methods a Single Repository</h2><p>We can add custom methods to a single repository by following these steps:</p><ol><li>Create a custom interface which declares the custom methods.</li><li>Implement the custom interface.</li><li>Modify the repository interface to extend the custom interface.</li></ol><p>These steps are described with more details in the following subsections.</p><h3>Creating the Custom Interface</h3><p>First, we have to create an interface and declare the custom methods in it. We can do this by following these steps:</p><ol><li>Create an interface called <em>PartialUpdateRepository</em>.</li><li>Declare the custom methods.</li></ol><p>Because we have to declare only one custom method which is used to update the information of a todo entry, the source code of the <em>PartialUpdateRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> PartialUpdateRepository <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> update<span style="color: #009900;">&#40;</span>Todo todoEntry<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Implementing the Custom Interface</h3><p>Second, we have to implement the <em>PartialUpdateRepository</em> interface. The repository infrastructure tries to auto detect the classes which implements the custom repository interfaces by using the following rules:</p><ul><li>The implementation of a custom repository interface must be found from the same package than the custom interface.</li><li>The name of the class which implements a custom repository interface must be created by using the following formula: <em>[The name of the actual repository interface][The repository implementation postfix]</em>.</li></ul><p>The default value of the repository implementation postfix is &#8216;Impl&#8217;. We can overwrite the default value by using one of the following methods:</p><ul><li>If we are using Java configuration, we can configure the used postfix by setting the preferred postfix as the value of the <em>repositoryImplementationPostfix</em> attribute of the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/api/org/springframework/data/solr/repository/config/EnableSolrRepositories.html" target="_blank"><em>@EnableSolrRepositories</em> annotation</a>.</li><li>If we are using XML configuration, we can configure the used postfix by setting the preferred postfix as the value of the <em>repository-impl-postfix</em> attribute of the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/reference/htmlsingle/#namespace-dao-config" target="_blank"><em>repositories</em> namespace element</a>.</li></ul><p>The example application of this blog entry uses the default configuration. Thus, we can implement the <em>PartialUpdateRepository</em> interface by following these steps:</p><ol><li>Create a class called <em>TodoDocumentRepositoryImpl</em>.</li><li>Annotate the class with the <em>@Repository</em> annotation.</li><li>Add <em>SolrTemplate</em> field to the class and annotate this field with the <em>@Resource</em> annotation.</li><li>Implement the <em>update()</em> method.</li></ol><p>Let&#8217;s take a closer look at the implementation of the <em>update()</em> method. We can implement this method by following these steps:</p><ol><li>Create a new <em>PartialUpdate</em> object. Set the name of the document&#8217;s <em>id</em> field and its value as constructor arguments.<li>Set the names and values of updated fields to the created object.<li>Do a partial update by calling the <em>saveBean()</em> method of the <em>SolrTemplate</em> class.</li><li>Commit changes by calling the <em>commit()</em> method of the <em>SolrTemplate</em> class.</li></ol><p>The source code of the <em>TodoRepositoryImpl</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:420px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.SolrTemplate</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.query.PartialUpdate</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Repository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @<span style="color: #003399;">Repository</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TodoDocumentRepositoryImpl <span style="color: #000000; font-weight: bold;">implements</span> PartialUpdateRepository <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> SolrTemplate solrTemplate<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> update<span style="color: #009900;">&#40;</span>Todo todoEntry<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; PartialUpdate update <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> PartialUpdate<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;id&quot;</span>, todoEntry.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; update.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;description&quot;</span>, todoEntry.<span style="color: #006633;">getDescription</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; update.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;title&quot;</span>, todoEntry.<span style="color: #006633;">getTitle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; solrTemplate.<span style="color: #006633;">saveBean</span><span style="color: #009900;">&#40;</span>update<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; solrTemplate.<span style="color: #006633;">commit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Modifying the Repository Interface</h3><p>We can make the custom <em>update()</em> method visible to the users of our repository by extending the <em>PartialUpdateRepository</em> interface. The source code of <em>TodoDocumentRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> PartialUpdateRepository, SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Query methods are omitted.</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p>Let’s move on and find out how we can use our new repository method.</p><h2>Using the Custom Method</h2><p>We can use the custom <em>update()</em> method by making the following changes to our example application:</p><ol><li>Add <em>update()</em> method to the TodoIndexService interface.</li><li>Implement the <em>update()</em> method.</li><li>Modify the <em>update()</em> method of the <em>RepositoryTodoService</em> class to use the new method.</li></ol><p>These steps are described with more details in the following subsections.</p><h3>Adding New Method to TodoIndexService Interface</h3><p>As we remember, the <em>TodoIndexRepository</em> interface declares methods which are used to add information to the Solr index, search information from it and remove documents from the index.</p><p>We have to add a new method to this interface. This method is called <em>update()</em> and it takes the updated <em>Todo</em> object as a method parameter. The source code of the <em>TodoIndexRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> update<span style="color: #009900;">&#40;</span>Todo todoEntry<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Implementing the Added Method</h3><p>We can implement the <em>update()</em> method of the <em>TodoIndexService</em> interface by following these steps:</p><ol><li>Add the <em>update()</em> method to the <em>RepositoryIndexService</em> class and annotate the method with the <em>@Transactional</em> annotation. This ensures that our <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/reference/htmlsingle/#solr.transactions" target="_blank">Spring Data Solr repository will participate in Spring managed transactions</a>.</li><li>Call the <em>update()</em> repository method and pass the updated <em>Todo</em> object as a method parameter.</li></ol><p>The source code of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other fields and methods are omitted.</span>
<br> 
<br> &nbsp; &nbsp; @Transactional
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> update<span style="color: #009900;">&#40;</span>Todo todoEntry<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; repository.<span style="color: #006633;">update</span><span style="color: #009900;">&#40;</span>todoEntry<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Modifying the RepositoryTodoService Class</h3><p>Our last step is to modify the <em>update()</em> method of the <em>RepositoryTodoService</em> class to use the new <em>update()</em> method which is declared in the <em>TodoIndexService</em> interface. The relevant parts of the <em>RepositoryTodoService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:560px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.security.access.prepost.PreAuthorize</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoService <span style="color: #000000; font-weight: bold;">implements</span> TodoService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoIndexService indexService<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Other methods are omitted.</span>
<br> 
<br> &nbsp; &nbsp; @PreAuthorize<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;hasPermission('Todo', 'update')&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @Transactional<span style="color: #009900;">&#40;</span>rollbackFor <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>TodoNotFoundException.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> Todo update<span style="color: #009900;">&#40;</span>TodoDTO updated<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> TodoNotFoundException <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; Todo model <span style="color: #339933;">=</span> findById<span style="color: #009900;">&#40;</span>updated.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color: #006633;">update</span><span style="color: #009900;">&#40;</span>updated.<span style="color: #006633;">getDescription</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, updated.<span style="color: #006633;">getTitle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; indexService.<span style="color: #006633;">update</span><span style="color: #009900;">&#40;</span>model<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> model<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Summary</h2><p>We have now added a custom method to a single Spring Data Solr repository and implemented an update function which uses the partial update feature of Solr. This tutorial has taught us two things:</p><ul><li>We know how we can add custom methods to a single Spring Data Solr repository.</li><li>We know that we can use partial update only if all fields of our document are stored (The value of the <em>stored</em> attribute is true).</li></ul><p>The next part of my Spring Data Solr tutorial describes how we can use the skills learned from this blog entry for <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/">creating dynamic queries with Spring Data Solr</a>.</p><p>P.S. The example application of this blog entry is available at <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/query-methods" target="_blank">Github</a>.</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/39108108/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/39108108/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/&quot;&gt;Spring Data Solr Tutorial: Query Methods&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/39108108/0/petrikainulainen~Spring-Data-Solr-Tutorial-Adding-Custom-Methods-to-a-Single-Repository/feed/</wfw:commentRss> <slash:comments>0</slash:comments></item>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/</feedburner:origLink><title>Spring Data Solr Tutorial: Query Methods</title><link>http://feeds.feedblitz.com/~/38878307/0/petrikainulainen~Spring-Data-Solr-Tutorial-Query-Methods/</link> <comments>http://feeds.feedblitz.com/~/38878307/0/petrikainulainen~Spring-Data-Solr-Tutorial-Query-Methods/#comments</comments> <pubDate>Sun, 10 Mar 2013 19:27:01 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Solr]]></category> <category><![CDATA[spring data]]></category> <category><![CDATA[spring data solr]]></category> <category><![CDATA[Spring Framework]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=4929</guid> <description><![CDATA[We have learned how we can configure Spring Data Solr. We have also learned how we can add new documents to the Solr index, update the information of existing documents and delete documents from the Solr index. Now it is time to move forward and learn how we can search information from the Solr index [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/openindexdrawer.jpg" alt="Open index drawer" /></a></p><p>We have learned how we can configure Spring Data Solr. We have also learned how we can add new documents to the Solr index, update the information of existing documents and delete documents from the Solr index. Now it is time to move forward and learn how we can search information from the Solr index by using Spring Data Solr.</p><p>The requirements of our search function are given in the following:</p><ul><li>The search function must return all todo entries which title or description contains the given search term.</li><li>The search must be case insensitive.</li></ul><p>We can implement the search function by following these steps:</p><ol><li>Create a query method.</li><li>Use the created query method.</li></ol><p>Let’s move on and find out how we can implement the search function by using query methods.</p><p><strong>Note:</strong> These blog entries provide additional information which helps us the understand the concepts described in this blog entry:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/maven/running-solr-with-maven/">Running Solr with Maven</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/">Spring Data Solr Tutorial: Introduction to Solr</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/">Spring Data Solr Tutorial: Configuration</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-crud-almost/">Spring Data Solr Tutorial CRUD (Almost)</a></li></ul><h2>Creating the Query Method</h2><p>Query methods are methods which are</p><ol><li>added to the repository interface.</li><li>used to specify the search query which is executed when the query method is called.</li><li>used to build static queries (queries which have always the same amount of query parameters).</li></ol><p>We can create query methods with Spring Data Solr by using the following techniques:</p><ul><li>Query generation from the method name</li><li>Named queries</li><li>@Query annotation</li></ul><p>These techniques are described with more details in the following subsections.</p><h3>Query Generation from the Method Name</h3><p>The query generation from the method name is a query generation strategy where the executed query is parsed from the name of the query method.</p><ol><li>The name of the query method must start with a special prefix which identifies the query method. These prefixes are: <em>find, findBy, get, getBy, read and readBy</em>. This prefix is stripped from the method name when the executed query is parsed.</li><li>Property expressions are used to refer to the properties of our document class.</li><li>Special keywords are used together with property expressions to specify the operators used in the created query. These keywords are added to the name of the query method after a property expression.</li><li>We can combine property expressions by adding either <em>And</em> or <em>Or</em> keyword between them.</li><li>The parameter count of the query method must be equal with the number of property expressions used in its name.</li></ol><p>We can get more information about the property expressions and the repository keywords by reading the following resources:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/reference/htmlsingle/#repositories.query-methods.query-creation" target="_blank">Spring Data Solr Reference Manual: Query Creation</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/reference/htmlsingle/#repository-query-keywords" target="_blank">Spring Data Solr Reference Manual: Repository Query Keywords</a></li></ul><p>As we remember, our search function must return all todo entries which title or description contains the given search term. Also, our document class has two properties which we are using in this query. These properties are called <em>title</em> and <em>description</em>. We can create the method name which fulfils the requirements of our search function by following these steps:</p><ol><li>Add the <em>findBy</em> prefix to start of the method name.</li><li>Add the property expression of the <em>title</em> property after the prefix.</li><li>Add the <em>Contains</em> keyword after the property expression.</li><li>Add the <em>Or</em> keyword to the method name.</li><li>Add the property expression of the <em>description</em> property after the <em>Or</em> keyword.</li><li>Add the <em>Contains</em> keyword to the method name.</li><li>Add two method parameters to our query method. The first parameter matched against the <em>title</em> property and second one is matched against the <em>description</em> property.</li></ol><p>The source code of the <em>TodoDocumentRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> findByTitleContainsOrDescriptionContains<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> title, <span style="color: #003399;">String</span> description<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><p><strong>Note:</strong> This query method will not work if the search term contains more than one word.</p><h3>Named Queries</h3><p>Named queries are queries which are declared in a separate properties file and wired to the correct query method. The rules concerning the properties file used to declare the named queries are described in the following:</p><ul><li>The default location of the properties file is <em>META-INF/solr-named-queries.properties</em> but we can configure the location by using the <em>namedQueriesLocation</em> property of the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/api/org/springframework/data/solr/repository/config/EnableSolrRepositories.html" target="_blank"><em>@EnableSolrRepositories</em> annotation</a>.</li><li>The key of each named query is created by using the following formula: <em>[The name of the document class].[The name of the named query]</em>.</li></ul><p>Named queries which are configured in the properties files are matched with the query methods of our repository interface by using the following rules:</p><ul><li>The name of query method which executes the named query must be same than the name of the named query.</li><li>If the name of the query method is not the same than the name of the named query, the query method must be annotated with the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/api/org/springframework/data/solr/repository/Query.html" target="_blank"><em>@Query</em> annotation</a> and the name of the named query must be configured by using the <em>name</em> property of the <em>@Query</em> annotation.</li></ul><p>We can implement query method with named queries by following these steps:</p><ol><li>Specify the named query.</li><li>Create the query method.</li></ol><p>These steps are described with more details in the following.</p><h4>Specifying the Named Query</h4><p>We can create a named query which fulfils the requirements of our search function by following these steps:</p><ol><li>Create the properties file which contains the named queries.</em><li>Create a key for the named query by using the formula described earlier. Since the name of our document class is <em>TodoDocument</em>, the key of our named query is <em>TodoDocument.findByNamedQuery</em>.<li>Create the named query by using the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/SolrQuerySyntax#Default_QParserPlugin:_LuceneQParserPlugin" target="_blank">Lucene query parser syntax</a>. Because our query must return documents which title or description contains the given search term, our query is: <em>title:*?0* OR description:*?0*</em> (The <em>?0</em> is replaced with the value of the query method’s first parameter).</ol><p>The content of the <em>META-INF/solr-named-query.properties</em> file looks as follows:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">TodoDocument.findByNamedQuery=title:*?0* OR description:*?0*</div></div><h4>Creating the Query Method</h4><p>We can create the query method which uses the created named query by following these steps:</p><ol><li>Add <em>findByNamedQuery()</em> method to the <em>TodoDocumentRepository</em> interface. This method returns a list of <em>TodoDocument</em> objects and takes a single <em>String</em> parameter called <em>searchTerm</em>.</li><li>Annotate the method with the <em>@Query</em> annotation and set the value of its <em>name</em> property to &#8216;TodoDocument.findByNamedQuery&#8217;. This step is not required since the name of the query method is the same than the name of the named query but I wanted to demonstrate the usage of the <em>@Query</em> annotation here.</li></ol><p>The source code of the <em>TodoDocumentRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.Query</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Query<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;TodoDocument.findByNamedQuery&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> findByNamedQuery<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>@Query Annotation</h3><p>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/api/org/springframework/data/solr/repository/Query.html" target="_blank"><em>@Query</em> annotation</a> can be used to specify the query which is executed when a query method is called. We can create the query method which fulfils the requirements of our search function by following these steps:</p><ol><li>Add <em>findByQueryAnnotation()</em> method to the <em>TodoDocumentRepository</em> interface. This method returns a list of <em>TodoDocument</em> objects and it has a single <em>String</em> parameter called <em>searchTerm</em>.</li><li>Annotate the method with the <em>@Query</em> annotation.</li><li>Set the executed query as the value of the <em>@Query</em> annotation. We can create the query by using the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/SolrQuerySyntax#Default_QParserPlugin:_LuceneQParserPlugin" target="_blank">Lucene query parser syntax</a>. Because our query must return documents which title or description contains the given search term, the correct query is: <em>title:*?0* OR description:*?0*</em> (The <em>?0</em> is replaced with the value of the query method’s first parameter).</ol><p>The source code of the <em>TodoDocumentRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.Query</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Query<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;title:*?0* OR description:*?0*&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> findByQueryAnnotation<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Using the Created Query Method</h2><p>We can use the created query method by following these steps:</p><ol><li>Declare the <em>search()</em> method in the <em>TodoIndexService</em> interface.</li><li>Add the implementation of the <em>search()</em> method to the <em>RepositoryTodoIndexService</em> class.</li></ol><p>These steps are described with more details in the following subsections.</p><h3>Declaring the Search Method</h3><p>Our first step is to declare the search method in the <em>TodoIndexService</em> interface. The relevant part of the <em>TodoIndexService</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Implementing the Search Method</h3><p>Our second step is to implement the <em>search()</em> method. Our implementation is rather simple. It obtains a list of <em>TodoDocument</em> objects by calling the correct method of the <em>TodoDocumentRepository</em> interface and returns that list.</p><p>The name of the query method depends from the technique used to create the query method. The different implementations are described in the following.</p><h4>Query Generation from the Method Name</h4><p>When we are generating the query from the name of the query method, our implementation obtains a list of <em>TodoDocument</em> objects by calling the <em>findByTitleContainsOrDescriptionContains()</em> method of the <em>TodoDocumentRepository</em> interface and returns that list.</p><p>The relevant part of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">findByTitleContainsOrDescriptionContains</span><span style="color: #009900;">&#40;</span>searchTerm, searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Named Queries</h4><p>If we are using named queries, our implementation gets a list of <em>TodoDocument</em> objects by calling the <em>findByNamedQuery()</em> method of the <em>TodoDocumentRepository</em> interface and returns that list.</p><p>The relevant part of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">findByNamedQuery</span><span style="color: #009900;">&#40;</span>searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>@Query Annotation</h4><p>When we are using the <em>@Query</em> annotation, our implementation obtains a list of <em>TodoDocument</em> objects by calling the <em>findByQueryAnnotation()</em> method of the <em>TodoDocumentRepository</em> interface and returns that list.</p><p>The relevant part of the <em>RepositoryTodoIndexService</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> List<span style="color: #339933;">&lt;</span>TodoDocument<span style="color: #339933;">&gt;</span> search<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> searchTerm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> repository.<span style="color: #006633;">findByQueryAnnotation</span><span style="color: #009900;">&#40;</span>searchTerm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Selecting the Correct Query Creation Technique</h2><p>The obvious question is:</p><blockquote><p>What is the best way to add query methods to our Spring Data Solr repositories?</p></blockquote><p>We can use the following guidelines when we are deciding the correct query creation technique for our query method:</p><ul><li>If the created query is very simple, query generation from the method name is often the best choice. The problem of this approach is that implementing &#8220;complex&#8221; queries with this approach leads into long and ugly method names.</li><li>It is a good idea to keep our queries near our query methods. The benefit of using the <em>@Query</em> annotation is that we can see the executed query and our query method by reading the source code of our repository interface.</li><li>If we want to separate the executed queries from our repository interface, we should use named queries. The problem of this approach is that we have to check the executed query from the properties file which is quite cumbersome.</li></ul><h2>Summary</h2><p>We have now learned how we can create static queries with Spring Data Solr. This blog entry has taught us two things:</p><ul><li>We know what query method methods are and how we can create them.</li><li>We are familiar with the different query creation techniques and we know when to use them.</li></ul><p>The example application which demonstrates the concepts described in this blog entry is available at <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/query-methods" target="_blank">Github</a>. In the next part of this tutorial we will learn <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/">how we can add custom functionality to a single repository</a>.</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/38878307/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/38878307/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/38878307/0/petrikainulainen~Spring-Data-Solr-Tutorial-Query-Methods/feed/</wfw:commentRss> <slash:comments>4</slash:comments></item>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-crud-almost/</feedburner:origLink><title>Spring Data Solr Tutorial: CRUD (Almost)</title><link>http://feeds.feedblitz.com/~/38428432/0/petrikainulainen~Spring-Data-Solr-Tutorial-CRUD-Almost/</link> <comments>http://feeds.feedblitz.com/~/38428432/0/petrikainulainen~Spring-Data-Solr-Tutorial-CRUD-Almost/#comments</comments> <pubDate>Sat, 23 Feb 2013 18:20:47 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Solr]]></category> <category><![CDATA[spring data]]></category> <category><![CDATA[spring data solr]]></category> <category><![CDATA[Spring Framework]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=4851</guid> <description><![CDATA[In the previous part of my Spring Data Solr tutorial, we learned how we can configure Spring Data Solr. Now it is time to take a step forward and learn how we can manage the information stored in our Solr instance. This blog entry describes how we add new documents to the Solr index, update [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-crud-almost/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/librarianandindex.jpg" alt="Librarian and index cards" /></a></p><p>In the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/">previous part</a> of my Spring Data Solr tutorial, we learned how we can configure Spring Data Solr. Now it is time to take a step forward and learn how we can manage the information stored in our Solr instance. This blog entry describes how we add new documents to the Solr index, update the information of existing documents and delete documents from the index.</p><p>We can make the necessary modifications to our <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/query-methods" target="_blank">example application</a> by following these steps:</p><ol><li>Create a document class which contains the information stored in the Solr index.</li><li>Create a repository interface for our Spring Data Solr repository.</li><li>Create a service which uses the created repository.</li><li>Use the created service.</li></ol><p>These steps are described with more details in the following sections.</p><p><strong>Note</strong>: These blog entries provide additional information which helps us to understand the concepts described in this blog entry:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/maven/running-solr-with-maven/">Running Solr with Maven</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/">Spring Data Solr Tutorial: Introduction to Solr</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/">Spring Data Solr Tutorial: Configuration</a></li></ul><h2>Creating the Document Class</h2><p>The first step is to create a document class which contains the information added to the Solr index. A document class is basically just a POJO which is implemented by following these rules:</p><ul><li>The <em>@Field</em> annotation is used to create a link between the fields of the POJO and the fields of the Solr document.</li><li>If the name of the bean’s field is not equal to the name of the document’s field, the name of the document’s field must be given as a value of the <em>@Field</em> annotation.</li><li>The <em>@Field</em> annotation can be applied either to a field or setter method.</li><li>Spring Data Solr assumes by default that the name of the document’s id field is &#8216;id&#8217;. We can override this setting by annotating the id field with the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/commons/docs/current/api/org/springframework/data/annotation/Id.html" target="_blank"><em>@Id</em></a> annotation.</li><li>Spring Data Solr (version 1.0.0.RC1) requires that the type of the document&#8217;s id is <em>String</em>.</li></ul><p><strong>More information</strong>:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/Solrj#Directly_adding_POJOs_to_Solr" target="_blank">Solrj @ Solr Wiki</a></li></ul><p>Let’s move on and create our document class.</p><p>In the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/">first part</a> of my Spring Data Solr tutorial, we learned that we have to store the <em>id</em>, <em>description</em> and <em>title</em> of each todo entry to the Solr index.</p><p>Thus, we can create a document class for todo entries by following these steps:</p><ol><li>Create a class called <em>TodoDocument</em>.</li><li>Add the <em>id</em> field to the <em>TodoDocument</em> class and annotate the field with the <em>@Field</em> annotation. Annotate the field with the @Id annotation (This is not required since the name of the id field is &#8216;id&#8217; but I wanted to demonstrate its usage here).</li><li>Add the <em>description</em> field to the <em>TodoDocument</em> class and annotate this field with the <em>@Field</em> annotation.</li><li>Add the <em>title</em> field to the <em>TodoDocument</em> and annotate this field with the <em>@Field</em> annotation.</li><li>Create getter methods to the fields of the <em>TodoDocument</em> class.</li><li>Create a static inner class which is used to build new <em>TodoDocument</em> objects.</li><li>Add a static <em>getBuilder()</em> method to the <em>TodoDocument</em> class. The implementation of this method returns a new <em>TodoDocument.Builder</em> object.</li></ol><p>The source code of the <em>TodoDocument</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:810px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.apache.solr.client.solrj.beans.Field</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.annotation.Id</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> TodoDocument <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Id
<br> &nbsp; &nbsp; @<span style="color: #003399;">Field</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> id<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @<span style="color: #003399;">Field</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> description<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @<span style="color: #003399;">Field</span>
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">String</span> title<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> TodoDocument<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> Builder getBuilder<span style="color: #009900;">&#40;</span><span style="color: #003399;">Long</span> id, <span style="color: #003399;">String</span> title<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> Builder<span style="color: #009900;">&#40;</span>id, title<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Getters are omitted</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000000; font-weight: bold;">class</span> Builder <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocument build<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> Builder<span style="color: #009900;">&#40;</span><span style="color: #003399;">Long</span> id, <span style="color: #003399;">String</span> title<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; build <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> TodoDocument<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; build.<span style="color: #006633;">id</span> <span style="color: #339933;">=</span> id.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; build.<span style="color: #006633;">title</span> <span style="color: #339933;">=</span> title<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> Builder description<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> description<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; build.<span style="color: #006633;">description</span> <span style="color: #339933;">=</span> description<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">this</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> TodoDocument build<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> build<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Creating the Repository Interface</h2><p>The base interface of Spring Data Solr repositories is the <em>SolrCrudRepository&lt;T, ID&gt;</em> interface and each repository interface must extend this interface.</p><p>When we extend the <em>SolrCrudRepository&lt;T, ID&gt;</em> interface, we must give two type parameters which are described in the following:</p><ul><li>The <em>T</em> type parameter means the type of our document class.</li><li>The <em>ID</em> type parameter means the type of the document’s id. Spring Data Solr (version 1.0.0.RC1) requires that the id of a document is <em>String</em>.</li></ul><p>We can create the repository interface by following these steps:</p><ol><li>Create an interface called <em>TodoDocumentRepository</em>.</li><li>Extend the <em>SolrCrudRepository</em> interface and give the type of our document class and its id as type parameters.</li></ol><p>The source code of the <em>TodoDocumentRepository</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.SolrCrudRepository</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoDocumentRepository <span style="color: #000000; font-weight: bold;">extends</span> SolrCrudRepository<span style="color: #339933;">&lt;</span>TodoDocument, String<span style="color: #339933;">&gt;</span> <span style="color: #009900;">&#123;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Creating the Service</h2><p>Our next step is to create the service which uses the created Solr repository. We can create this service by following these steps:</p><ol><li>Create a service interface.</li><li>Implement the created interface.</li></ol><p>These steps are described with more details in the following.</p><h3>Creating the Service Interface</h3><p>Our service interface declares two methods which are described in the following:</p><ul><li>The <em>void addToIndex(Todo todoEntry)</em> method adds a todo entry to the index.</li><li>The <em>void deleteFromIndex(Long id)</em> method deletes a todo entry from the index.</li></ul><p><strong>Note:</strong> We can use the <em>addToIndex()</em> method for adding new todo entries to the Solr index and updating the information of existing todo entries. If an existing document has the same id than the new one, the old document is deleted and the information of the new document is saved to the Solr index (See <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/SchemaXml#The_Unique_Key_Field" target="_blank">SchemaXML @ Solr Wiki</a> for more details).</p><p>The source code of the <em>TodoIndexService</em> interface looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> addToIndex<span style="color: #009900;">&#40;</span>Todo todoEntry<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> deleteFromIndex<span style="color: #009900;">&#40;</span><span style="color: #003399;">Long</span> id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h3>Implementing the Created Interface</h3><p>We cam implement the service interface by following these steps:</p><ol><li>Create a skeleton implementation of our service class.</li><li>Implement the method used to add documents to the Solr index.</li><li>Implement the method used to delete documents from the Solr index.</li></ol><p>These steps are described with more details in the following.</p><h4>Creating a Skeleton Implementation of the Service Class</h4><p>We can create a skeleton implementation of our service interface by following these steps:</p><ol><li>Create a class called <em>RepositoryTodoIndexService</em> and annotate this class with the <em>@Service</em> annotation. This annotation marks this class as a service and ensures that the class will be detected during the classpath scanning.</li><li>Add a <em>TodoDocumentRepository</em> field to the <em>RepositoryTodoIndexService</em> class and annotate that field with the <em>@Resource</em> annotation. This annotation instructs the Spring IoC container to inject the actual repository implementation the service’s <em>repository</em> field.</li></ol><p>The source code of our dummy service implementation looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Add methods here</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Adding Documents to the Solr Index</h4><p>We can create the method which adds new documents to the Solr index by following these steps:</p><ol><li>Add the <em>addToIndex()</em> method to the <em>RepositoryTodoIndexService</em> class and annotate this method with the <em>@Transactional</em> annotation. This ensures that our <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/reference/htmlsingle/#solr.transactions" target="_blank">Spring Data Solr repository will participate in Spring managed transactions</a>.</li><li>Create a new <em>TodoDocument</em> object by using the builder pattern. Set the <em>id</em>, <em>title</em> and <em>description</em> of the created document.</li><li>Add the document to the Solr index by calling the <em>save()</em> method of the <em>TodoDocumentRepository</em> interface.</li></ol><p>The source code of the created method looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:445px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Transactional
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> addToIndex<span style="color: #009900;">&#40;</span>Todo todoEntry<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; TodoDocument document <span style="color: #339933;">=</span> TodoDocument.<span style="color: #006633;">getBuilder</span><span style="color: #009900;">&#40;</span>todoEntry.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, todoEntry.<span style="color: #006633;">getTitle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">description</span><span style="color: #009900;">&#40;</span>todoEntry.<span style="color: #006633;">getDescription</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">build</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; 
<br> &nbsp; &nbsp; &nbsp; &nbsp; repository.<span style="color: #006633;">save</span><span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Add deleteFromIndex() method here</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>Deleting Documents from the Solr Index</h4><p>We can create a method which deletes documents from the Solr index by following these steps:</p><ol><li>Add the <em>deleteFromIndex()</em> method to the <em>RepositoryTodoDocumentService</em> class and annotate this method with the <em>@Transactional</em> annotation. This ensures that our <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/data-solr/docs/1.0.0.RC1/reference/htmlsingle/#solr.transactions" target="_blank">Spring Data Solr repository will participate in Spring managed transactions</a>.</li><li>Delete document from the Solr index by calling the <em>delete()</em> method of the <em>TodoDocumentRepository</em> interface.</li></ol><p>The source code of the created method looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoIndexService <span style="color: #000000; font-weight: bold;">implements</span> TodoIndexService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoDocumentRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #666666; font-style: italic;">//Add addToIndex() method here</span>
<br> 
<br> &nbsp; &nbsp; @Transactional
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> deleteFromIndex<span style="color: #009900;">&#40;</span><span style="color: #003399;">Long</span> id<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; repository.<span style="color: #006633;">delete</span><span style="color: #009900;">&#40;</span>id.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Using the Created Service</h2><p>Our last step is to use the service which we created earlier. We can do this by making the following modifications to the <em>RepositoryTodoService</em> class:</p><ol><li>Add the <em>TodoIndexService</em> field to the the <em>RepositoryTodoService</em> class and annotate this field with the <em>@Resource</em> annotation. This annotation instructs the Spring IoC container to inject the created <em>RepositoryTodoIndexService</em> object to the service’s <em>indexService</em> field.</li><li>Call the <em>addToIndex()</em> method of the <em>TodoIndexService</em> interface in the <em>add()</em> method of the <em>RepositoryTodoService</em> class.</li><li>Call the <em>deleteFromIndex()</em> method of the <em>TodoIndexService</em> interface in the <em>deleteById()</em> method of the <em>RepositoryTodoService</em> class.</li><li>Call the <em>addToIndex()</em> method of the <em>TodoIndexService</em> interface in the update() method of the <em>RepositoryTodoService</em> class.</li></ol><p>The source code of the <em>RepositoryTodoService</em> looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:775px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.security.access.prepost.PreAuthorize</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.stereotype.Service</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.transaction.annotation.Transactional</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.List</span><span style="color: #339933;">;</span>
<br> 
<br> @Service
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RepositoryTodoService <span style="color: #000000; font-weight: bold;">implements</span> TodoService <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoIndexService indexService<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> TodoRepository repository<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @PreAuthorize<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;hasPermission('Todo', 'add')&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @Transactional
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> Todo add<span style="color: #009900;">&#40;</span>TodoDTO added<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; Todo model <span style="color: #339933;">=</span> Todo.<span style="color: #006633;">getBuilder</span><span style="color: #009900;">&#40;</span>added.<span style="color: #006633;">getTitle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">description</span><span style="color: #009900;">&#40;</span>added.<span style="color: #006633;">getDescription</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #006633;">build</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; Todo persisted <span style="color: #339933;">=</span> repository.<span style="color: #006633;">save</span><span style="color: #009900;">&#40;</span>model<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; indexService.<span style="color: #006633;">addToIndex</span><span style="color: #009900;">&#40;</span>persisted<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> persisted<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; @PreAuthorize<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;hasPermission('Todo', 'delete')&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @Transactional<span style="color: #009900;">&#40;</span>rollbackFor <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>TodoNotFoundException.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> Todo deleteById<span style="color: #009900;">&#40;</span><span style="color: #003399;">Long</span> id<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> TodoNotFoundException <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; Todo deleted <span style="color: #339933;">=</span> findById<span style="color: #009900;">&#40;</span>id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; repository.<span style="color: #006633;">delete</span><span style="color: #009900;">&#40;</span>deleted<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; indexService.<span style="color: #006633;">deleteFromIndex</span><span style="color: #009900;">&#40;</span>id<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> deleted<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; @PreAuthorize<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;hasPermission('Todo', 'update')&quot;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @Transactional<span style="color: #009900;">&#40;</span>rollbackFor <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>TodoNotFoundException.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
<br> &nbsp; &nbsp; @Override
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> Todo update<span style="color: #009900;">&#40;</span>TodoDTO updated<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> TodoNotFoundException <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; Todo model <span style="color: #339933;">=</span> findById<span style="color: #009900;">&#40;</span>updated.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color: #006633;">update</span><span style="color: #009900;">&#40;</span>updated.<span style="color: #006633;">getDescription</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, updated.<span style="color: #006633;">getTitle</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; indexService.<span style="color: #006633;">addToIndex</span><span style="color: #009900;">&#40;</span>model<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> model<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h2>Summary</h2><p>We have successfully created an application which adds documents to the Solr index and deletes documents from it. This blog entry has taught us the following things:</p><ul><li>We learned how we can create document classes.</li><li>We learned that we can create Spring Data Solr repositories by extending the <em>SolrCrudRepository</em> interface.</li><li>We learned that Spring Data Solr assumes by default that the name of the document’s id field is &#8216;id&#8217;. However, we can override this setting by annotating the id field with the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring-data/commons/docs/current/api/org/springframework/data/annotation/Id.html" target="_blank"><em>@Id</em></a> annotation.</li><li>We learned that at the moment Spring Data Solr (version 1.0.0.RC1) expects that the id of a document is <em>String</em>.</li><li>We learned how we can add documents to the Solr index and delete documents from it.</li><li>We learned that Spring Data Solr repositories can participate in Spring managed transactions.</li></ul><p>The next part of my Spring Data Solr tutorial describes how we can <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-query-methods/">search information from the Solr index by using query methods</a>.</p><p>P.S. The example application of this blog entry is available at <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/query-methods" target="_blank">Github</a>.</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/38428432/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/38428432/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/38428432/0/petrikainulainen~Spring-Data-Solr-Tutorial-CRUD-Almost/feed/</wfw:commentRss> <slash:comments>4</slash:comments></item>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/</feedburner:origLink><title>Spring Data Solr Tutorial: Configuration</title><link>http://feeds.feedblitz.com/~/38218905/0/petrikainulainen~Spring-Data-Solr-Tutorial-Configuration/</link> <comments>http://feeds.feedblitz.com/~/38218905/0/petrikainulainen~Spring-Data-Solr-Tutorial-Configuration/#comments</comments> <pubDate>Sat, 16 Feb 2013 19:52:12 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Solr]]></category> <category><![CDATA[spring data]]></category> <category><![CDATA[spring data solr]]></category> <category><![CDATA[Spring Framework]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=4760</guid> <description><![CDATA[In the previous part of my Spring Data Solr tutorial, we learned that Solr provides a REST-like HTTP API which can be used to add information to Solr index and execute queries against indexed data. The problem is that running a separate Solr instance in a development environment is a bit cumbersome. However, not all [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/brasscogs.jpg" alt="Spring Data Solr Tutorial: Configuration post image" /></a></p><p>In the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/">previous part</a> of my Spring Data Solr tutorial, we learned that Solr provides a REST-like HTTP API which can be used to add information to Solr index and execute queries against indexed data. The problem is that running a separate Solr instance in a development environment is a bit cumbersome.</p><p>However, not all hope is lost because Solr provides two alternative server implementations which we can use in our applications. These implementations are described in the following:</p><ul><li>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/Solrj#EmbeddedSolrServer" target="_blank">embedded Solr server</a> connects directly to Solr core. We can use this server for development purposes but we must also remember that <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/EmbeddedSolr" target="_blank">using it in production environment is not recommended</a>. However, using the embedded Solr server is still a viable option in the development environment.</li><li>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/Solrj#HttpSolrServer" target="_blank">HTTP Solr server</a> connects to an external Solr server by using HTTP. This is the recommended way of using the Solr search server and that is why we should always use it in the production environment.</li></ul><p>This blog entry describes how we can get the required dependencies with Maven. We also learn to configure the Spring Data Solr to use the embedded Solr server in the development environment and the HTTP Solr server in the production environment.</p><p><strong>Note</strong>: These blog entries provides additional information which helps us to understand the concepts described in this blog entry:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/maven/running-solr-with-maven/">Running Solr with Maven</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/">Spring Data Solr Tutorial: Introduction to Solr</a></li></ul><p>Let’s get started.</p><h2>Getting the Required Dependencies with Maven</h2><p>We can get the required dependencies with Maven by following these steps:</p><ol><li>Add the Spring Milestone Maven repository to the POM file.</li><li>Add the required dependencies to the pom.xml file.</li></ol><p>Both of these steps are described with more details in the following.</p><h3>Adding the Spring Milestone Maven Repository to the POM File</h3><p>We can add the Spring milestone Maven repository to our POM file by adding the following XML to the <em>pom.xml</em> file:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;repositories<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;repository<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>spring-milestone<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Spring Milestone Maven Repository<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://repo.springsource.org/libs-milestone<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/url<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/repository<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/repositories<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><h3>Adding the Required Dependencies to the POM File</h3><p>We can add the required dependencies to the POM file by following these steps:</p><ol><li>Add the Spring Data Solr dependency (version 1.0.0.RC1) to the dependencies section of our POM file.</li><li>Add the Solr core dependency (version 4.1.0) to the dependencies section of our POM file and exclude the SLF4J JDK14 binding. Because Solr core is required by the embedded Solr server, we can skip this step if we are not using the embedded Solr server.</li></ol><p>We can complete these steps by adding the following XML to the dependencies section of the POM file:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #808080; font-style: italic;">&lt;!-- Spring Data Solr --&gt;</span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.springframework.data<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>spring-data-solr<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1.0.0.RC1<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> 
<br> <span style="color: #808080; font-style: italic;">&lt;!-- Required by embedded solr server --&gt;</span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.solr<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>solr-core<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>4.1.0<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;exclusions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;exclusion<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>slf4j-jdk14<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.slf4j<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/exclusion<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/exclusions<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dependency<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><h2>Configuring Spring Data Solr</h2><p>This section describes how we can configure Spring Data Solr to use different Solr servers in the development and production environment. We will use the embedded Solr server in the development environment and the HTTP Solr server in the production environment.</p><p>We can configure Spring Data Solr by following these steps:</p><ol><li>Create a properties file.</li><li>Configure the embedded Solr server.</li><li>Configure the HTTP Solr server.</li><li>Set the active bean definition profile.</li></ol><p>These steps are described with more details in the following subsections.</p><h3>Creating the Properties File</h3><p>The name of our properties file is <em>application.properties</em> and we will use it to configure two properties which are described in the following:</p><ul><li>The <em>solr.server.url</em> property specifies the url of the used Solr server. The value of this property is used to configure the HTTP Solr server which is used in the production environment.</li><li>The <em>solr.solr.home</em> configures the home directory of Solr. The value of this property is used to configure the home directory of the embedded Solr server which is used in the development environment.</li></ul><p>The content of the <em>application.properties</em> file looks as follows:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">solr.server.url=http://localhost:8983/solr/
<br> solr.solr.home=</div></div><h3>Configuring the Embedded Solr Server</h3><p>This subsection describes how we can configure Spring Data Solr to use the embedded Solr server in the development environment.</p><h4>Java Configuration</h4><p>We can create a configuration class which configures the embedded Solr server by following these steps:</p><ol><li>Create a class called <em>EmbeddedSolrContext</em> and annotate that class with the <em>@Configuration</em> annotation.</li><li>Enable Spring Data Solr repositories by annotating that class with the <em>@EnableSolrRepositories</em> annotation and configuring the root package of our Solr repositories.</li><li>Annotate the created class with the <em><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/context/annotation/Profile.html" target="_blank">@Profile annotation</a></em> and set its value to &#8216;dev&#8217;. This means that this configuration class is bypassed unless the &#8216;dev&#8217; profile have been activated.</li><li>Annotate the class with the <em>@PropertySource</em> annotation and set its value to &#8216;classpath:application.properties&#8217;. This configures the location of our property file and adds a <em><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/core/env/PropertySource.html" target="_blank">PropertySource</a></em> to Spring’s <em><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/core/env/Environment.html" target="_blank">Environment</a></em>.</li><li>Add an <em>Environment</em> field to the class and annotate that field with the <em>@Resource</em> annotation. The injected <em>Environment</em> is used to access the properties which we added to our properties file.</li><li>Create a method called <em>solrServerFactoryBean()</em> and annotate this method with the <em>@Bean</em> annotation. The implementation of this method creates a new <em>EmbeddedSolrServerFactoryBean</em> object, sets the value of the Solr home and returns the created object.</li><li>Create a method called <em>solrTemplate()</em> and annotate this method with the <em>@Bean</em> annotation. The implementation of this method creates a new <em>SolrTemplate</em> object and passes the used <em>SolrServer</em> implementation as a constructor argument.</li></ol><p>The source code of the <em>EmbeddedSolrContext</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:625px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.annotation.Bean</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.annotation.Configuration</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.annotation.Profile</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.core.env.Environment</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.SolrTemplate</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.config.EnableSolrRepositories</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.server.support.EmbeddedSolrServerFactoryBean</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @Configuration
<br> @EnableSolrRepositories<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;net.petrikainulainen.spring.datasolr.todo.repository.solr&quot;</span><span style="color: #009900;">&#41;</span>
<br> @Profile<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;dev&quot;</span><span style="color: #009900;">&#41;</span>
<br> @PropertySource<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;classpath:application.properties&quot;</span><span style="color: #009900;">&#41;</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> EmbeddedSolrContext <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Environment</span> environment<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Bean
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> EmbeddedSolrServerFactoryBean solrServerFactoryBean<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; EmbeddedSolrServerFactoryBean factory <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> EmbeddedSolrServerFactoryBean<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; factory.<span style="color: #006633;">setSolrHome</span><span style="color: #009900;">&#40;</span>environment.<span style="color: #006633;">getRequiredProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;solr.solr.home&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> factory<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; @Bean
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> SolrTemplate solrTemplate<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> SolrTemplate<span style="color: #009900;">&#40;</span>solrServerFactoryBean<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>XML Configuration</h4><p>We can create an XML configuration file for the embedded Solr server by following these steps:</p><ol><li>Configure the used properties file by using the <em>property-placeholder</em> element of the <em>context</em> namespace.</li><li>Enable Solr repositories and configure the base package of our Solr repositories by using the <em>repositories</em> element of the <em>solr</em> namespace.</li><li>Create a bean configuration for the development profile.</li><li>Configure the embedded Solr server bean by using the <em>embedded-solr-server</em> element of the <em>solr</em> namespace. Set the value of the Solr home.</li><li>Configure the Solr template bean. Set the configured embedded Solr server bean as constructor argument.</li></ol><p>The contents of the <em>exampleApplicationContext-solr.xml</em> file looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:500px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;beans</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:context</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/context&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:solr</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/data/solr&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/data/solr http://www.springframework.org/schema/data/solr/spring-solr.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;context:property-placeholder</span> <span style="color: #000066;">location</span>=<span style="color: #ff0000;">&quot;classpath:application.properties&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Enable Solr repositories and configure repository base package --&gt;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;solr:repositories</span> <span style="color: #000066;">base-package</span>=<span style="color: #ff0000;">&quot;net.petrikainulainen.spring.datasolr.todo.repository.solr&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Bean definitions for the dev profile --&gt;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;beans</span> <span style="color: #000066;">profile</span>=<span style="color: #ff0000;">&quot;dev&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configures embedded Solr server --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;solr:embedded-solr-server</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;solrServer&quot;</span> <span style="color: #000066;">solrHome</span>=<span style="color: #ff0000;">&quot;${solr.solr.home}&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configures Solr template --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bean</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;solrTemplate&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.springframework.data.solr.core.SolrTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constructor-arg</span> <span style="color: #000066;">index</span>=<span style="color: #ff0000;">&quot;0&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;solrServer&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/beans<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Bean definitions for the prod profile are omitted --&gt;</span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/beans<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><h3>Configuring the Http Solr Server</h3><p>This subsection describes how we can configure Spring Data Solr to use the HTTP Solr server in the production environment.</p><h4>Java Configuration</h4><p>We can create a configuration class which configures the HTTP Solr server by following these steps:</p><ol><li>Create a class called <em>HttpSolrContext</em> and annotate that class with the <em>@Configuration</em> annotation.</li><li>Enable Spring Data Solr repositories by annotating that class with the <em>@EnableSolrRepositories</em> annotation and configuring the root package of our Solr repositories.</li><li>Annotate the created class with a <em><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/context/annotation/Profile.html" target="_blank">@Profile annotation</a></em> and set its value to &#8216;prod&#8217;. This means that this configuration class is bypassed unless the &#8216;prod&#8217; profile have been activated.</li><li>Annotate the class with the <em>@PropertySource</em> annotation and set its value to &#8216;classpath:application.properties&#8217;. This configures the location of our property file and adds a <em><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/core/env/PropertySource.html" target="_blank">PropertySource</a></em> to Spring’s <em><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/core/env/Environment.html" target="_blank">Environment</a></em>.</li><li>Add an <em>Environment</em> field to the class and annotate that field with the <em>@Resource</em> annotation. The injected <em>Environment</em> is used to access the properties which we added to our properties file.</li><li>Create a method called <em>solrServerFactoryBean()</em> and annotate this method with the <em>@Bean</em> annotation. The implementation of this method create a new <em>HttpSolrServerFactoryBean</em> object, sets the value of the Solr server url and returns the created object.<li>Create a method called <em>solrTemplate()</em> and annotate this method with the <em>@Bean</em> annotation. The implementation of this method creates a new <em>SolrTemplate</em> object and passes the used <em>SolrServer</em> implementation as a constructor argument.</li></ol><p>The source code of the <em>HttpSolrContext</em> class looks as follows:</p><div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:625px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.annotation.Bean</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.annotation.Configuration</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.context.annotation.Profile</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.core.env.Environment</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.core.SolrTemplate</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.repository.config.EnableSolrRepositories</span><span style="color: #339933;">;</span>
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">org.springframework.data.solr.server.support.HttpSolrServerFactoryBean</span><span style="color: #339933;">;</span>
<br> 
<br> <span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.annotation.Resource</span><span style="color: #339933;">;</span>
<br> 
<br> @Configuration
<br> @EnableSolrRepositories<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;net.petrikainulainen.spring.datasolr.todo.repository.solr&quot;</span><span style="color: #009900;">&#41;</span>
<br> @Profile<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;prod&quot;</span><span style="color: #009900;">&#41;</span>
<br> @PropertySource<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;classpath:application.properties&quot;</span><span style="color: #009900;">&#41;</span>
<br> <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> HttpSolrContext <span style="color: #009900;">&#123;</span>
<br> 
<br> &nbsp; &nbsp; @Resource
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #003399;">Environment</span> environment<span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; @Bean
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> HttpSolrServerFactoryBean solrServerFactoryBean<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; HttpSolrServerFactoryBean factory <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> HttpSolrServerFactoryBean<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; factory.<span style="color: #006633;">setUrl</span><span style="color: #009900;">&#40;</span>environment.<span style="color: #006633;">getRequiredProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;solr.server.url&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> factory<span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> 
<br> &nbsp; &nbsp; @Bean
<br> &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">public</span> SolrTemplate solrTemplate<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> <span style="color: #003399;">Exception</span> <span style="color: #009900;">&#123;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> SolrTemplate<span style="color: #009900;">&#40;</span>solrServerFactoryBean<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;">&#125;</span>
<br> <span style="color: #009900;">&#125;</span></div></div><h4>XML Configuration</h4><p>We can create an XML configuration file for the HTTP Solr server by following these steps:</p><ol><li>Configure the used properties file by using the <em>property-placeholder</em> element of the <em>context</em> namespace.<li>Enable Solr repositories and configure the base package of our Solr repositories by using the <em>repositories</em> element of the <em>solr</em> namespace.<li>Create a bean configuration for the production profile.<li>Configure the HTTP Solr server bean by using the <em>solr-server</em> element of the <em>solr</em> namespace. Set the url of the Solr server.<li>Configure the Solr template bean. Set the configured HTTP Solr server bean as a constructor argument.</ol><p>The content of the <em>exampleApplicationContext-solr.xml</em> file looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:500px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;beans</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:xsi</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:context</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/context&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xmlns:solr</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/data/solr&quot;</span></span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; <span style="color: #000066;">xsi:schemaLocation</span>=<span style="color: #ff0000;">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</span>
<br> <span style="color: #009900;"> &nbsp; &nbsp; &nbsp; http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/data/solr http://www.springframework.org/schema/data/solr/spring-solr.xsd&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;context:property-placeholder</span> <span style="color: #000066;">location</span>=<span style="color: #ff0000;">&quot;classpath:application.properties&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Enable Solr repositories and configure repository base package --&gt;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;solr:repositories</span> <span style="color: #000066;">base-package</span>=<span style="color: #ff0000;">&quot;net.petrikainulainen.spring.datasolr.todo.repository.solr&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Bean definitions for the dev profile are omitted --&gt;</span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Bean definitions for the prod profile --&gt;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;beans</span> <span style="color: #000066;">profile</span>=<span style="color: #ff0000;">&quot;prod&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configures HTTP Solr server --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;solr:solr-server</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;solrServer&quot;</span> <span style="color: #000066;">url</span>=<span style="color: #ff0000;">&quot;${solr.server.url}&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> 
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configures Solr template --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;bean</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;solrTemplate&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;org.springframework.data.solr.core.SolrTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;constructor-arg</span> <span style="color: #000066;">index</span>=<span style="color: #ff0000;">&quot;0&quot;</span> <span style="color: #000066;">ref</span>=<span style="color: #ff0000;">&quot;solrServer&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/bean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/beans<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/beans<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><h3>Setting the Active Bean Definition Profile</h3><p>We can select the active bean definition profile by setting the value of the <em>spring.profiles.active</em> system variable. The allowed values of this system variable (in the context of our example application) are described in the following:</p><ul><li>We can configure our application to run in the development profile by setting the value of the <em>spring.profiles.active</em> system variable to &#8216;dev&#8217;.</li><li>When we want configure our application to run in the production profile, we have to set the of the <em>spring.profiles.active</em> system variable to &#8216;prod&#8217;.</li></ul><p>We can configure our example application to support both profiles by following these steps:</p><ol><li>Add required profiles to the POM file.</li><li>Create the profile specific properties files for system properties.</li><li>Configure the Jetty Maven plugin.</li></ol><p>These steps are described with more details in the following.</p><h4>Adding the Required Profiles to the POM File</h4><p>We can add the required profiles to our Maven build by following these steps:</p><ol><li>Create a profile for development environment. Set the <em>id</em> of this profile to &#8216;dev&#8217; and set the value of the <em>build.profile.id</em> property to &#8216;dev&#8217;.<li>Create a profile for the production environment. Set the <em>id</em> of this profile to &#8216;prod&#8217; and set the value of the <em>build.profile.id</em> property to &#8216;prod&#8217;.</ol><p>The configuration of our Maven profiles looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;profiles<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;profile<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>dev<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;properties<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;build.profile.id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>dev<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/build.profile.id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/properties<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/profile<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;profile<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>prod<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;properties<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;build.profile.id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>prod<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/build.profile.id<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/properties<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/profile<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/profiles<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><h4>Creating the Profile Specific Properties Files for System Properties</h4><p>The profile specific properties files are located in the sub directories of the <em>profiles</em> directory. The name of each sub directory matches with the values of the <em>build.profile.id</em> properties configured in the <em>pom.xml</em> file.</p><p>We can create the profile specific properties files for system properties by following these steps:</p><ol><li>Create a properties file called <em>system.properties</em> to the <em>profiles/dev</em> directory. This properties file contains the system properties of the development profile.</li><li>Create a properties file called <em>system.properties</em> to the <em>profiles/prod</em> directory. This properties file contains the system properties of the production profile.</li></ol><p>The content of the properties file used to configure the system properties of the development profile looks as follows:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">spring.profiles.active=dev</div></div><p>The content of the properties file used to configure the system properties of the production profile looks as follows:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">spring.profiles.active=prod</div></div><h4>Configuring the Jetty Maven Plugin</h4><p>We can configure the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin" target="_blank">Jetty Maven plugin</a> by following these steps:</p><ol><li>Add the plugin declaration of the Jetty Maven plugin to the <em>plugins</em> section of our Pom file.</li><li>Configure the <em>stopKey</em> and stopPort</em> of the Jetty Maven plugin.</li><li>Configure the location of the properties file containing the used system properties.</li></ol><p>The configuration of the Jetty Maven plugin looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.mortbay.jetty<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>jetty-maven-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>8.1.5.v20120716<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;stopKey<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>todostop<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/stopKey<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;stopPort<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>9999<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/stopPort<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;systemPropertiesFile<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${project.basedir}/profiles/${build.profile.id}/system.properties<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/systemPropertiesFile<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp;<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><h2>Summary</h2><p>We have now successfully obtained the required dependencies with Maven and configured Spring Data Solr. This blog entry has taught us four things:</p><ul><li>We learned to get the required dependencies with Maven.</li><li>We know that we should use the embedded Solr server only in the development environment and learned how we can configure Spring Data Solr to use it.</li><li>We learned that we should always use the HTTP Solr server in the production environment and know how we can configure Spring Data Solr to use it.</li><li>We know how we can use the bean definition profiles of Spring Framework for creating different configurations for development and production environment.</li></ul><p>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-crud-almost/">next part</a> of my Spring Data Solr tutorial describes how we can add new document to Solr index, update the information of an existing documents and delete documents from the Solr index.</p><p>PS. The example application of this blog entry is available at <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~https://github.com/pkainulainen/spring-data-solr-examples/tree/master/query-methods" target="_blank">Github</a>.</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/38218905/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/38218905/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/38218905/0/petrikainulainen~Spring-Data-Solr-Tutorial-Configuration/feed/</wfw:commentRss> <slash:comments>40</slash:comments></item>
<item>
<feedburner:origLink>http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/</feedburner:origLink><title>Spring Data Solr Tutorial: Introduction to Solr</title><link>http://feeds.feedblitz.com/~/37806676/0/petrikainulainen~Spring-Data-Solr-Tutorial-Introduction-to-Solr/</link> <comments>http://feeds.feedblitz.com/~/37806676/0/petrikainulainen~Spring-Data-Solr-Tutorial-Introduction-to-Solr/#comments</comments> <pubDate>Sun, 03 Feb 2013 13:21:34 +0000</pubDate> <dc:creator>Petri Kainulainen</dc:creator> <category><![CDATA[Solr]]></category><guid isPermaLink="false">http://www.petrikainulainen.net/?p=4598</guid> <description><![CDATA[Most of the applications must have a some kind of a search function. The problem is that search functions are often huge resource hogs and they can kill the performance of our application by causing heavy load to the database. That is why transferring that load to an external search server is a great idea. [...]]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</description> <content:encoded><![CDATA[<p><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-introduction-to-solr/" title="click to read"><img class="post_image" src="http://d2x79bjupkp9on.cloudfront.net/wp-content/uploads/opencataloguedrawer.jpg" alt="Open Catalogue Drawer" /></a></p><p>Most of the applications must have a some kind of a search function. The problem is that search functions are often huge resource hogs and they can kill the performance of our application by causing heavy load to the database. That is why transferring that load to an external search server is a great idea.</p><p>This is the first part of my Spring Data Solr tutorial. During this tutorial we will implement a search function to a todo application which is the example application of my <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/spring-mvc-test-tutorial/">Spring MVC Test tutorial</a>.</p><p>The requirements of our search function are simple. It must return a list of todo entries which title or description contains the used search term. The search result page must also provide a link to the page used to view the information of a todo entry.</p><p>Before we can start the implementation of our search function, we need to take a look at the Solr search server. This blog entry provides us the basic information about Solr and it is divided into three parts:</p><ul><li>The first part gives us a brief introduction to Solr and its data model.</li><li>The second part describes how we can create a schema for our Solr instance.</li><li>The last part describes how we can use the REST-like HTTP API provided by Solr.</li></ul><p>Let&#8217;s get started.</p><h2>A Brief Introduction to Solr</h2><p>Let’s start by getting a brief introduction to the Solr search server. This introduction is very thin and it provides only the information we need to know in order to understand the implementation of our search function.</p><p>Also, even though <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~lucene.apache.org/solr/" target="_blank">Solr</a> is heavily dependent from <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~lucene.apache.org/core/" target="_blank">Lucene</a>, this blog entry makes no difference between them.</p><p>This section describes</p><ul><li>The data model of Solr search server.</li><li>What happens when new documents are added to Solr.</li><li>What happens when a search query is executed against the indexed data.</li></ul><h3>The Data Model</h3><p>An <em>index</em> consists of <em>documents</em> which are essentially a collection of <em>fields</em>. If we compare this data model to the data model of a relational database, we notice the following similarities:</p><ul><li>An <em>index</em> is roughly the same than a database table.</li><li>A <em>document</em> is similar than a row of a database table.</li><li>A <em>field</em> means the same than a column of a database table.</li></ul><p>Each field of a document can be either <em>indexed</em>, <em>stored</em> or both. The meaning of these terms is described in the following:</p><ul><li>An <em>indexed</em> field is a field which is searchable and sortable. Indexed fields are not returned in the search results.</li><li>A <em>stored</em> field is field which value returned in the search results.</li><li>If a field is both <em>indexed</em> and <em>stored</em>, the field is both searchable and sortable. Its value is also returned in the search results.</li></ul><h3>Adding Information to the Index</h3><p>When a new document is added to Solr, indexed and stored fields are processed in a different way. This difference is described in the following:</p><ul><li>Indexed fields undergo an analysis phase which typically breaks the text into words and apply different transformations to it. The results of this analysis phase are saved to Solr index.</li><li>The values of stored fields are saved as is.</ul><h3>Searching Information from the Index</h3><p>The search function can be divided into three steps which are described in the following:</p><ul><li>Typically the search query undergo a similar analysis phase than the indexed fields. The goal of this is to ensure that the search query matches with the content of the index.</li><li>Solr uses its index to perform the search.</li><li>The matching documents are returned in the requested format. Each document contains the values of its stored fields.</li></ul><h2>Creating the Schema</h2><p>The schema is used to configure the following things:</p><ul><li>The fields of a document.</li><li>How the fields of document are processed when a new document is added to the index.</li><li>How the fields are dealt with when a search is executed against the index.</li></ul><p>The schema is configured in a file called <em>schema.xml</em>, and we can create a schema for our application by following these steps:</p><ol><li>Configure the used field types.</li><li>Configure the fields of our document.</li><li>Configure the copy fields.</li><li>Configure the unique key field of our document.</li></ol><p>These steps are described with more details in the following subsections. The skeleton schema of our Solr instance looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;schema</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;todo&quot;</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.5&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fields<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configure fields here --&gt;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/fields<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> 
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configure unique key --&gt;</span>
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configure copy fields here --&gt;</span>
<br> &nbsp; &nbsp; 
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;types<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configure field types here --&gt;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/types<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/schema<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><p><strong>Note</strong>: This section describes the schema of the example application of my blog entry called <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/maven/running-solr-with-maven/">Running Solr with Maven</a>.</p><h3>Configuring the Field Types</h3><p>A field type specifies the following things:</p><ul><li>The data type of the field.</li><li>How the information is analyzed when it is added to the index.</li><li>How the information is processed when information is searched from the index.</li></ul><p>We can configure a field type by using the <em>fieldType</em> element. Its attributes which are used in our schema are described in the following:</p><ul><li>The <em>name</em> attribute states the name of the field type. It is basically an alias which is used declare the type of a field.</li><li>The <em>class</em> attribute declares the class that implements the field type in question.</li><li>The <em>sortMissingLast</em> attribute specifies how the sorting works when the value of this field is missing. If the value of this attribute is set to &#8216;true&#8217;, the documents which don&#8217;t have value in the field in question are returned last.<li>The <em>positionIncrementGap</em> attribute declares the amount of empty space which is put between multiple fields of the same document. The value of this attribute is used in multivalued fields and its idea is to prevent false matches across different fields.</li><li>The <em>precisionStep</em> attribute is used in ranged queries of numeric fields. We can get more information about this by reading the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~lucene.apache.org/core/4_1_0/core/org/apache/lucene/search/NumericRangeQuery.html" target="_blank">API documentation of the NumericRangeQuery class</a>.</li></ul><p>We can configure the field types of our schema by following these steps:</p><ol><li>Configure the Field Type for Long Fields</li><li>Configure the Field Type for String Fields</li><li>Configure the Field Type for Fields Containing Text</li></ol><p>These steps are described with more details in the following.</p><h4>Configuring the Field Type for Long Fields</h4><p>Let&#8217;s start by configuring a simple field type for long fields which are not analyzed on the index or search phase. We can configure this field type by following these steps:</p><ol><li>Set the <em>name</em> of the field type to &#8216;long&#8217;.</li><li>Set the name of the implementing <em>class</em> to &#8216;solr.TrieLongField&#8217;.</li><li>Set the value of the <em>precisionStep</em> attribute to zero.</li><li>Set the value of the <em>positionIncrementGap</em> attribute to zero.</li></ol><p>Our field type declaration looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fieldType</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;long&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.TrieLongField&quot;</span> <span style="color: #000066;">precisionStep</span>=<span style="color: #ff0000;">&quot;0&quot;</span> <span style="color: #000066;">positionIncrementGap</span>=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></div><h4>Configuring the Field Type for String Fields</h4><p>The next step is to configure a simple field type for string fields which are not analyzed on the index or search phase. We can configure this field type by following these steps:</p><ol><li>Set the <em>name</em> of the field type to &#8216;string&#8217;.</li><li>Set the name of the implementing <em>class</em> to &#8216;solr.StrField&#8217;.<li>Set the value of the <em>sortMissingLast</em> attribute to &#8216;true&#8217;.</ol><p>The declaration of our string field looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fieldType</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;string&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.StrField&quot;</span> <span style="color: #000066;">sortMissingLast</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></div><h4>Configuring the Field Type for Fields Containing Text</h4><p>The last step is to configure the <em>text_general</em> field type. We can do this by following these steps:</p><ol><li>Create a new field type. Set the <em>name</em> of the field type to &#8216;text_general&#8217;. Set the name of the implementing <em>class</em> to &#8216;solr.TextField&#8217;. Set the value of the <em>positionIncrementGap</em> to 100.</li><li>Create a new analyzer which is run at the index time. Configure that the text is splitted into words by using the word break rules of <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~unicode.org/reports/tr29/" target="_blank">the Unicode Text Segmentation algorithm</a>. Create a filter which removes words found from <em>stopwords.txt</em> file from the text. Transform text to lower case.</li><li>Create a new analyzer which is run at the query phase.  Configure that the search query is splitted into words by using the word break rules of <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~unicode.org/reports/tr29/" target="_blank">the Unicode Text Segmentation algorithm</a>. Create a filter which removes words found from <em>stopwords.txt</em> file from the search query. Ensure that the synonyms found from <em>synonyms.txt</em> are applied. Transform the search query to lower case.</li></ol><p>The declaration of the <em>text_general</em> field type looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:430px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fieldType</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;text_general&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.TextField&quot;</span> <span style="color: #000066;">positionIncrementGap</span>=<span style="color: #ff0000;">&quot;100&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configures the analysis done at the index phase --&gt;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;analyzer</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;index&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Uses word break rules of the Unicode Text Segmentation algorith when splitting text into words. --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;tokenizer</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.StandardTokenizerFactory&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Removes words found from stopwords.txt file. This filter is case insensitive. --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.StopFilterFactory&quot;</span> <span style="color: #000066;">ignoreCase</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">words</span>=<span style="color: #ff0000;">&quot;stopwords.txt&quot;</span> <span style="color: #000066;">enablePositionIncrements</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Transforms text to lower case --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.LowerCaseFilterFactory&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/analyzer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Configures the analysis done at the query time --&gt;</span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;analyzer</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;query&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Uses word break rules of the Unicode Text Segmentation algorith when splitting text into words. --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;tokenizer</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.StandardTokenizerFactory&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Removes words found from stopwords.txt file. This filter is case insensitive. --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.StopFilterFactory&quot;</span> <span style="color: #000066;">ignoreCase</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">words</span>=<span style="color: #ff0000;">&quot;stopwords.txt&quot;</span> <span style="color: #000066;">enablePositionIncrements</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Applies synonyms found from the synonyms.txt file. --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.SynonymFilterFactory&quot;</span> <span style="color: #000066;">synonyms</span>=<span style="color: #ff0000;">&quot;synonyms.txt&quot;</span> <span style="color: #000066;">ignoreCase</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">expand</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!-- Transforms text to lower case --&gt;</span>
<br> &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;filter</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;solr.LowerCaseFilterFactory&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/analyzer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/fieldType<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><p>We can get more information about the analysis phase by reading the following documents:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/AnalyzersTokenizersTokenFilters" target="_blank">Analyzers, Tokenizers and Token Filters</a>.</li></ul><h3>Configuring the Fields of Our Document</h3><p>We can add new fields to our document by adding <em>field</em> elements to the <em>schema.xml</em> file. <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/SchemaXml#Common_field_options" target="_blank">The <em>field</em> element has many attributes</a> but at this point we need to understand the meaning of following attributes:</p><ul><li>The <em>name</em> attribute specifies the name of the field.</li><li>The <em>indexed</em> attribute (true/false) specifies if the field is added to the search index. Only indexed fields are searchable and sortable.</li><li>The <em>stored</em> attribute(true/false) specifies if the field should be returned in the search results.</li><li>The <em>multiValued</em> (true/false) specifies if the field can appear in the document more than once.</li><li>The <em>type</em> type attribute specifies the type of the field.</li><li>The <em>required</em> (true/false) specifies whether the field is required or not.</li></ul><p>In order to make maximize the performance of our Solr instance, we must follow the following guidelines:</p><ul><li>We should not store fields which are not required in the search results.</li><li>We should not index the fields which are not used by our search function.</li></ul><p>We can get more information about the optimal field configuration by reading the following documents:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/FieldOptionsByUseCase" target="_blank">Field Options by Use Case</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/SolrPerformanceFactors" target="_blank">Solr Performance Factors</a></li></ul><p>We are now ready to configure the actual fields of our schema. Let’s first talk a bit about the information which we need show on the search result page. This information is described in the following:</p><ul><li>We need the id of the todo entry which is used to create a link to the view todo entry page.</li><li>We need the title of the todo entry which is used as an anchor text of the created link.</li></ul><p>When we know that our application must be able to search the contents of the title and description of a todo entry, we can add the required fields to our schema by following these steps:</p><ol><li>Add a required field called &#8216;id&#8217; to the schema and set its type to &#8216;string&#8217;. Ensure that this field is both indexed and stored. Set the value of the <em>multiValued</em> attribute to false.</li><li>Add a required field called &#8216;title&#8217; to the schema and its type to &#8216;text_general&#8217;. Configure this field to be both indexed and stored. Set the value of the <em>multivalued</em> attribute to false.</li><li>Add a field called &#8216;description&#8217; the schema sets its type to &#8216;text_general&#8217;. Configure this field to be indexed but not stored. Set the value of the <em>multiValued</em> attribute to false.</li><li>Add a field called &#8216;text&#8217; and set its type &#8216;text_general&#8217;. Configure this field to be indexed but not stored. Set the value of its <em>multiValue</em> attribute to true. This field is a field which stores the content of all other indexed text fields.</li><li>Add a field called &#8216;_version_&#8217; and sets its type &#8216;long&#8217;. Configure this field to be indexed and stored.</ol><p>Our field declarations looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;id&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;string&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">required</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;title&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text_general&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">required</span>=“true” <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text_general&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;text&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text_general&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000066;">multiValued</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;field</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;_version_&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;long&quot;</span> <span style="color: #000066;">indexed</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">stored</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></div><h3>Configuring the Copy Fields</h3><p>We use <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/SchemaXml#Copy_Fields" target="_blank">copy fields</a> to copy the contents of <em>title</em> and <em>description</em> fields to the <em>text</em> field. We can configure the copy fields by using the <em>copyField</em> element. We can create the required configuration by following these steps:</p><ol><li>Create a copy field which copies the value of the &#8216;title&#8217; field to the &#8216;text&#8217; field.</li><li>Create a copy field which copies the value of the &#8216;description&#8217; field to the &#8216;text&#8217; field.</li></ol><p>The declaration of our copy fields looks as follows:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;copyField</span> <span style="color: #000066;">source</span>=<span style="color: #ff0000;">&quot;title&quot;</span> <span style="color: #000066;">dest</span>=<span style="color: #ff0000;">&quot;text&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<br> <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;copyField</span> <span style="color: #000066;">source</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">dest</span>=<span style="color: #ff0000;">&quot;text&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></div><h3>Configuring the Unique Key Field of Our Document</h3><p>The <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/SchemaXml#The_Unique_Key_Field" target="_blank">unique key</a> is a field which should be unique for all documents. It is not mandatory to specify the unique key of a document but if we decide to do so, it means that the index cannot contain two documents which both have same value in the field configured as the unique key.</p><p>In our case, we use the field &#8216;id&#8217; as the unique key of our document. We can make this configuration by adding the following XML to the <em>schema.xml</em> file:</p><div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;uniqueKey<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>id<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/uniqueKey<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div><h2>Using the REST-like HTTP API</h2><p>Solr offers a REST-like HTTP API which we can use to add information to Solr and execute search queries against its index. Both of these use cases are described in the following.</p><p><strong>Note</strong>: This section assumes that we are using the example application of my blog entry called <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/maven/running-solr-with-maven/">Running Solr with Maven</a>.</p><h3>Adding Information to Solr</h3><p>We can add new information to Solr by following these steps:</p><ol><li>Send a POST request to the url &#8216;http://localhost:8983/solr/update/json?commit=true&#8217;.</li><li>Set content type of the request to &#8216;application/json&#8217;.</li><li>Sending the added information in the body of the request as JSON.</li></ol><p>The contents of our request body looks as follows:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[
<br> &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;id&quot;:&quot;1&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;title&quot;:&quot;Write introduction to Solr&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;description&quot;:&quot;This blog entry provides an introduction to Solr search server&quot;
<br> &nbsp; &nbsp; },
<br> &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;id&quot;:&quot;2&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;title&quot;:&quot;Implement example application&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &quot;description&quot;:&quot;This application demonstrates the usage of spring-data-solr.&quot;
<br> &nbsp; &nbsp; }
<br> ]</div></div><p>We have now added two documents to our Solr index by using the REST-like API provided by Solr.</p><p>However, it is good to know that there are other options which we can use to add information to the Solr index. These options are described in the following documents:</p><ul><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/UpdateJSON" target="_blank">POST JSON documents</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/DataImportHandler" target="_blank">Import records from a database</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/UpdateCSV" target="_blank">Load data from a CSV file</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/ExtractingRequestHandler" target="_blank">Index binary documents</a></li><li><a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/Solrj" target="_blank">Use SolrJ</a></li></ul><h3>Searching Information from Solr Index</h3><p>We are now ready to search the information stored in the index of our Solr instance. We can execute search queries against the Solr index by following these guidelines:</p><ul><li>The search query is executed by sending a GET request to the url &#8216;http://localhost:8983/solr/todo/select&#8217;.</li><li>The query string must be set as the value of the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/CommonQueryParameters#q" target="_blank"><em>q</em> request parameter</a>.</li><li>The format of the query results must be set as the value of the <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~wiki.apache.org/solr/CoreQueryParameters#wt" target="_blank"><em>wt</em> request parameter</a>.</li></ul><p>Let&#8217;s move on and find out how we can list all documents found from the index and execute a simple search query against the indexed data.</p><h4>Finding All Documents of the Index</h4><p>We can list all documents in JSON format by following these steps:</p><ol><li>Send a GET request to the url &#8216;http://localhost:8983/solr/todo/select&#8217;.</li><li>Set the value of <em>q</em> request parameter to &#8216;*.*&#8217;</li><li>Set the value of the <em>wt</em> request parameter to &#8216;json&#8217;.</ol><p>When we send a GET request to the url &#8216;http://localhost:8983/solr/todo/select?q=*%3A*&#038;wt=json&#8217;, we should receive the following JSON:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:500px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">{
<br> &nbsp; &nbsp; &quot;responseHeader&quot;: {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;status&quot;:0,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;QTime&quot;:1,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;params&quot;:{
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;wt&quot;:&quot;json&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;q&quot;:&quot;*:*&quot;
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
<br> &nbsp; &nbsp; },
<br> &nbsp; &nbsp; &quot;response&quot;:{
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;numFound&quot;:2,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;start&quot;:0,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;docs&quot;:[
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;id&quot;:&quot;1&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;title&quot;:&quot;Write introduction to Solr&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;_version_&quot;:1425949176574771200
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;id&quot;:&quot;2&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;title&quot;:&quot;Implement example application&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;_version_&quot;:1425949176662851584
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ]
<br> &nbsp; &nbsp; }
<br> }</div></div><h4>Searching Information from the Index</h4><p>We can search all documents which title or description contains the word &#8216;application&#8217; by following these steps:</p><ol><li>Send a GET request to the url &#8216;http://localhost:8983/solr/todo/select&#8217;.</li><li>Set the value of <em>q</em> request parameter to &#8216;application&#8217;</li><li>Set the value of the <em>wt</em> request parameter to &#8216;json&#8217;.</ol><p>When we send a GET request tot he url &#8216;http://localhost:8983/solr/todo/select?q=application&#038;wt=json&#8217;, we should receive the following JSON:</p><div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:400px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">{
<br> &nbsp; &nbsp; &quot;responseHeader&quot;:{
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;status&quot;:0,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;QTime&quot;:7,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;params&quot;:{
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;wt&quot;:&quot;json&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;q&quot;:&quot;application&quot;
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
<br> &nbsp; &nbsp; },
<br> &nbsp; &nbsp; &quot;response&quot;:{
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;numFound&quot;:1,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;start&quot;:0,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;docs&quot;:[
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;id&quot;:&quot;2&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;title&quot;:&quot;Implement example application&quot;,
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;_version_&quot;:1425949176662851584
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ]
<br> &nbsp; &nbsp; }
<br> }</div></div><h2>The End</h2><p>We have now obtained the information which is required to understand the concepts described in the next parts of my Spring Data Solr tutorial. This blog entry has teached us three things:</p><ul><li>We know the basics of the Solr data model.</li><li>We know how we can configure the schema of our Solr instance.</li><li>We know how we can add documents to the Solr index and search information from it by using the HTTP API of Solr.</ul><p>The next part of this tutorial describes how we can <a href="http://feeds.feedblitz.com/~/t/0/0/petrikainulainen/~www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-configuration/">get the required dependencies with Maven and configure Spring Data Solr</a>.</p> <Img align="left" border="0" height="1" width="1" style="border:0;float:left;margin:0;padding:0" hspace="0" src="http://feeds.feedblitz.com/~/i/37806676/0/petrikainulainen">
]]>
&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Like on Facebook&quot; href=&quot;http://feeds.feedblitz.com/_/28/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fblike20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feeds.feedblitz.com/_/30/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to LinkedIn&quot; href=&quot;http://feeds.feedblitz.com/_/16/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/linkedin20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feeds.feedblitz.com/_/24/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feeds.feedblitz.com/_/20/37806676/PetriKainulainen&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&lt;h3 style=&quot;clear:left;padding-top:10px&quot;&gt;Related Stories&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-sorting/&quot;&gt;Spring Data Solr Tutorial: Sorting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-dynamic-queries/&quot;&gt;Spring Data Solr Tutorial: Dynamic Queries&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;http://www.petrikainulainen.net/programming/solr/spring-data-solr-tutorial-adding-custom-methods-to-a-single-repository/&quot;&gt;Spring Data Solr Tutorial: Adding Custom Methods to a Single Repository&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&amp;#160;&lt;/div&gt;</content:encoded> <wfw:commentRss>http://feeds.feedblitz.com/~/37806676/0/petrikainulainen~Spring-Data-Solr-Tutorial-Introduction-to-Solr/feed/</wfw:commentRss> <slash:comments>3</slash:comments></item>
</channel></rss>

