├── .gitignore
├── LICENSE
├── README.md
├── onionarch-data
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── github
│ └── adamsiemion
│ └── onionarch
│ ├── MongoConfig.java
│ ├── UserDaoMongo.java
│ └── UserRepositorySpringData.java
├── onionarch-domain
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── github
│ └── adamsiemion
│ └── onionarch
│ ├── User.java
│ └── UserRepository.java
├── onionarch-rest
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── github
│ └── adamsiemion
│ └── onionarch
│ ├── Application.java
│ └── UserRest.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 |
14 | # IntelliJ files
15 | *.iml
16 | .idea
17 |
18 | # maven
19 | target
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Adam Siemion
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This tutorial will show how to create a REST application using the Onion Architecture and Spring Boot (Spring Core, Spring MVC and Spring Data). For simplicity it will use an in-memory database (Fongo) and expose only one REST endpoint. Also please note that this tutorial focuses on using the Onion Architecture in practise and intentionally does not cover very important aspects of developing production applications such as [writing tests](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html), [packaging of Spring applications](http://www.kubrynski.com/2015/11/smart-package-structure-to-improve.html) or [REST API design](https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling).
2 |
3 | The traditional three-layered architecture consists of:
4 |
5 | + presentation layer
6 | + application layer (also called business logic, logic or middle layer)
7 | + data layer
8 |
9 | The traditional three-layered architecture has downward dependencies - the presentation layer depends on the application layers and the application layer depends on the data layer and therefore, transitively, the presentation layer depends on the data layer. The dependencies of the downward layers are inherited by the upward layers, so if the data layer defines a dependency to a library (e.g. ORM library) this dependency will be inherited by the application (and presentation) layer. In a project where boundaries between the layers are not enforced it might lead to a situation where an ORM class (e.g. `SQLException`) is propagated to the application (and presentation) layer. This introduces an coupling between the layers - your domain (and presentation) is no longer independent of the implementation of the data layer - whenever the implementation of the data layer change (e.g. you switch from JPA to Spring Data) you have to change the domain (and presentation) layer. The Onion Architecture is designed to prevent this problem.
10 |
11 | The Onion Architecture is a variant of multi-layered architecture, which consists of:
12 |
13 | + application core which consists of:
14 | * domain model
15 | * domain services
16 | * application services
17 | + infrastructure
18 |
19 | [More on Onion Architecture](http://jeffreypalermo.com/blog/the-onion-architecture-part-1)
20 |
21 | # Project setup
22 |
23 | ## Create a new multimodule maven project
24 |
25 | Create directory `onionarch` with `pom.xml` with:
26 |
27 | + `pom` packaging
28 | + a dependency to javax.inject:javax.inject:1
29 | + a dependency to junit:junit:4.12
30 | + Java 1.8 properties
31 |
32 | The complete `pom.xml` content:
33 |
34 | ```xml
35 |
37 | 4.0.0
38 | com.github.adamsiemion.onionarch
39 | onionarch
40 | pom
41 | 1.0.0-SNAPSHOT
42 |
43 |
44 | 1.8
45 | 1.8
46 |
47 |
48 |
49 |
50 | javax.inject
51 | javax.inject
52 | 1
53 |
54 |
55 | junit
56 | junit
57 | 4.12
58 | test
59 |
60 |
61 |
62 | ```
63 |
64 | Multimodule maven project allows better dependencies management because each maven module can contain only the dependencies needed by the code in this specific module. Whenever the domain module requires access to infrastructure code, e.g. to send an email or download a file from FTP instead of adding a dependency to the selected infrastructure library in the domain layer one should:
65 |
66 | + create an interface in the domain layer simplifying the API of the infrastructure library (Facade design pattern)
67 | + create a new maven module with an implementation of the interface and dependencies to the chosen libraries
68 |
69 | The Onion Architecture relies on the Dependency Inversion principle, so a way to specify that a class will be injected by the Dependency Injection framework is needed. One option is to use the annotations provided by the DI framework (e.g. Spring), however this will couple the domain to a specific infrastructure library. In order to prevent this coupling we use the annotations from the standard dependency injection API (JSR-330) `javax.inject`.
70 |
71 | # Domain layer
72 |
73 | ## Create maven module `onionarch-domain`
74 |
75 | From the root directory run:
76 |
77 | ```bash
78 | mvn archetype:generate -DgroupId=com.github.adamsiemion.onionarch -DartifactId=onionarch-domain \
79 | -DinteractiveMode=false -Dversion=1.0.0-SNAPSHOT
80 | ```
81 |
82 | We start development from the domain layer, following the principles of Domain Driven Design.
83 | A specific version (`1.0.0-SNAPSHOT`) was provided just to follow the most popular versioning convention - [semantic versioning](http://semver.org).
84 |
85 | ## Delete the generated Java files
86 |
87 | ```bash
88 | rm -rf onionarch-domain\src\main\java\com onionarch-domain\src\test\java\com
89 | ```
90 |
91 | ## Create an empty User model class
92 |
93 | Create class `User` in `onionarch-domain\src\main\java\com\github\adamsiemion\onionarch`
94 |
95 | ```java
96 | public class User {
97 | }
98 | ```
99 |
100 | # Presentation layer (providing REST API)
101 |
102 | ## Create maven module `onionarch-rest`
103 |
104 | From the root directory run:
105 |
106 | ```bash
107 | mvn archetype:generate -DgroupId=com.github.adamsiemion.onionarch -DartifactId=onionarch-rest \
108 | -DinteractiveMode=false -Dversion=1.0.0-SNAPSHOT
109 | ```
110 |
111 | ## Delete the generated Java files
112 |
113 | ```bash
114 | rm -rf onionarch-rest\src\main\java\com onionarch-rest\src\test\java\com
115 | ```
116 |
117 | ## Add Spring Boot Starter Web dependency
118 |
119 | Add below content to `onionarch-rest\pom.xml`
120 |
121 | ```xml
122 |
123 |
124 |
125 | org.springframework.boot
126 | spring-boot-dependencies
127 | 1.3.3.RELEASE
128 | pom
129 | import
130 |
131 |
132 |
133 |
134 |
135 |
136 | org.springframework.boot
137 | spring-boot-starter-web
138 |
139 |
140 | ```
141 |
142 | ## Add a dependency to the domain module
143 |
144 | ```xml
145 |
146 | com.github.adamsiemion.onionarch
147 | onionarch-domain
148 | ${project.version}
149 |
150 | ```
151 |
152 | ## Add a plugin to build an executable jar
153 |
154 | Edit pom.xml from the rest module directory and add:
155 |
156 | ```xml
157 |
158 |
159 |
160 | org.springframework.boot
161 | spring-boot-maven-plugin
162 |
163 |
164 |
165 | repackage
166 |
167 |
168 |
169 |
170 |
171 |
172 | ```
173 |
174 | ## Create a `@SpringBootApplication` class
175 |
176 | Create class `Application` in `onionarch-rest\src\main\java\com\github\adamsiemion\onionarch` with the following content:
177 |
178 | ```java
179 | package com.github.adamsiemion.onionarch;
180 |
181 | import org.springframework.boot.SpringApplication;
182 | import org.springframework.boot.autoconfigure.SpringBootApplication;
183 |
184 | @SpringBootApplication
185 | public class Application {
186 | public static void main(String[] args) {
187 | SpringApplication.run(Application.class, args);
188 | }
189 | }
190 | ```
191 |
192 | ## Create UserRest class with the `GET /users` method
193 |
194 | Create class `UserRest` in `onionarch-rest\src\main\java\com\github\adamsiemion\onionarch` with the following content:
195 |
196 | ```java
197 | package com.github.adamsiemion.onionarch;
198 |
199 | import org.springframework.web.bind.annotation.RequestMapping;
200 | import org.springframework.web.bind.annotation.RequestMethod;
201 | import org.springframework.web.bind.annotation.RestController;
202 |
203 | import java.util.ArrayList;
204 | import java.util.List;
205 |
206 | @RestController
207 | @RequestMapping("/users")
208 | public class UserRest {
209 | @RequestMapping(method = RequestMethod.GET)
210 | public List list() {
211 | return new ArrayList<>();
212 | }
213 | }
214 | ```
215 |
216 | If you [build and run the application](#build-and-run-the-application) now and send a GET request to http://localhost:8080/users (`curl http://localhost:8080/users`) the application will respond with an empty array.
217 |
218 | # Domain and presentation layer development
219 |
220 | ## Add attributes to the User model class
221 |
222 | + String id
223 | + String name
224 |
225 | The complete `User` source code:
226 |
227 | ```java
228 | package com.github.adamsiemion.onionarch;
229 |
230 | import java.util.Objects;
231 |
232 | public class User {
233 | private String id;
234 | private String name;
235 |
236 | User() {
237 | }
238 |
239 | public User(String name) {
240 | this.name = name;
241 | }
242 |
243 | public User(String id, String name) {
244 | this.id = id;
245 | this.name = name;
246 | }
247 |
248 | public String getId() {
249 | return id;
250 | }
251 |
252 | public String getName() {
253 | return name;
254 | }
255 |
256 | @Override
257 | public boolean equals(Object o) {
258 | if (this == o) return true;
259 | if (o == null || getClass() != o.getClass()) return false;
260 | User user = (User) o;
261 | return Objects.equals(id, user.id) &&
262 | Objects.equals(name, user.name);
263 | }
264 |
265 | @Override
266 | public int hashCode() {
267 | return Objects.hash(id, name);
268 | }
269 |
270 | @Override
271 | public String toString() {
272 | return "User{id='" + id + "', name='" + name + "'}";
273 | }
274 | }
275 | ```
276 |
277 | [Lombok](https://projectlombok.org) can reduce the number of boilerplate code (such as getters, `toString()`, `equals()`, `hashCode()`).
278 | It is possible to [make the above class immutable what brings a lot of advantages](http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html), by defining an all args constructor and using [Jackon’s parameter names module](https://github.com/FasterXML/jackson-module-parameter-names).
279 |
280 | ## Create UserRepository interface in the domain
281 |
282 | Create interface `UserRepository` in `onionarch-domain\src\main\java\com\github\adamsiemion\onionarch` with the following content:
283 |
284 | ```java
285 | package com.github.adamsiemion.onionarch;
286 |
287 | public interface UserRepository {
288 | Iterable list();
289 |
290 | User get(Long id);
291 |
292 | void save(User user);
293 |
294 | void delete(Long id);
295 | }
296 | ```
297 |
298 | ## Inject UserRepository into UserRest
299 |
300 | Add the following content to `onionarch-rest\src\main\java\com\github\adamsiemion\onionarch\UserRest.java`:
301 |
302 | ```java
303 | private final UserRepository userRepository;
304 |
305 | @Inject
306 | public UserRest(final UserRepository userRepository) {
307 | this.userRepository = userRepository;
308 | }
309 | ```
310 |
311 | ## Add CRUD methods to UserRest
312 |
313 | Add the following content to `onionarch-rest\src\main\java\com\github\adamsiemion\onionarch\UserRest.java` (overwrite the existing `list` method):
314 |
315 | ```java
316 | @RequestMapping(method = RequestMethod.GET)
317 | public Iterable list() {
318 | return userRepository.list();
319 | }
320 |
321 | @RequestMapping(method = RequestMethod.POST)
322 | public void create(@RequestBody User user) {
323 | userRepository.save(user);
324 | }
325 |
326 | @RequestMapping(value = "{id}", method = RequestMethod.DELETE)
327 | public void delete(@PathVariable("id") final Long id) {
328 | userRepository.delete(id);
329 | }
330 |
331 | @RequestMapping(value = "{id}", method = RequestMethod.GET)
332 | public User get(@PathVariable("id") final Long id) {
333 | return userRepository.get(id);
334 | }
335 | ```
336 |
337 | ## Create a fake UserRepository implementation
338 |
339 | Create class `UserRespositoryFake` in `onionarch-domain\src\main\java\com\github\adamsiemion\onionarch` with the following content:
340 |
341 | ```java
342 | package com.github.adamsiemion.onionarch;
343 |
344 | import javax.inject.Named;
345 | import java.util.Arrays;
346 | import java.util.List;
347 |
348 | @Named
349 | public class UserRepositoryFake implements UserRepository {
350 | @Override
351 | public List list() {
352 | return Arrays.asList(new User(1L, "John Smith"), new User(2L, "John Doe"));
353 | }
354 |
355 | @Override
356 | public User get(Long id) {
357 | return new User();
358 | }
359 |
360 | @Override
361 | public void save(User user) { }
362 |
363 | @Override
364 | public void delete(Long aLong) { }
365 | }
366 | ```
367 |
368 | This class is a [fake](http://www.martinfowler.com/bliki/TestDouble.html) implementation, created to test the current solution, which will not be used in production.
369 |
370 | If you [build and run the application](#build-and-run-the-application) now and send a GET request to http://localhost:8080/users (`curl http://localhost:8080/users`) the application will respond with:
371 | `[{"id":1,"name":"John Smith"},{"id":2,"name":"John Doe"}]`
372 |
373 | # Data layer
374 |
375 | ## Delete UserRespositoryFake
376 |
377 | ## Create maven module `onionarch-data`
378 |
379 | From the root directory run:
380 |
381 | ```bash
382 | mvn archetype:generate -DgroupId=com.github.adamsiemion.onionarch -DartifactId=onionarch-data \
383 | -DinteractiveMode=false -Dversion=1.0.0-SNAPSHOT
384 | ```
385 |
386 | ## Delete the generated Java files
387 |
388 | ```bash
389 | <<<<<<< HEAD
390 | rm -rf onionarch-data\src\main\java\com onionarch-data\src\test\java\com
391 | ```
392 |
393 | ## Add dependencies for Spring Boot and Spring Data
394 |
395 | ```xml
396 |
397 |
398 |
399 | org.springframework.boot
400 | spring-boot-dependencies
401 | 1.3.3.RELEASE
402 | pom
403 | import
404 |
405 |
406 |
407 |
408 |
409 |
410 | org.springframework.boot
411 | spring-boot-starter-data-mongodb
412 |
413 |
414 | ```
415 |
416 | ## Add a dependency to the domain module
417 |
418 | ```xml
419 |
420 | com.github.adamsiemion.onionarch
421 | onionarch-domain
422 | ${project.version}
423 |
424 | ```
425 |
426 | ## Add a dependency to fongo in the data module
427 |
428 | ```xml
429 |
430 | com.github.fakemongo
431 | fongo
432 | 1.6.7
433 |
434 | ```
435 |
436 | ## Add a dependency to the data module in the presentation module
437 |
438 | ```xml
439 |
440 | com.github.adamsiemion.onionarch
441 | onionarch-data
442 | ${project.version}
443 | runtime
444 |
445 | ```
446 |
447 | This is required because we want the Dependency Injection container to instantiate classes from the data layer in runtime but we do not want these classes at compile time.
448 |
449 | ## Create UserDaoSpringData interface extending Spring Data's MongoRepository
450 |
451 | Create class `UserDaoMongo` in `onionarch-data\src\main\java\com\github\adamsiemion\onionarch` with the following content:
452 |
453 | ```java
454 | package com.github.adamsiemion.onionarch;
455 |
456 | import org.springframework.data.mongodb.repository.MongoRepository;
457 |
458 | public interface UserDaoMongo extends MongoRepository {
459 | }
460 | ```
461 |
462 | ## Create a Mongo configuration class
463 |
464 | Create class `MongoConfig` in `onionarch-data\src\main\java\com\github\adamsiemion\onionarch` with the following content:
465 |
466 | ```java
467 | package com.github.adamsiemion.onionarch;
468 |
469 | import com.github.fakemongo.Fongo;
470 | import com.mongodb.Mongo;
471 | import org.springframework.context.annotation.Configuration;
472 | import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
473 |
474 | @Configuration
475 | public class MongoConfig extends AbstractMongoConfiguration {
476 | @Override
477 | protected String getDatabaseName() {
478 | return "users";
479 | }
480 |
481 | @Override
482 | public Mongo mongo() {
483 | return new Fongo("mongo-test").getMongo();
484 | }
485 | }
486 | ```
487 |
488 | ## Create a UserRepository implementation, which will delegate all the calls to UserDaoSpringData
489 |
490 | Create class `UserRepositorySpringData` in `onionarch-data\src\main\java\com\github\adamsiemion\onionarch` with the following content:
491 |
492 | ```java
493 | package com.github.adamsiemion.onionarch;
494 |
495 | import org.springframework.stereotype.Repository;
496 |
497 | import javax.inject.Inject;
498 |
499 | @Repository
500 | public class UserRepositorySpringData implements UserRepository {
501 |
502 | private final UserDaoMongo dao;
503 |
504 | @Inject
505 | public UserRepositorySpringData(final UserDaoMongo dao) {
506 | this.dao = dao;
507 | }
508 |
509 | @Override
510 | public Iterable list() {
511 | return dao.findAll();
512 | }
513 |
514 | @Override
515 | public User get(String id) {
516 | return dao.findOne(id);
517 | }
518 |
519 | @Override
520 | public void save(User user) {
521 | dao.save(user);
522 | }
523 |
524 | @Override
525 | public void delete(String id) {
526 | dao.delete(id);
527 | }
528 | }
529 | ```
530 |
531 | The above class is an example of the delegate design pattern.
532 |
533 | ## Build and run the application
534 |
535 | To build the application go to the root directory and run: `mvn install`
536 |
537 | To run the application go to the root directory and run: `java -jar onionarch-rest/target/onionarch-rest-1.0.0-SNAPSHOT.jar`
538 |
539 | ## Test the application
540 |
541 | ### Get a list of users
542 |
543 | `curl http://localhost:8080/users`
544 |
545 | ### Add a user
546 |
547 | `curl -H 'Content-Type: application/json' -X POST -d '{"name":"John Smith"}' http://localhost:8080/users`
548 |
549 | ### Get a user details
550 |
551 | `curl http://localhost:8080/users/`
552 |
553 | ### Delete a user
554 |
555 | `curl -X DELETE http://localhost:8080/users/`
556 |
--------------------------------------------------------------------------------
/onionarch-data/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.github.adamsiemion.onionarch
7 | onionarch
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | com.github.adamsiemion.onionarch
12 | onionarch-data
13 | 1.0.0-SNAPSHOT
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-dependencies
20 | 1.3.3.RELEASE
21 | pom
22 | import
23 |
24 |
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-data-mongodb
31 |
32 |
33 |
34 | com.github.adamsiemion.onionarch
35 | onionarch-domain
36 | ${project.version}
37 |
38 |
39 |
40 | com.github.fakemongo
41 | fongo
42 | 1.6.7
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/onionarch-data/src/main/java/com/github/adamsiemion/onionarch/MongoConfig.java:
--------------------------------------------------------------------------------
1 | package com.github.adamsiemion.onionarch;
2 |
3 | import com.github.fakemongo.Fongo;
4 | import com.mongodb.Mongo;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
7 |
8 | /**
9 | * @author Adam Siemion
10 | */
11 | @Configuration
12 | public class MongoConfig extends AbstractMongoConfiguration {
13 | @Override
14 | protected String getDatabaseName() {
15 | return "users";
16 | }
17 |
18 | @Override
19 | public Mongo mongo() {
20 | return new Fongo("mongo-test").getMongo();
21 | }
22 | }
--------------------------------------------------------------------------------
/onionarch-data/src/main/java/com/github/adamsiemion/onionarch/UserDaoMongo.java:
--------------------------------------------------------------------------------
1 | package com.github.adamsiemion.onionarch;
2 |
3 | import org.springframework.data.mongodb.repository.MongoRepository;
4 |
5 | /**
6 | * @author Adam Siemion
7 | */
8 | public interface UserDaoMongo extends MongoRepository {
9 | }
10 |
--------------------------------------------------------------------------------
/onionarch-data/src/main/java/com/github/adamsiemion/onionarch/UserRepositorySpringData.java:
--------------------------------------------------------------------------------
1 | package com.github.adamsiemion.onionarch;
2 |
3 | import org.springframework.stereotype.Repository;
4 |
5 | import javax.inject.Inject;
6 |
7 | /**
8 | * @author Adam Siemion
9 | */
10 | @Repository
11 | public class UserRepositorySpringData implements UserRepository {
12 |
13 | private final UserDaoMongo dao;
14 |
15 | @Inject
16 | public UserRepositorySpringData(final UserDaoMongo dao) {
17 | this.dao = dao;
18 | }
19 |
20 | @Override
21 | public Iterable list() {
22 | return dao.findAll();
23 | }
24 |
25 | @Override
26 | public User get(String id) {
27 | return dao.findOne(id);
28 | }
29 |
30 | @Override
31 | public void save(User user) {
32 | dao.save(user);
33 | }
34 |
35 | @Override
36 | public void delete(String id) {
37 | dao.delete(id);
38 | }
39 | }
--------------------------------------------------------------------------------
/onionarch-domain/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.github.adamsiemion.onionarch
7 | onionarch
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | com.github.adamsiemion.onionarch
12 | onionarch-domain
13 | 1.0.0-SNAPSHOT
14 |
15 |
16 |
17 | junit
18 | junit
19 | 3.8.1
20 | test
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/onionarch-domain/src/main/java/com/github/adamsiemion/onionarch/User.java:
--------------------------------------------------------------------------------
1 | package com.github.adamsiemion.onionarch;
2 |
3 | import java.util.Objects;
4 |
5 | /**
6 | * @author Adam Siemion
7 | */
8 | public class User {
9 | private String id;
10 | private String name;
11 |
12 | User() {
13 | }
14 |
15 | public User(String name) {
16 | this.name = name;
17 | }
18 |
19 | public User(String id, String name) {
20 | this.id = id;
21 | this.name = name;
22 | }
23 |
24 | public String getId() {
25 | return id;
26 | }
27 |
28 | public String getName() {
29 | return name;
30 | }
31 |
32 | @Override
33 | public boolean equals(Object o) {
34 | if (this == o) return true;
35 | if (o == null || getClass() != o.getClass()) return false;
36 | User user = (User) o;
37 | return Objects.equals(id, user.id) &&
38 | Objects.equals(name, user.name);
39 | }
40 |
41 | @Override
42 | public int hashCode() {
43 | return Objects.hash(id, name);
44 | }
45 |
46 | @Override
47 | public String toString() {
48 | return "User{ownerId='" + id + "', name='" + name + "'}";
49 | }
50 | }
--------------------------------------------------------------------------------
/onionarch-domain/src/main/java/com/github/adamsiemion/onionarch/UserRepository.java:
--------------------------------------------------------------------------------
1 | package com.github.adamsiemion.onionarch;
2 |
3 | /**
4 | * @author Adam Siemion
5 | */
6 | public interface UserRepository {
7 | Iterable list();
8 |
9 | User get(String id);
10 |
11 | void save(User user);
12 |
13 | void delete(String id);
14 | }
15 |
--------------------------------------------------------------------------------
/onionarch-rest/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.github.adamsiemion.onionarch
7 | onionarch
8 | 1.0.0-SNAPSHOT
9 |
10 |
11 | com.github.adamsiemion.onionarch
12 | onionarch-rest
13 | 1.0.0-SNAPSHOT
14 |
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-dependencies
20 | 1.3.3.RELEASE
21 | pom
22 | import
23 |
24 |
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-web
31 |
32 |
33 | com.github.adamsiemion.onionarch
34 | onionarch-domain
35 | ${project.version}
36 |
37 |
38 | com.github.adamsiemion.onionarch
39 | onionarch-data
40 | ${project.version}
41 | runtime
42 |
43 |
44 |
45 |
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-maven-plugin
50 |
51 |
52 |
53 | repackage
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/onionarch-rest/src/main/java/com/github/adamsiemion/onionarch/Application.java:
--------------------------------------------------------------------------------
1 | package com.github.adamsiemion.onionarch;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | /**
7 | * @author Adam Siemion
8 | */
9 | @SpringBootApplication
10 | public class Application {
11 | public static void main(String[] args) {
12 | SpringApplication.run(Application.class, args);
13 | }
14 | }
--------------------------------------------------------------------------------
/onionarch-rest/src/main/java/com/github/adamsiemion/onionarch/UserRest.java:
--------------------------------------------------------------------------------
1 | package com.github.adamsiemion.onionarch;
2 |
3 | import org.springframework.web.bind.annotation.PathVariable;
4 | import org.springframework.web.bind.annotation.RequestBody;
5 | import org.springframework.web.bind.annotation.RequestMapping;
6 | import org.springframework.web.bind.annotation.RequestMethod;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | import javax.inject.Inject;
10 |
11 | /**
12 | * @author Adam Siemion
13 | */
14 | @RestController
15 | @RequestMapping("/users")
16 | public class UserRest {
17 | private final UserRepository userRepository;
18 |
19 | @Inject
20 | public UserRest(final UserRepository userRepository) {
21 | this.userRepository = userRepository;
22 | }
23 |
24 | @RequestMapping(method = RequestMethod.GET)
25 | public Iterable list() {
26 | return userRepository.list();
27 | }
28 |
29 | @RequestMapping(method = RequestMethod.POST)
30 | public void create(@RequestBody User user) {
31 | userRepository.save(user);
32 | }
33 |
34 | @RequestMapping(value = "{id}", method = RequestMethod.DELETE)
35 | public void delete(@PathVariable("id") final String id) {
36 | userRepository.delete(id);
37 | }
38 |
39 | @RequestMapping(value = "{id}", method = RequestMethod.GET)
40 | public User get(@PathVariable("id") final String id) {
41 | return userRepository.get(id);
42 | }
43 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | com.github.adamsiemion.onionarch
5 | onionarch
6 | pom
7 | 1.0.0-SNAPSHOT
8 |
9 |
10 | 1.8
11 | 1.8
12 |
13 |
14 |
15 |
16 | javax.inject
17 | javax.inject
18 | 1
19 |
20 |
21 | junit
22 | junit
23 | 4.12
24 | test
25 |
26 |
27 |
28 | onionarch-domain
29 | onionarch-rest
30 | onionarch-data
31 |
32 |
--------------------------------------------------------------------------------