This year I greeted Christmas in a different fashion: I was a part of the Java Advent Calendar. Let's boot up for Christmas:
Spring Boot is an opinionated framework that simplifies the development of Spring applications. It frees us from the slavery of complex configuration files and helps us to create standalone Spring applications that don’t need an external servlet container.
This sounds almost too good to be true, but Spring Boot can really do all this.
This blog post demonstrates how easy it is to implement a REST API that provides CRUD operations for todo entries that are saved to MongoDB database.
Let’s start by creating our Maven project.
Creating Our Maven Project
We can create our Maven project by following these steps:
- Use the spring-boot-starter-parent POM as the parent POM of our Maven project. This ensures that our project inherits sensible default settings from Spring Boot.
- Add the Spring Boot Maven Plugin to our project. This plugin allows us to package our application into an executable jar file, package it into a war archive, and run the application.
- Configure the dependencies of our project. We need to configure the following dependencies:
- The spring-boot-starter-web dependency provides the dependencies of a web application.
- The spring-data-mongodb dependency provides integration with the MongoDB document database.
- Enable the Java 8 Support of Spring Boot.
- Configure the main class of our application. This class is responsible of configuring and starting our application.
The relevant part of our pom.xml file looks as follows:
<properties> <!-- Enable Java 8 --> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- Configure the main class of our Spring Boot application --> <start-class>com.javaadvent.bootrest.TodoAppConfig</start-class> </properties> <!-- Inherit defaults from Spring Boot --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.1.9.RELEASE</version> </parent> <dependencies> <!-- Get the dependencies of a web application --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Data MongoDB--> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> </dependency> </dependencies> <build> <plugins> <!-- Spring Boot Maven Support --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
Let’s move on and find out how we can configure our application.
Configuring Our Application
We can configure our Spring Boot application by following these steps:
- Create a TodoAppConfig class to the com.javaadvent.bootrest package.
- Enable Spring Boot auto-configuration.
- Configure the Spring container to scan components found from the child packages of the com.javaadvent.bootrest package.
- Add the main() method to the TodoAppConfig class and implement by running our application.
The source code of the TodoAppConfig class looks as follows:
package com.javaadvent.bootrest; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @EnableAutoConfiguration @ComponentScan public class TodoAppConfig { public static void main(String[] args) { SpringApplication.run(TodoAppConfig.class, args); } }
We have now created the configuration class that configures and runs our Spring Boot application. Because the MongoDB jars are found from the classpath, Spring Boot configures the MongoDB connection by using its default settings.
- Spring Boot Reference Manual: 13.2 Location the main application class
- Spring Boot Reference Manual: 14. Configuration classes
- The Javadoc of the @EnableAutoConfiguration annotation
- Spring Boot Reference Manual: 15. Auto-configuration
- The Javadoc of the SpringApplication class
- Spring Boot Reference Manual: 27.2.1 Connecting to a MongoDB database
Let’s move on and implement our REST API.
Implementing Our REST API
We need implement a REST API that provides CRUD operations for todo entries. The requirements of our REST API are:
- A POST request send to the url ‘/api/todo’ must create a new todo entry by using the information found from the request body and return the information of the created todo entry.
- A DELETE request send to the url ‘/api/todo/{id}’ must delete the todo entry whose id is found from the url and return the information of the deleted todo entry.
- A GET request send to the url ‘/api/todo’ must return all todo entries that are found from the database.
- A GET request send to the url ‘/api/todo/{id}’ must return the information of the todo entry whose id is found from the url.
- A PUT request send to the url ‘/api/todo/{id}’ must update the information of an existing todo entry by using the information found from the request body and return the information of the updated todo entry.
We can fulfill these requirements by following these steps:
- Create the entity that contains the information of a single todo entry.
- Create the repository that is used to save todo entries to MongoDB database and find todo entries from it.
- Create the service layer that is responsible of mapping DTOs into domain objects and vice versa. The purpose of our service layer is to isolate our domain model from the web layer.
- Create the controller class that processes HTTP requests and returns the correct response back to the client.
Let’s get started.
Creating the Entity
We need to create the entity class that contains the information of a single todo entry. We can do this by following these steps:
- Add the id, description, and title fields to the created entity class. Configure the id field of the entity by annotating the id field with the @Id annotation.
- Specify the constants (MAX_LENGTH_DESCRIPTION and MAX_LENGTH_TITLE) that specify the maximum length of the description and title fields.
- Add a static builder class to the entity class. This class is used to create new Todo objects.
- Add an update() method to the entity class. This method simply updates the title and description of the entity if valid values are given as method parameters.
The source code of the Todo class looks as follows:
import org.springframework.data.annotation.Id; import static com.javaadvent.bootrest.util.PreCondition.isTrue; import static com.javaadvent.bootrest.util.PreCondition.notEmpty; import static com.javaadvent.bootrest.util.PreCondition.notNull; final class Todo { static final int MAX_LENGTH_DESCRIPTION = 500; static final int MAX_LENGTH_TITLE = 100; @Id private String id; private String description; private String title; public Todo() {} private Todo(Builder builder) { this.description = builder.description; this.title = builder.title; } static Builder getBuilder() { return new Builder(); } //Other getters are omitted public void update(String title, String description) { checkTitleAndDescription(title, description); this.title = title; this.description = description; } /** * We don't have to use the builder pattern here because the constructed * class has only two String fields. However, I use the builder pattern * in this example because it makes the code a bit easier to read. */ static class Builder { private String description; private String title; private Builder() {} Builder description(String description) { this.description = description; return this; } Builder title(String title) { this.title = title; return this; } Todo build() { Todo build = new Todo(this); build.checkTitleAndDescription(build.getTitle(), build.getDescription()); return build; } } private void checkTitleAndDescription(String title, String description) { notNull(title, "Title cannot be null"); notEmpty(title, "Title cannot be empty"); isTrue(title.length() <= MAX_LENGTH_TITLE, "Title cannot be longer than %d characters", MAX_LENGTH_TITLE ); if (description != null) { isTrue(description.length() <= MAX_LENGTH_DESCRIPTION, "Description cannot be longer than %d characters", MAX_LENGTH_DESCRIPTION ); } } }
Let's move on and create the repository that communicates with the MongoDB database.
Creating the Repository
We have to create the repository interface that is used to save Todo objects to MondoDB database and retrieve Todo objects from it.
If we don’t want to use the Java 8 support of Spring Data, we could create our repository by creating an interface that extends the CrudRepository<T, ID> interface. However, because we want to use the Java 8 support, we have to follow these steps:
- Create an interface that extends the Repository<T, ID> interface.
- Add the following repository methods to the created interface:
- The void delete(Todo deleted) method deletes the todo entry that is given as a method parameter.
- The List
findAll() method returns all todo entries that are found from the database. - The Optional
findOne(String id) method returns the information of a single todo entry. If no todo entry is found, this method returns an empty Optional. - The Todo save(Todo saved) method saves a new todo entry to the database and returns the the saved todo entry.
The source code of the TodoRepository interface looks as follows:
import org.springframework.data.repository.Repository; import java.util.List; import java.util.Optional; interface TodoRepository extends Repository<Todo, String> { void delete(Todo deleted); List<Todo> findAll(); Optional<Todo> findOne(String id); Todo save(Todo saved); }
Let’s move on and create the service layer of our example application.
Creating the Service Layer
First, we have to create a service interface that provides CRUD operations for todo entries. The source code of the TodoService interface looks as follows:
import java.util.List; interface TodoService { TodoDTO create(TodoDTO todo); TodoDTO delete(String id); List<TodoDTO> findAll(); TodoDTO findById(String id); TodoDTO update(TodoDTO todo); }
Second, we have to implement the TodoService interface. We can do this by following these steps:
- Inject our repository to the service class by using constructor injection.
- Add a private Todo findTodoById(String id) method to the service class and implement it by either returning the found Todo object or throwing the TodoNotFoundException.
- Add a private TodoDTO convertToDTO(Todo model) method the service class and implement it by converting the Todo object into a TodoDTO object and returning the created object.
- Add a private List
convertToDTOs(List and implement it by converting the list of Todo objects into a list of TodoDTO objects and returning the created list.models) - Implement the TodoDTO create(TodoDTO todo) method. This method creates a new Todo object, saves the created object to the MongoDB database, and returns the information of the created todo entry.
- Implement the TodoDTO delete(String id) method. This method finds the deleted Todo object, deletes it, and returns the information of the deleted todo entry. If no Todo object is found with the given id, this method throws the TodoNotFoundException.
- Implement the List
findAll() method. This methods retrieves all Todo objects from the database, transforms them into a list of TodoDTO objects, and returns the created list. - Implement the TodoDTO findById(String id) method. This method finds the Todo object from the database, converts it into a TodoDTO object, and returns the created TodoDTO object. If no todo entry is found, this method throws the TodoNotFoundException.
- Implement the TodoDTO update(TodoDTO todo) method. This method finds the updated Todo object from the database, updates its title and description, saves it, and returns the updated information. If the updated Todo object is not found, this method throws the TodoNotFoundException.
The source code of the MongoDBTodoService looks as follows:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; import static java.util.stream.Collectors.toList; @Service final class MongoDBTodoService implements TodoService { private final TodoRepository repository; @Autowired MongoDBTodoService(TodoRepository repository) { this.repository = repository; } @Override public TodoDTO create(TodoDTO todo) { Todo persisted = Todo.getBuilder() .title(todo.getTitle()) .description(todo.getDescription()) .build(); persisted = repository.save(persisted); return convertToDTO(persisted); } @Override public TodoDTO delete(String id) { Todo deleted = findTodoById(id); repository.delete(deleted); return convertToDTO(deleted); } @Override public List<TodoDTO> findAll() { List<Todo> todoEntries = repository.findAll(); return convertToDTOs(todoEntries); } private List<TodoDTO> convertToDTOs(List<Todo> models) { return models.stream() .map(this::convertToDTO) .collect(toList()); } @Override public TodoDTO findById(String id) { Todo found = findTodoById(id); return convertToDTO(found); } @Override public TodoDTO update(TodoDTO todo) { Todo updated = findTodoById(todo.getId()); updated.update(todo.getTitle(), todo.getDescription()); updated = repository.save(updated); return convertToDTO(updated); } private Todo findTodoById(String id) { Optional<Todo> result = repository.findOne(id); return result.orElseThrow(() -> new TodoNotFoundException(id)); } private TodoDTO convertToDTO(Todo model) { TodoDTO dto = new TodoDTO(); dto.setId(model.getId()); dto.setTitle(model.getTitle()); dto.setDescription(model.getDescription()); return dto; } }
We have now created the service layer of our example application. Let's move on and create the controller class.
Creating the Controller Class
First, we need to create the DTO class that contains the information of a single todo entry and specifies the validation rules that are used to ensure that only valid information can be saved to the database. The source code of the TodoDTO class looks as follows:
import org.hibernate.validator.constraints.NotEmpty; import javax.validation.constraints.Size; public final class TodoDTO { private String id; @Size(max = Todo.MAX_LENGTH_DESCRIPTION) private String description; @NotEmpty @Size(max = Todo.MAX_LENGTH_TITLE) private String title; //Constructor, getters, and setters are omitted }
Second, we have to create the controller class that processes the HTTP requests send to our REST API and sends the correct response back to the client. We can do this by following these steps:
- Inject our service to our controller by using constructor injection.
- Add a create() method to our controller and implement it by following these steps:
- Read the information of the created todo entry from the request body.
- Validate the information of the created todo entry.
- Create a new todo entry and return the created todo entry. Set the response status to 201.
- Implement the delete() method by delegating the id of the deleted todo entry forward to our service and return the deleted todo entry.
- Implement the findAll() method by finding the todo entries from the database and returning the found todo entries.
- Implement the findById() method by finding the todo entry from the database and returning the found todo entry.
- Implement the update() method by following these steps:
- Read the information of the updated todo entry from the request body.
- Validate the information of the updated todo entry.
- Update the information of the todo entry and return the updated todo entry.
- Create an @ExceptionHandler method that sets the response status to 404 if the todo entry was not found (TodoNotFoundException was thrown).
The source code of the TodoController class looks as follows:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.util.List; @RestController @RequestMapping("/api/todo") final class TodoController { private final TodoService service; @Autowired TodoController(TodoService service) { this.service = service; } @RequestMapping(method = RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) TodoDTO create(@RequestBody @Valid TodoDTO todoEntry) { return service.create(todoEntry); } @RequestMapping(value = "{id}", method = RequestMethod.DELETE) TodoDTO delete(@PathVariable("id") String id) { return service.delete(id); } @RequestMapping(method = RequestMethod.GET) List<TodoDTO> findAll() { return service.findAll(); } @RequestMapping(value = "{id}", method = RequestMethod.GET) TodoDTO findById(@PathVariable("id") String id) { return service.findById(id); } @RequestMapping(value = "{id}", method = RequestMethod.PUT) TodoDTO update(@RequestBody @Valid TodoDTO todoEntry) { return service.update(todoEntry); } @ExceptionHandler @ResponseStatus(HttpStatus.NOT_FOUND) public void handleTodoNotFound(TodoNotFoundException ex) { } }
That is it. We have now created a REST API that provides CRUD operations for todo entries and saves them to MongoDB database. Let’s summarize what we learned from this blog post.
Summary
This blog post has taught us three things:
- We can get the required dependencies with Maven by declaring only two dependencies: spring-boot-starter-web and spring-data-mongodb.
- If we are happy with the default configuration of Spring Boot, we can configure our web application by using its auto-configuration support and “dropping” new jars to the classpath.
- We learned to create a simple REST API that saves information to MongoDB database and finds information from it.
P.S. You can get the example application of this blog post from Github.
Read the original blog post: Creating a REST API with Spring Boot and MongoDB.
Thanks for the post. Very nice and elegant code! I like the idea of using the builder pattern with the entity object and also using the streaming api when converting from entity list to DTO list.
You may consider using the @RepositoryRestResource annotation that instructs Spring to expose REST endpoints for repository operations. Here's an example on how to use it: http://kaviddiss.com/2014/12/28/twitter-feed-using-spring-boot
Thank you for your kind words. I really appreciate them!
Also, thank you for reminding me about Spring Data REST. We tried it very briefly when its first versions were released, but at the time we decided not to use it.
I am updating my Spring Data JPA tutorial, and Spring Data REST tutorial would be a good addition to my Spring Data tutorials -> Now is a good time to give it a second chance.
Glad to hear that. I'd be definitely interested in a Spring Data REST tutorial!
How to save data into the relationship table using the controller in Spring boot ?
Thank you writing this tutorial. It is very well written and clears many of my questions in this context.
Can you please explain why do you recommend using a DTO instead of directly using model objects?. I am sure there must be a reason.
Also if you could keep the pseudo code and the actual code side by side, it would be much more enjoyable experience (IMO) to read.
There are two reasons why I think that returning DTOs is a good idea:
If you are interested in this subject, you might want to read this blog post. It introduces the "classic" architecture of a Spring web application, and it might give you some new ideas. However, it is good to understand that the classic way is not the best way anymore (IMO).
I agree. The problem is that I haven't found a Wordpress plugin that would support this. :(
No Tests?
The example application has unit tests. However, it doesn't have integration tests since I didn't have time to figure out how to write integration tests that use MongoDB database.
It would be extremely useful if you added integration tests.
I added a new card to my Trello board since it seems that these tests are useful to you. I will update one of my older blog posts before I will take a closer look at this. If everything goes as expected, I assume that I can write those tests next weekend.
Petri, thanks for your nice work! It would be great to have integration test example as well.
I will try to write some integration tests next weekend. I was supposed to write them a bit earlier, but I didn't have time to do it because I was busy updating my Spring Data JPA tutorial.
I'm following this guide to implement my web app.
In my app I throw PropertyNotFoundException when the prop can not be found in mongodb with given id. I also expect there is 404 response to the client. However I got below exception instead of 404 response,
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.devicehub.api.exception.PropertyNotFoundException: No property found with id:
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:144)
at
Do you have any idea for this?
Thank you.
Update: I removed the irrelevant part from the stacktrace - Petri
Hi,
Check out the source code of the
TodoController
class. ThehandleTodoNotFound()
method returns the 404 HTTP status code when theTodoNotFoundException
is thrown. I think that you can use the same approach in your application.Also, if the
PropertyNotFoundException
exception is thrown by more than one class, it is often a good idea to move the@ExceptionHandler
method to a class that is annotated with the@ControllerAdvice
annotation.If you have any further questions about this, don't hesitate to ask them.
Petri, thanks for the hint.
You are welcome.
Where are we writing DB connection in this project?
We are not writing directly to the MongoDB connection. This example application follows these steps:
I hope that this answered to your question. If you have any additional questions, don't hesitate to ask them!
Thanks..! I had the same doubt.
You are welcome!
I am bit new to technical field. I want to know from where I have to run this project? I mean which class I have to run ?
Hi Kreg,
you can get the example application from Github. You can either clone the Git repository or download the source code as Zip file (click the Download ZIP link).
Before you can run the application, you need to
After you have installed Java 8 SDK, Maven, and MongoDB, you can run the application by running the command: mvn clean spring-boot:run at command prompt.
If you have any further questions, don't hesitate to ask them.
Thanks a lot Petri ! Much appreciated your talent.
You are welcome!
Answered my own question. I've never seen an update method in a domain object before so I missed it in the example. It didn't make sense to me so I spaced it out. Can you explain why you do that?
Well, basically the
update(String title, String description)
method is just a "setter" method that has more than one parameter.I use these methods because they help me to create "atomic" update operations. Each update method updates the field values of fields that belong to the same "logical" group. Also, these methods guarantee that the new field values of the updated fields are valid or they throw an exception.
If I would use traditional setter methods, my service methods would have to invoke multiple setter methods. This means that they would a be lot messier than the service methods that simply invoke these update methods.
However, if the updated object has too many properties, it is not practical to have just one update method. In these cases I create methods such as:
updateInvoicingAddress()
,updateMailingAddress()
, and so on.excellent ideas, thanks.
You are welcome!
Just remember to use common sense. Sometimes using these update methods makes sense, but sometimes a simple setter method is the best tool for the job. It all depends from your requirements.
Could you give an example of a CRUD operation, for example POST, because I'm not sure how to make it work.
Do you mean that you don't know how you can create HTTP requests (like
POST
for example) that are processed by the controller methods? If so, are you using jQuery, AngularJS, or some other JS framework?Yes.
I'm not using any of these, I just wanted to check how it works using a browser.
I mean, using mozilla extension.
I use RESTClient for this purpose. You can create a
POST
request by following these steps:POST
) by using the 'Method' combo box.Content-Type
and set its value toapplication/json
(You can find the correct popup from Headers -> Custom Header).If you want create a todo entry whose title is 'foo' and description is 'bar', you can use the following json:
I hope that this answered to your question.
Except MongoDb configuration , you have mentioned everything.
I used the default configuration mainly because I am not a MongoDb expert, and I don't want to give bad advice to anyone. Check out the MongoDb Manual. It has a section that covers different configuration options.
Hi Petri,
Is there a way to know which database my java application is pointing to.
I basically want to find all the documents across all collections that has been loaded in the database.
I am expecting some get expressions to execute correctly say get(/templates/json/names) but i am unable to understand what exactly the expression means here. Does it mean collection name is templates? and remaining uri is the further xpath expression. For some reason my data is coming as blank for the uri expressions and i am trying to diagnose why my documents are not getting retrieved.
Thanks
Shreejit
Hi Shreejit,
I have used MongoDb only once when I wrote this blog post. Unfortunately this means that I don't know the answer to your question :( Have you tried posting it to StackOverflow?
Hi Petri,
Correct me if I am wrong but your update method does not take into account id from url?
So if I PUT /api/todo/mickeyMouse with body {id:"1", title:"My Todo"} it will update todo with id 1 and ignore "mickeyMouse" from the url?
Cheers,
Goran
Hi Goran,
you are right.
Hi Petri,
I was hoping for more details :)
Is it something expected or is it something that you would want to fix? I saw the similar implementation in book "Spring REST", without dtos but still ignoring id from url.
Is there maybe some spring magic that would shove that id in the request bodu object?
Cheers,
Goran.
Hi Goran,
Ah. Sorry about that. I was in Finnish mode which means that I answer only to the question that was asked :P
Well, there are two things to consider here:
In other words, if I would write this example now, I would not ignore the id found from the url.
Hello petri,
thank you for your toturial , I am new in Spring and have some question . i am sure that your answer as a professional can help me so much.
would you please let me know your email to ask my question there ? looking forward to hear from you.
thank you
Sure. Let's continue this discussion via email.
I seem to have missed something in the implementation. I'm getting a NoSuchBeanDefinitionException:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
...
Caused by org.springframework.beans.factory.UnsatisfiedDepenencyException: Error creating bean with name 'MongoDbToDoService' defined in file ['/home/anne/workspace-sts/SpringTraining/target/classes/MongoDbToDoService.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [ToDoRepository]: No qualifying bean of type [ToDoRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {};
.....
....
Caused by: org.springfamework.beans.bactory.NoSuchBeanDefinitionException: No qualifying bean of type [TodoRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Hi,
It seems that for some reason Spring Boot could not find the
TodoRepository
bean. Did you remember to declare the spring-data-mongodb dependency in your POM file? Also, you should check that your application class is annotated with the@ComponentScan
annotation.Hello Petri,
Thanks you for your nice tutorials. I am new in Spring and Mongodb. I want to insert jSON object into Mongodb collection that we didn't know its specific fields. I tried many way, but it didn't work for me. Could you please explain me how to do it? I am waiting to hear from you.
Thanks you,
Hi,
Check out this blog post (the example 4 describes how you can do it).
Hi, i do not understand, can you tell me why to use the interfaces ToDoRepository and ToDoService? Why isn't it possible to put ToDoService in ToDoRepository? Thank you alot for this great tutorial!
Hi,
The
TodoRepository
interface is a repository interface that is required by Spring Data MongoDB. In other words, you need to use that interface when you save information to your MongoDB database or query information from it.The
TodoService
interface declares the service API that provides CRUD operations for todo entries. Note that you don't necessarily have to create this interface if you have only implementation for it. If this is the case, you can create a service class and inject it to the controller.I didn't understand this question. Did you mean to ask: is it possible to inject
TodoRepository
to theTodoController
?Hi Petri,
I am getting this error when i try running the project which i created using spring tool suite
i am not sure what the problem is
2016-08-09 11:41:37.346 ERROR 10904 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.IllegalAccessError: tried to access class com.example.entity.Todo from class com.sun.proxy.$Proxy56] with root cause
java.lang.IllegalAccessError: tried to access class com.example.entity.Todo from class com.sun.proxy.$Proxy56
at com.sun.proxy.$Proxy56.save(Unknown Source) ~[na:na]
at com.example.entity.MongoDBTodoService.create(MongoDBTodoService.java:27) ~[classes/:na]
at com.example.entity.TodoController.create(TodoController.java:31) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_51]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_51]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_51]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_51]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
Update: I removed the irrelevant part of the stack trace - Petri
Hi,
Unfortunately I have never seen this exception. In fact, it looks so weird that it might be a version mismatch problem. Are you using the latest Spring and Spring Data MongoDB versions?
i am using spring tool suite and it gave me option to select web and mongodb.this is pom file
4.0.0
com.ioc
demo
0.0.1-SNAPSHOT
jar
internetOfThings
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
1.4.0.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-data-mongodb
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
can we please communicate using email..i have the project due tomorrow..please
The Spring Boot 1.4.0 uses MongoDB Driver 3.2.2. I took a quick look at its documentation and it looks like that this driver is compatible only with MongoDB 3.2.x. If you are using some other MongoDB version, you should either update your MongoDB version or use an older driver.
I have to admit that I have no idea if this fixes your problem since I have no real-life experience from MongoDB (or Spring Data MongoDB). I simply wrote this blog post because I wanted to try it out.
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /C:/Users/Kiran Pasuluri/Documents/SystemLogic/workspace/java-advent-2014/src/test/java/com/javaadvent/bootrest/todo/MongoDbTodoServiceTest.java:[28,8] class MongoDBTodoServiceTest is public, should be declared in a file named MongoDBTodoServiceTest.java
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.372 s
[INFO] Finished at: 2017-05-23T11:48:04+02:00
[INFO] Final Memory: 20M/219M
Oops :( Thank you for reporting this problem. It is fixed now.
Hi Petri, what did you change ? where can i get that fixed file ?
I have managed to fix the issue
Hi, I probably should I have mentioned that I fixed the problem and committed the fix to Github. In any case, it's good hear that you were able to solve your problem.
Hi Petri,
I follow your guide and i had created similar proyect in NetBEans. But i have some problem with run of MongoDb, when i run the application my program is throwing an exception:
[localhost:27017] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server localhost:27017
com.mongodb.MongoSocketOpenException: Exception opening socket
/....
After this exception Tomcat is starting but because of that problem i can't store any date in MongoDb, do u have some ideas how to resolve this issue??
Best regards
It seems that the application cannot open a database connection for some reason. Are using a local or a remote MongoDB instance? In any case, I would check that the connection string is correct and that MongoDB is listening the "correct" port (this depends from your configuration).
I reinstalled my MongoDb to newest version and after starting mongoDB server i run my application and works perfectly. Magic lol :D Big thanks for help!!
You are welcome! I am happy to hear that you were able to solve your problem.
Hi
How can I add my custom methods and link them to a custom rest call?
It's very helpful tutorial. Thanks Alot.
I get:
[ERROR] No plugin found for prefix 'spring' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (/home/ben/.m2/repository), spring-releases (https://repo.spring.io/libs-release), central (http://repo.maven.apache.org/maven2)] -> [Help 1]
org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException: No plugin found for prefix 'spring' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (/home/ben/.m2/repository), spring-releases (https://repo.spring.io/libs-release), central (http://repo.maven.apache.org/maven2)]
at org.apache.maven.plugin.prefix.internal.DefaultPluginPrefixResolver.resolve(DefaultPluginPrefixResolver.java:94)
Drives me nuts didnt find any help on google
Hi,
I haven't seen this error myself, but if you are trying to run the example application of this blog post and you get this error, you might want to update the Spring Boot Maven plugin. The example uses rather old Spring Boot version and the configuration might have changed in newer versions (I cannot remember if this is the case though).
Hi Petri,
How to config mongoDB connection?
In normal JAVA I have to connect to mongodb first before do anything in database, like this.
MongoClient mongoClient = new MongoClient("localhost", 27017);
in the tutorial there's not any connection in code.
Thanks
Hi,
Take a look at the Spring Boot's Reference Documentation. The section 30.2 MongoDB answers to your question.
What is the purpose of the TodoDTO class? Why is it important to have this?
The
TodoDTO
class is a data transfer object that simply hides the data model (basically entities) of the example application from the outside world. This allows you to change the data model without breaking the clients that use your API (assuming that you can still use the same DTOs).By the way, it's also important to realize that you might not need this if you are writing prototypes or internal APIs because you can update the clients at the same time you update your API. However, if you are writing a public API, you have to be more cautious because it's not a good idea to break your API every time you make changes to your data model.
have you thought about one to many embedded documents collection in Mongodb? instead of just saving new document every time? This way you can also take care of multiple users.
your new mongodb document -
{
id: xxjjjx,
userName: kunal;
todoList:[
{
id:xx
todo: "whatever"
},
{
id:xx2
todo: "whatever"
}
]
}
Hi Petrik,
We have a requirement to design our application business logic in a DB neutral way. Which implies that our service layer will data model. We will get data from our Rest API base on that we will fetch our domain model from DB. So there will be a conversion layer which will translate stored data into a service layer data model. We want to design our service layer domain model, not in the way we are storing it in DB so that we can switch our DB with minimal or zero impact to our business logic. Is this a good way to think in this direction?
Is there any framework already exists?
Do you have any recommendation/best practices on it?
Hi,
Can we use spring 3.2 with spring data mongodb version 2.2.3.Release.
Hi,
Unfortunately the answer to your question is no. Spring Data MongoDB 2.2.3 requires Spring Framework 5.2.2 or newer.