#8 - Some polishing of the example.

Introduced the usage of Lombok to be able to get rid off the getters and setters. Simplified the configuration to use Spring Boot's auto-configuration. The initializer is now an enum manually triggered with a MongoOperations instance. Switched from MongoTemplate to MongoOperations where possible. Polished some JavaDoc.

Original pull request: #10.
This commit is contained in:
Oliver Gierke
2014-09-01 17:00:27 +02:00
parent 09317bc6de
commit ecadc65483
8 changed files with 83 additions and 114 deletions

View File

@@ -23,4 +23,4 @@
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
</project>

View File

@@ -17,15 +17,21 @@ package example.springdata.mongodb.textsearch;
import java.util.List;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.TextIndexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.TextScore;
/**
* Document representation of a {@link BlogPost} carrying annotation based information for text indexes.
*
* @author Christoph Strobl
* @author Oliver Gierke
*/
@Document
@Data
public class BlogPost {
private @Id String id;
@@ -33,50 +39,4 @@ public class BlogPost {
private @TextIndexed(weight = 2) String content;
private @TextIndexed List<String> categories;
private @TextScore Float score;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public List<String> getCategories() {
return categories;
}
public void setCategories(List<String> categories) {
this.categories = categories;
}
public Float getScore() {
return score;
}
public void setScore(Float score) {
this.score = score;
}
@Override
public String toString() {
return "BlogPost [score=" + score + ", id=" + id + ", title=" + title + ", categories=" + getCategories() + "]";
}
}

View File

@@ -15,46 +15,35 @@
*/
package example.springdata.mongodb.textsearch;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import org.springframework.data.mongodb.core.MongoOperations;
import example.springdata.mongodb.util.BlogPostInitializer;
/**
* @author Christoph Strobl
* @author Oliver Gierke
*/
@Configuration
@EnableMongoRepositories
public class MongoTestConfiguration extends AbstractMongoConfiguration {
@EnableAutoConfiguration
public class MongoTestConfiguration {
static final String DATABASE_NAME = "s2gx2014-blog";
static final String BLOG_POST_ATOM_FEED_SOURCE = "https://spring.io/blog.atom";
@Override
protected String getDatabaseName() {
return DATABASE_NAME;
}
@Override
public Mongo mongo() throws Exception {
return new MongoClient();
}
@Autowired MongoOperations operations;
/**
* Initializes the repository with a predefined set of entities.
*
* @return
* @throws Exception
*/
@Bean
public BlogPostInitializer initializer() {
return new BlogPostInitializer(BLOG_POST_ATOM_FEED_SOURCE);
@PostConstruct
void initialize() throws Exception {
BlogPostInitializer.INSTANCE.initialize(operations);
}
/**
@@ -63,8 +52,7 @@ public class MongoTestConfiguration extends AbstractMongoConfiguration {
* @throws Exception
*/
@PreDestroy
public void dropTestDB() throws Exception {
mongo().dropDatabase(getDatabaseName());
void dropTestDB() throws Exception {
operations.dropCollection(BlogPost.class);
}
}

View File

@@ -22,12 +22,16 @@ import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.mapping.TextScore;
import org.springframework.data.mongodb.core.query.TextCriteria;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Integration tests showing the text search functionality using repositories.
*
* @author Christoph Strobl
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { MongoTestConfiguration.class })
@@ -44,6 +48,7 @@ public class TextSearchRepositoryTests {
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny("release");
List<BlogPost> blogPosts = repo.findAllBy(criteria);
printResult(blogPosts, criteria);
}
@@ -55,6 +60,7 @@ public class TextSearchRepositoryTests {
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny("release").notMatching("engineering");
List<BlogPost> blogPosts = repo.findAllBy(criteria);
printResult(blogPosts, criteria);
}
@@ -66,17 +72,19 @@ public class TextSearchRepositoryTests {
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingPhrase("release candidate");
List<BlogPost> blogPosts = repo.findAllBy(criteria);
printResult(blogPosts, criteria);
}
/**
* Sort by relevance relying on the value marked with {@link org.springframework.data.mongodb.core.mapping.TextScore}.
* Sort by relevance relying on the value marked with {@link TextScore}.
*/
@Test
public void findAllBlogPostsByPhraseSortByScore() {
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingPhrase("release candidate");
List<BlogPost> blogPosts = repo.findAllByOrderByScoreDesc(criteria);
printResult(blogPosts, criteria);
}
}

View File

@@ -22,14 +22,14 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.index.TextIndexDefinition;
import org.springframework.data.mongodb.core.index.TextIndexDefinition.TextIndexDefinitionBuilder;
import org.springframework.data.mongodb.core.query.TextCriteria;
import org.springframework.data.mongodb.core.query.TextQuery;
import com.mongodb.MongoClient;
import example.springdata.mongodb.util.BlogPostInitializer;
/**
@@ -37,16 +37,19 @@ import example.springdata.mongodb.util.BlogPostInitializer;
*/
public class TextSearchTemplateTests {
MongoTemplate template;
MongoOperations operations;
@Before
public void setUp() throws Exception {
template = new MongoTemplate(new MongoClient(), MongoTestConfiguration.DATABASE_NAME);
template.dropCollection(BlogPost.class);
MongoProperties properties = new MongoProperties();
operations = new MongoTemplate(properties.createMongoClient(null), properties.getMongoClientDatabase());
operations.dropCollection(BlogPost.class);
createIndex();
loadTestData();
BlogPostInitializer.INSTANCE.initialize(this.operations);
}
/**
@@ -57,7 +60,8 @@ public class TextSearchTemplateTests {
public void findAllBlogPostsWithRelease() {
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny("release");
List<BlogPost> blogPosts = template.find(query(criteria), BlogPost.class);
List<BlogPost> blogPosts = operations.find(query(criteria), BlogPost.class);
printResult(blogPosts, criteria);
}
@@ -73,7 +77,8 @@ public class TextSearchTemplateTests {
query.setScoreFieldName("score");
query.sortByScore();
List<BlogPost> blogPosts = template.find(query, BlogPost.class);
List<BlogPost> blogPosts = operations.find(query, BlogPost.class);
printResult(blogPosts, criteria);
}
@@ -106,13 +111,6 @@ public class TextSearchTemplateTests {
.onField("categories") //
.build();
template.indexOps(BlogPost.class).ensureIndex(textIndex);
operations.indexOps(BlogPost.class).ensureIndex(textIndex);
}
private void loadTestData() throws Exception {
BlogPostInitializer initializer = new BlogPostInitializer(MongoTestConfiguration.BLOG_POST_ATOM_FEED_SOURCE);
initializer.initialize(this.template);
}
}

View File

@@ -18,11 +18,12 @@ package example.springdata.mongodb.util;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;
import com.sun.syndication.feed.atom.Category;
@@ -33,47 +34,58 @@ import com.sun.syndication.feed.atom.Feed;
import example.springdata.mongodb.textsearch.BlogPost;
/**
* Component to initialize {@link BlogPost}s by accessing the latest ones from the Spring blog.
*
* @author Christoph Strobl
* @author Oliver Gierke
*/
public class BlogPostInitializer implements InitializingBean {
@Slf4j
public enum BlogPostInitializer {
private final String url;
private final RestTemplate restTemplate;
private final Converter<Entry, BlogPost> converter;
INSTANCE;
@Autowired MongoTemplate mongoTemplate;
private final RestTemplate restTemplate = new RestTemplate();
private final Converter<Entry, BlogPost> converter = EntryConverter.INSTANCE;
private final String url = "https://spring.io/blog.atom";
public BlogPostInitializer(String url) {
/**
* Initializes the given {@link MongoOperations} with {@link BlogPost}s from the Spring Blog.
*
* @param operations must not be {@literal null}.
*/
public void initialize(MongoOperations operations) {
restTemplate = new RestTemplate();
this.converter = new EntryConverter();
this.url = url;
}
public void initialize(MongoTemplate mongoTemplate) {
Assert.notNull(operations, "MongoOperations must not be null!");
ResponseEntity<Feed> feed = restTemplate.getForEntity(url, Feed.class);
int count = 0;
if (feed.hasBody()) {
for (Object entry : feed.getBody().getEntries()) {
if (entry instanceof Entry) {
mongoTemplate.save(converter.convert((Entry) entry));
operations.save(converter.convert((Entry) entry));
count++;
}
}
}
}
@Override
public void afterPropertiesSet() throws Exception {
initialize(this.mongoTemplate);
log.info("Imported {} blog posts from spring.io!", count);
}
/**
* {@link Converter} implementation capable of converting atom feed {@link Entry} into {@link BlogPost}.
*
* @author Christoph Strobl
* @author Oliver Gierke
*/
static class EntryConverter implements Converter<Entry, BlogPost> {
private enum EntryConverter implements Converter<Entry, BlogPost> {
INSTANCE;
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public BlogPost convert(Entry source) {
@@ -89,15 +101,16 @@ public class BlogPostInitializer implements InitializingBean {
}
List<String> categories = new ArrayList<String>();
for (Object category : source.getCategories()) {
if (category instanceof Category) {
categories.add(((Category) category).getLabel());
}
}
post.setCategories(categories);
return post;
}
}
}

View File

@@ -36,7 +36,7 @@ public class ConsoleResultPrinter {
for (BlogPost blogPost : blogPosts) {
System.out.println(blogPost);
}
System.out.println("XXXXXXXXXXXX -- XXXXXXXXXXXX -- XXXXXXXXXXXX\r\n");
}
}

View File

@@ -10,5 +10,7 @@
<root level="warn">
<appender-ref ref="console" />
</root>
<logger name="example.springdata" level="info" />
</configuration>
</configuration>