├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── encodings.xml
├── jarRepositories.xml
├── misc.xml
└── vcs.xml
├── ChallengeProject
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── gov
│ │ │ └── tubitak
│ │ │ └── keremt
│ │ │ ├── ChallengeApp.java
│ │ │ ├── controllers
│ │ │ └── StockController.java
│ │ │ ├── converter
│ │ │ └── StockConverter.java
│ │ │ ├── dto
│ │ │ ├── StockDto.java
│ │ │ └── TimeSeriesQueryResult.java
│ │ │ ├── entity
│ │ │ └── Stock.java
│ │ │ ├── loader
│ │ │ └── StockLoader.java
│ │ │ ├── repositories
│ │ │ └── StockRepository.java
│ │ │ └── services
│ │ │ └── StockService.java
│ └── resources
│ │ ├── PostmanCollections
│ │ ├── ChallengeProject_Collection_v2.1
│ │ │ └── StocksProjectAPI.postman_collection.json
│ │ └── collections.png
│ │ ├── application.properties
│ │ └── docker-compose.yml
│ └── test
│ └── java
│ └── gov
│ └── tubitak
│ └── keremt
│ ├── MockObjects.java
│ ├── controllers
│ └── StockControllerTest.java
│ ├── converter
│ └── StockConverterTest.java
│ ├── dto
│ └── StockDtoTest.java
│ ├── entity
│ └── StockTest.java
│ └── services
│ └── StockServiceTest.java
├── README.md
├── pom.xml
└── task3-h2
├── pom.xml
└── src
└── main
├── java
└── gov
│ └── tubitak
│ ├── App.java
│ ├── controllers
│ └── PersonController.java
│ ├── dto
│ └── PersonDto.java
│ ├── entity
│ ├── Address.java
│ └── Person.java
│ ├── repositories
│ ├── AddressRepository.java
│ └── PersonRepository.java
│ └── services
│ ├── Impl
│ └── PersonServiceImpl.java
│ └── PersonService.java
└── resources
└── application.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ChallengeProject/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | 4.0.0
7 | ChallengeProject
8 | gov.tubitak
9 | 1.0-SNAPSHOT
10 |
11 | org.springframework.boot
12 | spring-boot-starter-parent
13 | 3.0.0-M5
14 |
15 |
16 | Demo project for Spring Boot
17 |
18 | 17
19 |
20 |
21 |
22 | com.h2database
23 | h2
24 | runtime
25 |
26 |
27 | org.postgresql
28 | postgresql
29 | runtime
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-data-jpa
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-starter-web
38 |
39 |
40 | org.projectlombok
41 | lombok
42 | true
43 |
44 |
45 | org.springframework.boot
46 | spring-boot-starter-test
47 | test
48 |
49 |
50 | org.junit.vintage
51 | junit-vintage-engine
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.springframework.boot
61 | spring-boot-maven-plugin
62 |
63 |
64 |
65 | org.projectlombok
66 | lombok
67 |
68 |
69 |
70 |
71 |
72 | org.jacoco
73 | jacoco-maven-plugin
74 | 0.8.8
75 |
76 |
77 |
78 | prepare-agent
79 |
80 |
81 |
82 |
83 | report
84 | test
85 |
86 | report
87 |
88 |
89 |
90 |
91 | jacoco-check
92 |
93 | check
94 |
95 |
96 |
97 |
98 | PACKAGE
99 |
100 |
101 | LINE
102 | COVEREDRATIO
103 | 0.9
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | spring-milestones
118 | Spring Milestones
119 | https://repo.spring.io/milestone
120 |
121 | false
122 |
123 |
124 |
125 |
126 |
127 | spring-milestones
128 | Spring Milestones
129 | https://repo.spring.io/milestone
130 |
131 | false
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/ChallengeProject/src/main/java/gov/tubitak/keremt/ChallengeApp.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
7 | import org.springframework.web.client.RestTemplate;
8 |
9 | @SpringBootApplication
10 | @EnableJpaRepositories
11 | public class ChallengeApp {
12 | @Bean
13 | public RestTemplate restTemplate(){
14 | return new RestTemplate();
15 | }
16 | public static void main(String[] args) {
17 | SpringApplication.run(ChallengeApp.class, args);
18 | }
19 | }
--------------------------------------------------------------------------------
/ChallengeProject/src/main/java/gov/tubitak/keremt/controllers/StockController.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.controllers;
2 |
3 | import gov.tubitak.keremt.dto.StockDto;
4 | import gov.tubitak.keremt.services.StockService;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.*;
8 | import java.math.BigDecimal;
9 | import java.util.*;
10 |
11 | @RestController
12 | @RequestMapping("/v2/api/stocks")
13 | @RequiredArgsConstructor
14 | public class StockController {
15 | private final StockService stockService;
16 | @PostMapping
17 | public ResponseEntity save(@RequestBody StockDto stockDto,
18 | @RequestParam String symbol,
19 | @RequestParam String date){
20 | return ResponseEntity.ok(stockService.save(stockDto, date, symbol));
21 | }
22 | @GetMapping()
23 | public ResponseEntity> getStocks(@RequestParam(required = false) String symbol,
24 | @RequestParam(required = false) String date){
25 | return ResponseEntity.ok(stockService.getStocks(symbol,date));
26 | }
27 | @GetMapping("/price")
28 | public ResponseEntity getPrice(@RequestParam String symbol,
29 | @RequestParam String date,
30 | @RequestParam String type){
31 | return ResponseEntity.ok(stockService.getPrice(symbol,date,type));
32 | }
33 | @DeleteMapping("/del")
34 | public void deleteAll(){
35 | stockService.deleteAll();
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/ChallengeProject/src/main/java/gov/tubitak/keremt/converter/StockConverter.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.converter;
2 |
3 | import gov.tubitak.keremt.dto.StockDto;
4 | import gov.tubitak.keremt.entity.Stock;
5 | import org.springframework.stereotype.Component;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | @Component
11 | public class StockConverter {
12 | public Stock convertToStock(StockDto stockDto, String date, String symbol){
13 | return new Stock(
14 | (long) 0.0,date,symbol, stockDto.getOpen(), stockDto.getHigh(),
15 | stockDto.getLow(), stockDto.getClose(), stockDto.getAdjusted_close(),stockDto.getVolume());
16 | }
17 | public StockDto convertToStockDto(Stock stock){
18 | return new StockDto(
19 | stock.getDate(),stock.getSymbol(),stock.getOpen(),
20 | stock.getHigh(), stock.getLow(), stock.getClose(),
21 | stock.getAdjusted_close(), stock.getVolume());
22 | }
23 |
24 | public List convertToAllAsStockDTO(List resource){
25 | List stocks = new ArrayList<>();
26 | for (Stock stock : resource)
27 | stocks.add(convertToStockDto(stock));
28 | return stocks;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ChallengeProject/src/main/java/gov/tubitak/keremt/dto/StockDto.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.dto;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import lombok.*;
5 | import java.math.BigDecimal;
6 |
7 | @AllArgsConstructor
8 | @NoArgsConstructor
9 | @Getter
10 | @Setter
11 | @ToString
12 | @EqualsAndHashCode
13 | public class StockDto {
14 | String date;
15 | String symbol;
16 | @JsonProperty("1. open")
17 | BigDecimal open;
18 |
19 | @JsonProperty("2. high")
20 | BigDecimal high;
21 |
22 | @JsonProperty("3. low")
23 | BigDecimal low;
24 |
25 | @JsonProperty("4. close")
26 | BigDecimal close;
27 |
28 | @JsonProperty("5. adjusted close")
29 | BigDecimal adjusted_close;
30 |
31 | @JsonProperty("6. volume")
32 | BigDecimal volume;
33 | }
34 |
--------------------------------------------------------------------------------
/ChallengeProject/src/main/java/gov/tubitak/keremt/dto/TimeSeriesQueryResult.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.dto;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import gov.tubitak.keremt.dto.StockDto;
5 | import lombok.Data;
6 | import java.util.HashMap;
7 |
8 | @Data
9 | public class TimeSeriesQueryResult {
10 | @JsonProperty("Meta Data")
11 | HashMap metaData;
12 |
13 | @JsonProperty("Time Series (Daily)")
14 | HashMap timeSeries;
15 | }
16 |
--------------------------------------------------------------------------------
/ChallengeProject/src/main/java/gov/tubitak/keremt/entity/Stock.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.entity;
2 |
3 | import jakarta.persistence.*;
4 | import lombok.*;
5 | import java.math.BigDecimal;
6 |
7 | @Entity
8 | @Table(name = "stockTable")
9 | @AllArgsConstructor
10 | @NoArgsConstructor
11 | @Getter
12 | @Setter
13 | @ToString
14 | @EqualsAndHashCode
15 | public class Stock {
16 | @Id
17 | @SequenceGenerator(name = "seq_person", allocationSize = 1)
18 | @GeneratedValue(generator = "seq_person", strategy = GenerationType.SEQUENCE)
19 | private Long id;
20 |
21 | @Column
22 | private String date;
23 |
24 | @Column
25 | private String symbol;
26 |
27 | @Column
28 | private BigDecimal open;
29 |
30 | @Column
31 | private BigDecimal high;
32 |
33 | @Column
34 | private BigDecimal low;
35 |
36 | @Column
37 | private BigDecimal close;
38 |
39 | @Column
40 | private BigDecimal adjusted_close;
41 |
42 | @Column
43 | private BigDecimal volume;
44 | }
45 |
--------------------------------------------------------------------------------
/ChallengeProject/src/main/java/gov/tubitak/keremt/loader/StockLoader.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.loader;
2 |
3 | import gov.tubitak.keremt.dto.StockDto;
4 | import gov.tubitak.keremt.dto.TimeSeriesQueryResult;
5 | import gov.tubitak.keremt.repositories.StockRepository;
6 | import gov.tubitak.keremt.services.StockService;
7 | import org.springframework.http.ResponseEntity;
8 | import org.springframework.web.bind.annotation.RestController;
9 | import org.springframework.web.client.RestTemplate;
10 |
11 | import java.time.LocalDate;
12 | import java.util.*;
13 |
14 | @RestController
15 | public class StockLoader extends TimerTask {
16 | private final RestTemplate restTemplate;
17 | private final StockService stockService;
18 | private final String[] symbols= {"IBM","AAPL","TSCO.LON","GPV.TRV","DAI.DEX"};
19 | private LocalDate yesterday;
20 | Timer timer = new Timer();
21 |
22 | public StockLoader(RestTemplate restTemplate, StockService stockService){
23 | this.restTemplate = restTemplate;
24 | this.stockService = stockService;
25 | if (stockService.isRepositoryEmpty()) {
26 | for (String symbol : symbols) {
27 | loadToDB(symbol);
28 | }
29 | }
30 | else
31 | timer.schedule(this,0, 86400000);
32 |
33 | }
34 | @Override
35 | public void run() {
36 | checkDBandYesterday();
37 | }
38 |
39 | /**
40 | * Checking database and yesterday
41 | * reason of yesterday day is final data always belongs to previous day
42 | * */
43 | public void checkDBandYesterday(){
44 | yesterday = LocalDate.now().minusDays(1);
45 | String day = yesterday.getDayOfWeek().toString();
46 | if(!day.equals("SUNDAY") && !day.equals("SATURDAY")) {
47 | if (stockService.getStocks(null, yesterday.toString()).isEmpty()) {
48 | for (String symbol : symbols)
49 | loadToDBDaily(symbol, yesterday.toString());
50 | }
51 | else System.out.println("√----> All Data Already Recorded");
52 | }
53 | else System.out.println("X----> Yesterday was "+day+ ". There is NOT New Data!");
54 | }
55 |
56 | /**
57 | * Filling for empty database
58 | * */
59 | private void loadToDB(String symbol){
60 | String webUrl=
61 | "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol="
62 | +symbol+"&apikey=YJLNB9RRPZW4L704";
63 | ResponseEntity response = (restTemplate.getForEntity(webUrl, TimeSeriesQueryResult.class));
64 | if (response.getBody().getTimeSeries()!=null) {
65 | HashMap temp = response.getBody().getTimeSeries();
66 | for (Map.Entry map : temp.entrySet()) {
67 | stockService.save(map.getValue(), map.getKey(), symbol);
68 | }
69 | System.out.println("√----> All Data Has Been Recorded");
70 | }
71 | else System.out.println("X----> Response is NULL !!!");
72 | }
73 |
74 | /**
75 | * Final data is added to database
76 | * */
77 | private void loadToDBDaily(String symbol, String date) {
78 | String webUrl=
79 | "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol="
80 | +symbol+"&apikey=YJLNB9RRPZW4L704";
81 | ResponseEntity response = (restTemplate.getForEntity(webUrl, TimeSeriesQueryResult.class));
82 | if (response.getBody().getTimeSeries()!=null) {
83 | HashMap temp = response.getBody().getTimeSeries();
84 | for (Map.Entry map : temp.entrySet()) {
85 | if (map.getKey().equals(date)) {
86 | stockService.save(map.getValue(), map.getKey(), symbol);
87 | System.out.println("√----> New Data Has Been Recorded");
88 | break;
89 | }
90 | }
91 | }
92 | else System.out.println("X----> Response is NULL !!!");
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/ChallengeProject/src/main/java/gov/tubitak/keremt/repositories/StockRepository.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.repositories;
2 |
3 | import gov.tubitak.keremt.entity.Stock;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | import java.util.List;
7 |
8 | public interface StockRepository extends JpaRepository {
9 | Stock findBySymbolAndDate(String symbol, String date);
10 | List findBySymbol(String symbol);
11 | List findByDate(String date);
12 | }
13 |
--------------------------------------------------------------------------------
/ChallengeProject/src/main/java/gov/tubitak/keremt/services/StockService.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.services;
2 |
3 | import gov.tubitak.keremt.converter.StockConverter;
4 | import gov.tubitak.keremt.dto.StockDto;
5 | import gov.tubitak.keremt.repositories.StockRepository;
6 | import lombok.RequiredArgsConstructor;
7 | import org.springframework.stereotype.Service;
8 | import java.math.BigDecimal;
9 | import java.util.LinkedList;
10 | import java.util.List;
11 |
12 | @Service
13 | @RequiredArgsConstructor
14 | public class StockService {
15 | private final StockRepository stockRepository;
16 | private final StockConverter stockConverter;
17 | public StockDto save(StockDto stockDto, String date, String symbol){
18 | if (date!=null && symbol != null && stockDto!=null) {
19 | stockRepository.save(stockConverter.convertToStock(stockDto, date, symbol));
20 | return stockDto;
21 | }
22 | else return null;
23 | }
24 | /**
25 | * If symbol and date are NOT NULL
26 | * then it returns a list which has one element.
27 | * However, If symbol and date are NULL
28 | * then it returns a list which has all elements.
29 | */
30 | public List getStocks(String symbol, String date){
31 | List ret = new LinkedList<>();
32 | if (symbol==null && date==null)
33 | ret=stockConverter.convertToAllAsStockDTO(stockRepository.findAll());
34 | else if (symbol!=null && date!=null)
35 | ret.add(stockConverter.convertToStockDto(stockRepository.findBySymbolAndDate(symbol, date)));
36 | else if (symbol!=null)
37 | ret=stockConverter.convertToAllAsStockDTO(stockRepository.findBySymbol(symbol));
38 | else
39 | ret=stockConverter.convertToAllAsStockDTO(stockRepository.findByDate(date));
40 | return ret;
41 | }
42 | public BigDecimal getPrice(String symbol, String date, String type){
43 | return switch (type) {
44 | case "open" -> getStocks(symbol, date).get(0).getOpen();
45 | case "high" -> getStocks(symbol, date).get(0).getHigh();
46 | case "low" -> getStocks(symbol, date).get(0).getLow();
47 | case "close" -> getStocks(symbol, date).get(0).getClose();
48 | case "volume" -> getStocks(symbol, date).get(0).getVolume();
49 | default -> BigDecimal.valueOf(-1);
50 | };
51 | }
52 | public boolean isRepositoryEmpty(){
53 | return stockRepository.count() == 0;
54 | }
55 | public void deleteAll(){
56 | stockRepository.deleteAll();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ChallengeProject/src/main/resources/PostmanCollections/ChallengeProject_Collection_v2.1/StocksProjectAPI.postman_collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "_postman_id": "5b21a272-f98a-4570-97e6-4b70743b916d",
4 | "name": "StocksProjectAPI",
5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
6 | "_exporter_id": "24006704"
7 | },
8 | "item": [
9 | {
10 | "name": "All-Stocks-Info",
11 | "request": {
12 | "method": "GET",
13 | "header": [],
14 | "url": {
15 | "raw": "http://localhost:8081/v2/api/stocks",
16 | "protocol": "http",
17 | "host": [
18 | "localhost"
19 | ],
20 | "port": "8081",
21 | "path": [
22 | "v2",
23 | "api",
24 | "stocks"
25 | ]
26 | }
27 | },
28 | "response": []
29 | },
30 | {
31 | "name": "IBM-Prices-2022-09-06",
32 | "request": {
33 | "method": "GET",
34 | "header": [],
35 | "url": {
36 | "raw": "http://localhost:8081/v2/api/stocks?symbol=IBM&date=2022-09-06",
37 | "protocol": "http",
38 | "host": [
39 | "localhost"
40 | ],
41 | "port": "8081",
42 | "path": [
43 | "v2",
44 | "api",
45 | "stocks"
46 | ],
47 | "query": [
48 | {
49 | "key": "symbol",
50 | "value": "IBM"
51 | },
52 | {
53 | "key": "date",
54 | "value": "2022-09-06"
55 | }
56 | ]
57 | }
58 | },
59 | "response": []
60 | },
61 | {
62 | "name": "IBM-Open-Price-2022-09-06",
63 | "request": {
64 | "method": "GET",
65 | "header": [],
66 | "url": {
67 | "raw": "http://localhost:8081/v2/api/stocks/price?symbol=IBM&date=2022-09-06&type=open",
68 | "protocol": "http",
69 | "host": [
70 | "localhost"
71 | ],
72 | "port": "8081",
73 | "path": [
74 | "v2",
75 | "api",
76 | "stocks",
77 | "price"
78 | ],
79 | "query": [
80 | {
81 | "key": "symbol",
82 | "value": "IBM"
83 | },
84 | {
85 | "key": "date",
86 | "value": "2022-09-06"
87 | },
88 | {
89 | "key": "type",
90 | "value": "open"
91 | }
92 | ]
93 | }
94 | },
95 | "response": []
96 | },
97 | {
98 | "name": "IBM-High-Price-2022-09-06",
99 | "protocolProfileBehavior": {
100 | "disableBodyPruning": true
101 | },
102 | "request": {
103 | "method": "GET",
104 | "header": [],
105 | "body": {
106 | "mode": "raw",
107 | "raw": "",
108 | "options": {
109 | "raw": {
110 | "language": "json"
111 | }
112 | }
113 | },
114 | "url": {
115 | "raw": "http://localhost:8081/v2/api/stocks/price?symbol=IBM&date=2022-09-06&type=high",
116 | "protocol": "http",
117 | "host": [
118 | "localhost"
119 | ],
120 | "port": "8081",
121 | "path": [
122 | "v2",
123 | "api",
124 | "stocks",
125 | "price"
126 | ],
127 | "query": [
128 | {
129 | "key": "symbol",
130 | "value": "IBM"
131 | },
132 | {
133 | "key": "date",
134 | "value": "2022-09-06"
135 | },
136 | {
137 | "key": "type",
138 | "value": "high"
139 | }
140 | ]
141 | }
142 | },
143 | "response": []
144 | },
145 | {
146 | "name": "IBM-Low-Price-2022-09-06",
147 | "request": {
148 | "method": "GET",
149 | "header": [],
150 | "url": {
151 | "raw": "http://localhost:8081/v2/api/stocks/price?symbol=IBM&date=2022-09-06&type=low",
152 | "protocol": "http",
153 | "host": [
154 | "localhost"
155 | ],
156 | "port": "8081",
157 | "path": [
158 | "v2",
159 | "api",
160 | "stocks",
161 | "price"
162 | ],
163 | "query": [
164 | {
165 | "key": "symbol",
166 | "value": "IBM"
167 | },
168 | {
169 | "key": "date",
170 | "value": "2022-09-06"
171 | },
172 | {
173 | "key": "type",
174 | "value": "low"
175 | }
176 | ]
177 | }
178 | },
179 | "response": []
180 | },
181 | {
182 | "name": "IBM-Close-Price-2022-09-06",
183 | "request": {
184 | "method": "GET",
185 | "header": [],
186 | "url": {
187 | "raw": "http://localhost:8081/v2/api/stocks/price?symbol=IBM&date=2022-09-06&type=close",
188 | "protocol": "http",
189 | "host": [
190 | "localhost"
191 | ],
192 | "port": "8081",
193 | "path": [
194 | "v2",
195 | "api",
196 | "stocks",
197 | "price"
198 | ],
199 | "query": [
200 | {
201 | "key": "symbol",
202 | "value": "IBM"
203 | },
204 | {
205 | "key": "date",
206 | "value": "2022-09-06"
207 | },
208 | {
209 | "key": "type",
210 | "value": "close"
211 | }
212 | ]
213 | }
214 | },
215 | "response": []
216 | },
217 | {
218 | "name": "IBM-Volume-Price-2022-09-06",
219 | "request": {
220 | "method": "GET",
221 | "header": [],
222 | "url": {
223 | "raw": "http://localhost:8081/v2/api/stocks/price?symbol=IBM&date=2022-09-06&type=volume",
224 | "protocol": "http",
225 | "host": [
226 | "localhost"
227 | ],
228 | "port": "8081",
229 | "path": [
230 | "v2",
231 | "api",
232 | "stocks",
233 | "price"
234 | ],
235 | "query": [
236 | {
237 | "key": "symbol",
238 | "value": "IBM"
239 | },
240 | {
241 | "key": "date",
242 | "value": "2022-09-06"
243 | },
244 | {
245 | "key": "type",
246 | "value": "volume"
247 | }
248 | ]
249 | }
250 | },
251 | "response": []
252 | },
253 | {
254 | "name": "All-Stocks-Date-2022-09-06",
255 | "request": {
256 | "method": "GET",
257 | "header": [],
258 | "url": {
259 | "raw": "http://localhost:8081/v2/api/stocks?date=2022-09-06",
260 | "protocol": "http",
261 | "host": [
262 | "localhost"
263 | ],
264 | "port": "8081",
265 | "path": [
266 | "v2",
267 | "api",
268 | "stocks"
269 | ],
270 | "query": [
271 | {
272 | "key": "date",
273 | "value": "2022-09-06"
274 | }
275 | ]
276 | }
277 | },
278 | "response": []
279 | },
280 | {
281 | "name": "All-Stocks-IBM",
282 | "protocolProfileBehavior": {
283 | "disableBodyPruning": true
284 | },
285 | "request": {
286 | "method": "GET",
287 | "header": [],
288 | "body": {
289 | "mode": "raw",
290 | "raw": "",
291 | "options": {
292 | "raw": {
293 | "language": "json"
294 | }
295 | }
296 | },
297 | "url": {
298 | "raw": "http://localhost:8081/v2/api/stocks?symbol=IBM",
299 | "protocol": "http",
300 | "host": [
301 | "localhost"
302 | ],
303 | "port": "8081",
304 | "path": [
305 | "v2",
306 | "api",
307 | "stocks"
308 | ],
309 | "query": [
310 | {
311 | "key": "symbol",
312 | "value": "IBM"
313 | }
314 | ]
315 | }
316 | },
317 | "response": []
318 | },
319 | {
320 | "name": "Delete-All-Data-On-The-Database",
321 | "request": {
322 | "method": "DELETE",
323 | "header": [],
324 | "url": {
325 | "raw": "http://localhost:8081/v2/api/stocks/del",
326 | "protocol": "http",
327 | "host": [
328 | "localhost"
329 | ],
330 | "port": "8081",
331 | "path": [
332 | "v2",
333 | "api",
334 | "stocks",
335 | "del"
336 | ]
337 | }
338 | },
339 | "response": []
340 | }
341 | ]
342 | }
--------------------------------------------------------------------------------
/ChallengeProject/src/main/resources/PostmanCollections/collections.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeremTAN/Java-Spring/54acf8765d521e27d2716f08dccddfbb55b0fc62/ChallengeProject/src/main/resources/PostmanCollections/collections.png
--------------------------------------------------------------------------------
/ChallengeProject/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=8081
2 | !spring.jpa.hibernate.ddl-auto=update
3 | !spring.datasource.url=jdbc:postgresql://localhost:5432/stockdb
4 | !spring.datasource.username=postgres
5 | !spring.datasource.password=pass
6 | spring.h2.console.enabled=true
7 | spring.datasource.url=jdbc:h2:mem:stockdb
8 | spring.datasource.driverClassName=org.h2.Driver
9 | spring.datasource.username=sa
10 | spring.datasource.password=
--------------------------------------------------------------------------------
/ChallengeProject/src/main/resources/docker-compose.yml:
--------------------------------------------------------------------------------
1 | # Use postgres/example user/password credentials
2 | version: '3.1'
3 |
4 | services:
5 |
6 | db:
7 | image: postgres
8 | restart: always
9 | ports:
10 | - 5432:5432
11 | environment:
12 | POSTGRES_PASSWORD: pass
13 |
14 | adminer:
15 | image: adminer
16 | restart: always
17 | ports:
18 | - 8080:8080
--------------------------------------------------------------------------------
/ChallengeProject/src/test/java/gov/tubitak/keremt/MockObjects.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt;
2 |
3 | import gov.tubitak.keremt.dto.StockDto;
4 | import gov.tubitak.keremt.entity.Stock;
5 | import lombok.EqualsAndHashCode;
6 | import lombok.Getter;
7 |
8 | import java.math.BigDecimal;
9 | import java.util.LinkedList;
10 | import java.util.List;
11 |
12 | @Getter
13 | @EqualsAndHashCode
14 | public class MockObjects {
15 | List testStockDTOList =new LinkedList<>();
16 | List mockStockList =new LinkedList<>();
17 |
18 | /** TEST STOCKDTO OBJECTS **/
19 | StockDto testFirstIBMStockDto =new StockDto("2022-09-06","IBM",
20 | BigDecimal.valueOf(127.80),BigDecimal.valueOf(128.06),BigDecimal.valueOf(126.30),
21 | BigDecimal.valueOf(126.72), BigDecimal.valueOf(11),BigDecimal.valueOf(3345343.00));
22 | StockDto testSecondIBMStockDto =new StockDto("2022-08-31","IBM",
23 | BigDecimal.valueOf(129.92),BigDecimal.valueOf(130.00),BigDecimal.valueOf(128.40),
24 | BigDecimal.valueOf(128.45), BigDecimal.valueOf(22),BigDecimal.valueOf(3490380.00));
25 | StockDto testThirdAAPLStockDto =new StockDto("2022-09-06","AAPL",
26 | BigDecimal.valueOf(156.47),BigDecimal.valueOf(157.07),BigDecimal.valueOf(154.53),
27 | BigDecimal.valueOf(128.45), BigDecimal.valueOf(33),BigDecimal.valueOf(73295539.00));
28 |
29 | /** MOCK STOCK OBJECTS **/
30 | Stock mockFirstIBMStock =new Stock(0L,"2022-09-06","IBM",
31 | BigDecimal.valueOf(127.80),BigDecimal.valueOf(128.06),BigDecimal.valueOf(126.30),
32 | BigDecimal.valueOf(126.72), BigDecimal.valueOf(11),BigDecimal.valueOf(3345343.00));
33 | Stock mockSecondIBMStock =new Stock(1L, "2022-08-31","IBM",
34 | BigDecimal.valueOf(129.92),BigDecimal.valueOf(130.00),BigDecimal.valueOf(128.40),
35 | BigDecimal.valueOf(128.45), BigDecimal.valueOf(22),BigDecimal.valueOf(3490380.00));
36 |
37 | Stock mockThirdAAPLStock =new Stock(2L,"2022-09-06","AAPL",
38 | BigDecimal.valueOf(156.47),BigDecimal.valueOf(157.07), BigDecimal.valueOf(154.53),
39 | BigDecimal.valueOf(128.45),BigDecimal.valueOf(33), BigDecimal.valueOf(73295539.00));
40 |
41 | /** CREATE LISTS **/
42 | public void createFirstIBMStockDTO(){
43 | testStockDTOList.clear();
44 | testStockDTOList.add(testFirstIBMStockDto);
45 | }
46 | public void createIBMList(){
47 | testStockDTOList.clear();
48 | testStockDTOList.add(testFirstIBMStockDto);
49 | testStockDTOList.add(testSecondIBMStockDto);
50 | mockStockList.clear();
51 | mockStockList.add(mockFirstIBMStock);
52 | mockStockList.add(mockSecondIBMStock);
53 | }
54 | public void createDateList(){
55 | testStockDTOList.clear();
56 | testStockDTOList.add(testFirstIBMStockDto);
57 | testStockDTOList.add(testThirdAAPLStockDto);
58 | mockStockList.clear();
59 | mockStockList.add(mockFirstIBMStock);
60 | mockStockList.add(mockSecondIBMStock);
61 | }
62 | public void createAllList() {
63 | testStockDTOList.clear();
64 | testStockDTOList.add(testFirstIBMStockDto);
65 | testStockDTOList.add(testSecondIBMStockDto);
66 | testStockDTOList.add(testThirdAAPLStockDto);
67 | mockStockList.clear();
68 | mockStockList.add(mockFirstIBMStock);
69 | mockStockList.add(mockSecondIBMStock);
70 | mockStockList.add(mockThirdAAPLStock);
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/ChallengeProject/src/test/java/gov/tubitak/keremt/controllers/StockControllerTest.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.controllers;
2 |
3 | import gov.tubitak.keremt.MockObjects;
4 | import gov.tubitak.keremt.services.StockService;
5 | import org.junit.jupiter.api.Test;
6 | import org.junit.jupiter.api.extension.ExtendWith;
7 | import org.mockito.InjectMocks;
8 | import org.mockito.Mock;
9 | import org.mockito.junit.jupiter.MockitoExtension;
10 | import org.springframework.http.ResponseEntity;
11 |
12 | import java.math.BigDecimal;
13 |
14 | import static org.junit.jupiter.api.Assertions.*;
15 | import static org.mockito.Mockito.doNothing;
16 | import static org.mockito.Mockito.when;
17 |
18 | @ExtendWith(MockitoExtension.class)
19 | class StockControllerTest {
20 | @InjectMocks
21 | private StockController controller;
22 | @Mock
23 | private StockService service;
24 | MockObjects mObj = new MockObjects();
25 |
26 | /**
27 | ** Get Stocks Method ***
28 | */
29 |
30 | @Test
31 | public void whenGetStocksCalledWithValidAllRequest_ReturnsFirstIBM(){
32 | mObj.getTestStockDTOList().clear();
33 | mObj.getTestStockDTOList().add(mObj.getTestFirstIBMStockDto());
34 |
35 | when(service.getStocks("IBM","2022-09-6"))
36 | .thenReturn(mObj.getTestStockDTOList());
37 |
38 | assertEquals(
39 | ResponseEntity.ok(mObj.getTestStockDTOList()),
40 | controller.getStocks("IBM","2022-09-6")
41 | );
42 | }
43 | @Test
44 | public void whenGetStocksCalledWithSymbolAndNoDate_ReturnsIBMList(){
45 | mObj.createIBMList();
46 | when(service.getStocks("IBM",null))
47 | .thenReturn(mObj.getTestStockDTOList());
48 |
49 | assertEquals(
50 | ResponseEntity.ok(mObj.getTestStockDTOList()),
51 | controller.getStocks("IBM",null)
52 | );
53 | }
54 | @Test
55 | public void whenGetStocksCalledWithNoSymbolAndDate_ReturnsDateList(){
56 | mObj.createDateList();
57 | when(service.getStocks("IBM",null))
58 | .thenReturn(mObj.getTestStockDTOList());
59 |
60 | assertEquals(
61 | ResponseEntity.ok(mObj.getTestStockDTOList()),
62 | controller.getStocks("IBM",null)
63 | );
64 | }
65 | @Test
66 | public void whenGetStocksCalledWithNoSymbolAndNoDate_ReturnsAllList() {
67 | mObj.createDateList();
68 | when(service.getStocks(null, null))
69 | .thenReturn(mObj.getTestStockDTOList());
70 |
71 | assertEquals(
72 | ResponseEntity.ok(mObj.getTestStockDTOList()),
73 | controller.getStocks(null, null)
74 | );
75 | }
76 |
77 | /**
78 | ** Get Price Method ***
79 | */
80 | @Test
81 | public void whenGetPriceCalledWithValidReqsTypeOpen_ReturnsOpenPrice(){
82 | when(service.getPrice("IBM","2022-09-6","open"))
83 | .thenReturn(mObj.getMockFirstIBMStock().getOpen());
84 | assertEquals(
85 | ResponseEntity.ok(BigDecimal.valueOf(127.80)),
86 | controller.getPrice("IBM","2022-09-6","open")
87 | );
88 | }
89 | @Test
90 | public void whenGetPriceCalledWithValidReqsTypeHigh_ReturnsHighPrice(){
91 | when(service.getPrice("IBM","2022-09-6","high"))
92 | .thenReturn(mObj.getMockFirstIBMStock().getHigh());
93 | assertEquals(
94 | ResponseEntity.ok(BigDecimal.valueOf(128.06)),
95 | controller.getPrice("IBM","2022-09-6","high")
96 | );
97 | }
98 | @Test
99 | public void whenGetPriceCalledWithValidReqsTypeLow_ReturnsLowPrice(){
100 | when(service.getPrice("IBM","2022-09-6","low"))
101 | .thenReturn(mObj.getMockFirstIBMStock().getLow());
102 | assertEquals(
103 | ResponseEntity.ok(BigDecimal.valueOf(126.30)),
104 | controller.getPrice("IBM","2022-09-6","low")
105 | );
106 | }
107 | @Test
108 | public void whenGetPriceCalledWithValidReqsTypeClose_ReturnsClosePrice(){
109 | when(service.getPrice("IBM","2022-09-6","close"))
110 | .thenReturn(mObj.getMockFirstIBMStock().getClose());
111 | assertEquals(
112 | ResponseEntity.ok(BigDecimal.valueOf(126.72)),
113 | controller.getPrice("IBM","2022-09-6","close")
114 | );
115 | }
116 | @Test
117 | public void whenGetPriceCalledWithValidReqsTypeVolume_ReturnsVolumePrice(){
118 | when(service.getPrice("IBM","2022-09-6","volume"))
119 | .thenReturn(mObj.getMockFirstIBMStock().getVolume());
120 | assertEquals(
121 | ResponseEntity.ok(BigDecimal.valueOf(3345343.00)),
122 | controller.getPrice("IBM","2022-09-6","volume")
123 | );
124 | }
125 |
126 | /**
127 | ** Save Method ***
128 | */
129 | @Test
130 | public void whenSaveCalledWithValidReqs_ReturnsStockDto(){
131 | when(service.save(mObj.getTestFirstIBMStockDto(),"2022-09-6","IBM"))
132 | .thenReturn(mObj.getTestFirstIBMStockDto());
133 | assertEquals(
134 | ResponseEntity.ok(mObj.getTestFirstIBMStockDto()),
135 | controller.save(mObj.getTestFirstIBMStockDto(),"IBM","2022-09-6")
136 | );
137 | }
138 | @Test
139 | public void whenSaveCalledWithDateNull_ReturnsNULL(){
140 | when(service.save(mObj.getTestFirstIBMStockDto(),null,"IBM"))
141 | .thenReturn(null);
142 | assertEquals(
143 | ResponseEntity.ok(null),
144 | controller.save(mObj.getTestFirstIBMStockDto(),"IBM",null)
145 | );
146 | }
147 | @Test
148 | public void whenSaveCalledWithSymbolNull_ReturnsNULL(){
149 | when(service.save(mObj.getTestFirstIBMStockDto(),"2022-09-6",null))
150 | .thenReturn(null);
151 | assertEquals(
152 | ResponseEntity.ok(null),
153 | controller.save(mObj.getTestFirstIBMStockDto(),null,"2022-09-6")
154 | );
155 | }
156 | @Test
157 | public void whenSaveCalledWithEmptyStockDto_ReturnsNull(){
158 | when(service.save(null,"2022-09-6","IBM"))
159 | .thenReturn(null);
160 | assertEquals(
161 | ResponseEntity.ok(null),
162 | controller.save(null,"IBM","2022-09-6")
163 | );
164 | }
165 |
166 | /**
167 | ** Delete Method ***
168 | */
169 | @Test
170 | public void whenDeleteAllCalled_(){
171 | doNothing().when(service).deleteAll();
172 | controller.deleteAll();
173 | }
174 | }
--------------------------------------------------------------------------------
/ChallengeProject/src/test/java/gov/tubitak/keremt/converter/StockConverterTest.java:
--------------------------------------------------------------------------------
1 |
2 | package gov.tubitak.keremt.converter;
3 | import gov.tubitak.keremt.MockObjects;
4 | import org.junit.jupiter.api.Test;
5 | import static org.junit.jupiter.api.Assertions.*;
6 |
7 | class StockConverterTest {
8 | private final StockConverter converter = new StockConverter();
9 | MockObjects mObj = new MockObjects();
10 |
11 | /***** TESTS ****/
12 | @Test
13 | public void whenConvertToStockCalledValidRequest_ReturnsStock(){
14 | assertEquals(
15 | mObj.getMockFirstIBMStock(),
16 | converter.convertToStock(mObj.getTestFirstIBMStockDto(),"2022-09-06","IBM"));
17 | }
18 | @Test
19 | public void whenConvertToStockDTOCalledValidRequest_ReturnsStockDTO(){
20 | assertEquals(
21 | mObj.getTestFirstIBMStockDto(),
22 | converter.convertToStockDto(mObj.getMockFirstIBMStock()));
23 | }
24 | @Test
25 | public void convertToAllAsStockDTOCalledValidRequest_ReturnsAllStockDTO(){
26 | mObj.createAllList();
27 | assertEquals(
28 | mObj.getTestStockDTOList(),
29 | converter.convertToAllAsStockDTO(mObj.getMockStockList()));
30 | }
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/ChallengeProject/src/test/java/gov/tubitak/keremt/dto/StockDtoTest.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.dto;
2 |
3 | import gov.tubitak.keremt.MockObjects;
4 | import org.junit.jupiter.api.Test;
5 | import java.math.BigDecimal;
6 | import static org.junit.jupiter.api.Assertions.*;
7 |
8 | class StockDtoTest {
9 | MockObjects mObj = new MockObjects();
10 | StockDto stockDto = mObj.getTestFirstIBMStockDto();
11 | StockDto NoArgsConstructor = new StockDto();
12 |
13 |
14 | @Test
15 | void testSetDate() {
16 | stockDto.setDate("2022-12-30");
17 | assertEquals("2022-12-30", stockDto.getDate());
18 | }
19 |
20 | @Test
21 | void testSetSymbol() {
22 | stockDto.setSymbol("MBI");
23 | assertEquals("MBI", stockDto.getSymbol());
24 | }
25 |
26 | @Test
27 | void testSetOpen() {
28 | stockDto.setOpen(BigDecimal.valueOf(123.54));
29 | assertEquals(BigDecimal.valueOf(123.54), stockDto.getOpen());
30 | }
31 |
32 | @Test
33 | void testSetHigh() {
34 | stockDto.setHigh(BigDecimal.valueOf(123.54));
35 | assertEquals(BigDecimal.valueOf(123.54), stockDto.getHigh());
36 | }
37 |
38 | @Test
39 | void testSetLow() {
40 | stockDto.setLow(BigDecimal.valueOf(123.54));
41 | assertEquals(BigDecimal.valueOf(123.54), stockDto.getLow());
42 | }
43 |
44 | @Test
45 | void testSetClose() {
46 | stockDto.setClose(BigDecimal.valueOf(123.54));
47 | assertEquals(BigDecimal.valueOf(123.54), stockDto.getClose());
48 | }
49 |
50 | @Test
51 | void testSetVolume() {
52 | stockDto.setVolume(BigDecimal.valueOf(12354.9));
53 | assertEquals(BigDecimal.valueOf(12354.9), stockDto.getVolume());
54 | }
55 |
56 | @Test
57 | void testToString() {
58 | String s =
59 | "StockDto(date=2022-09-06, symbol=IBM, open=127.8, high=128.06," +
60 | " low=126.3, close=126.72, adjusted_close=11, volume=3345343.0)";
61 | assertEquals(s, stockDto.toString());
62 | }
63 |
64 | }
--------------------------------------------------------------------------------
/ChallengeProject/src/test/java/gov/tubitak/keremt/entity/StockTest.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.entity;
2 |
3 | import gov.tubitak.keremt.MockObjects;
4 | import org.junit.jupiter.api.Test;
5 | import java.math.BigDecimal;
6 | import static org.junit.jupiter.api.Assertions.*;
7 |
8 | class StockTest {
9 | MockObjects mObj = new MockObjects();
10 | Stock stock = mObj.getMockFirstIBMStock();
11 | Stock NoArgsConstructor = new Stock();
12 |
13 | @Test
14 | void testSetId() {
15 | stock.setId((123456789L));
16 | assertEquals(123456789L, stock.getId());
17 | }
18 |
19 | @Test
20 | void testSetDate() {
21 | stock.setDate("2022-12-30");
22 | assertEquals("2022-12-30", stock.getDate());
23 | }
24 |
25 | @Test
26 | void testSetSymbol() {
27 | stock.setSymbol("MBI");
28 | assertEquals("MBI", stock.getSymbol());
29 | }
30 |
31 | @Test
32 | void testSetOpen() {
33 | stock.setOpen(BigDecimal.valueOf(123.54));
34 | assertEquals(BigDecimal.valueOf(123.54), stock.getOpen());
35 | }
36 |
37 | @Test
38 | void testSetHigh() {
39 | stock.setHigh(BigDecimal.valueOf(123.54));
40 | assertEquals(BigDecimal.valueOf(123.54), stock.getHigh());
41 | }
42 |
43 | @Test
44 | void testSetLow() {
45 | stock.setLow(BigDecimal.valueOf(123.54));
46 | assertEquals(BigDecimal.valueOf(123.54), stock.getLow());
47 | }
48 |
49 | @Test
50 | void testSetClose() {
51 | stock.setClose(BigDecimal.valueOf(123.54));
52 | assertEquals(BigDecimal.valueOf(123.54), stock.getClose());
53 | }
54 |
55 | @Test
56 | void testSetVolume() {
57 | stock.setVolume(BigDecimal.valueOf(12354.9));
58 | assertEquals(BigDecimal.valueOf(12354.9), stock.getVolume());
59 | }
60 |
61 | @Test
62 | void testToString() {
63 | String s =
64 | "Stock(id=0, date=2022-09-06, symbol=IBM, open=127.8, high=128.06," +
65 | " low=126.3, close=126.72, adjusted_close=11, volume=3345343.0)";
66 | assertEquals(s, stock.toString());
67 | }
68 | }
--------------------------------------------------------------------------------
/ChallengeProject/src/test/java/gov/tubitak/keremt/services/StockServiceTest.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.keremt.services;
2 |
3 | import gov.tubitak.keremt.MockObjects;
4 | import gov.tubitak.keremt.converter.StockConverter;
5 | import gov.tubitak.keremt.repositories.StockRepository;
6 | import org.junit.jupiter.api.Test;
7 | import org.junit.jupiter.api.extension.ExtendWith;
8 | import org.mockito.InjectMocks;
9 | import org.mockito.Mock;
10 | import org.mockito.junit.jupiter.MockitoExtension;
11 | import java.math.BigDecimal;
12 |
13 | import static org.junit.jupiter.api.Assertions.*;
14 | import static org.mockito.Mockito.*;
15 |
16 | @ExtendWith(MockitoExtension.class)
17 | public class StockServiceTest {
18 | @InjectMocks
19 | private StockService service;
20 | @Mock
21 | private StockRepository stockRepository;
22 | @Mock
23 | private StockConverter stockConverter;
24 |
25 | MockObjects mObj = new MockObjects();
26 |
27 |
28 | /***** TESTS *****/
29 |
30 | /**
31 | ** GetPrice Method ***
32 | */
33 | @Test
34 | public void whenGetPriceCalledWithValidRequestTypeOpen_ReturnsOpenPrice(){
35 | mObj.createFirstIBMStockDTO();
36 | when(stockConverter.convertToStockDto(mObj.getMockFirstIBMStock()))
37 | .thenReturn(mObj.getTestFirstIBMStockDto());
38 | when(stockRepository.findBySymbolAndDate("IBM","2022-09-06"))
39 | .thenReturn(mObj.getMockFirstIBMStock());
40 | //testValue.get(0).getHigh()
41 | assertEquals(BigDecimal.valueOf(127.80), service.getPrice("IBM","2022-09-06","open"));
42 | }
43 | @Test
44 | public void whenGetPriceCalledWithValidRequestTypHigh_ReturnsHighPrice(){
45 | mObj.createFirstIBMStockDTO();
46 | when(stockConverter.convertToStockDto(mObj.getMockFirstIBMStock()))
47 | .thenReturn(mObj.getTestFirstIBMStockDto());
48 | when(stockRepository.findBySymbolAndDate("IBM","2022-09-06"))
49 | .thenReturn(mObj.getMockFirstIBMStock());
50 | assertEquals(BigDecimal.valueOf(128.06), service.getPrice("IBM","2022-09-06","high"));
51 | }
52 | @Test
53 | public void whenGetPriceCalledWithValidRequestTypeLow_ReturnsLowPrice(){
54 | mObj.createFirstIBMStockDTO();
55 | when(stockConverter.convertToStockDto(mObj.getMockFirstIBMStock()))
56 | .thenReturn(mObj.getTestFirstIBMStockDto());
57 | when(stockRepository.findBySymbolAndDate("IBM","2022-09-06"))
58 | .thenReturn(mObj.getMockFirstIBMStock());
59 | assertEquals(BigDecimal.valueOf(126.30), service.getPrice("IBM","2022-09-06","low"));
60 | }
61 | @Test
62 | public void whenGetPriceCalledWithValidRequestTypeClose_ReturnsClosePrice(){
63 | mObj.createFirstIBMStockDTO();
64 | when(stockConverter.convertToStockDto(mObj.getMockFirstIBMStock()))
65 | .thenReturn(mObj.getTestFirstIBMStockDto());
66 | when(stockRepository.findBySymbolAndDate("IBM","2022-09-06"))
67 | .thenReturn(mObj.getMockFirstIBMStock());
68 | assertEquals(BigDecimal.valueOf(126.72), service.getPrice("IBM","2022-09-06","close"));
69 | }
70 | @Test
71 | public void whenGetPriceCalledWithValidRequestTypeVolume_ReturnsVolume(){
72 | mObj.createFirstIBMStockDTO();
73 | when(stockConverter.convertToStockDto(mObj.getMockFirstIBMStock()))
74 | .thenReturn(mObj.getTestFirstIBMStockDto());
75 | when(stockRepository.findBySymbolAndDate("IBM","2022-09-06"))
76 | .thenReturn(mObj.getMockFirstIBMStock());
77 | assertEquals(BigDecimal.valueOf(3345343.00), service.getPrice("IBM","2022-09-06","volume"));
78 | }
79 | @Test
80 | public void whenGetPriceCalledWithValidRequestInValidType_ReturnsMinus1(){
81 | BigDecimal expectedValue = BigDecimal.valueOf(-1);
82 | assertEquals(expectedValue, service.getPrice("IBM","2022-09-06","none"));
83 | }
84 |
85 | /**
86 | ** IsRepositoryEmpty Method ***
87 | */
88 | @Test
89 | public void whenIsRepositoryEmptyCalledWithFullElements_ReturnsFalse(){
90 | mObj.createIBMList();
91 |
92 | when(stockRepository.count())
93 | .thenReturn((long) mObj.getMockStockList().size());
94 |
95 | assertEquals(2,stockRepository.count());
96 | assertFalse(service.isRepositoryEmpty());
97 | }
98 | @Test
99 | public void whenIsRepositoryEmptyCalledWithEmptyElements_ReturnsTrue(){
100 | mObj.getMockStockList().clear();
101 |
102 | when(stockRepository.count())
103 | .thenReturn((long) mObj.getMockStockList().size());
104 |
105 | assertEquals(0,stockRepository.count());
106 | assertTrue(service.isRepositoryEmpty());
107 | }
108 |
109 | /**
110 | ** GetStocks Method ***
111 | */
112 | @Test
113 | public void whenGetStocksCalledNullRequest_ReturnsAllElements(){
114 | mObj.createAllList();
115 |
116 | when(stockRepository.findAll())
117 | .thenReturn(mObj.getMockStockList());
118 | when(stockConverter.convertToAllAsStockDTO(mObj.getMockStockList()))
119 | .thenReturn(mObj.getTestStockDTOList());
120 | assertEquals(mObj.getTestStockDTOList(), service.getStocks(null,null));
121 | }
122 | @Test
123 | public void whenGetStocksCalledSymbolAndDate_ReturnsFirstIBMStockDTO(){
124 | mObj.getTestStockDTOList().clear();
125 | mObj.getTestStockDTOList().add(mObj.getTestFirstIBMStockDto());
126 |
127 | when(stockRepository.findBySymbolAndDate("IBM","2022-09-06"))
128 | .thenReturn(mObj.getMockFirstIBMStock());
129 | when(stockConverter.convertToStockDto(mObj.getMockFirstIBMStock()))
130 | .thenReturn(mObj.getTestFirstIBMStockDto());
131 | assertEquals(mObj.getTestStockDTOList(), service.getStocks("IBM","2022-09-06"));
132 | }
133 | @Test
134 | public void whenGetStocksCalledWithSymbol_ReturnsIBMList(){
135 | mObj.createIBMList();
136 | when(stockRepository.findBySymbol("IBM"))
137 | .thenReturn(mObj.getMockStockList());
138 | when(stockConverter.convertToAllAsStockDTO(mObj.getMockStockList()))
139 | .thenReturn(mObj.getTestStockDTOList());
140 | assertEquals(mObj.getTestStockDTOList(), service.getStocks("IBM",null));
141 | }
142 | @Test
143 | public void whenGetStocksCalledWithDate_ReturnsDateList(){
144 | mObj.createDateList();
145 | when(stockRepository.findByDate("2022-09-06"))
146 | .thenReturn(mObj.getMockStockList());
147 | when(stockConverter.convertToAllAsStockDTO(mObj.getMockStockList()))
148 | .thenReturn(mObj.getTestStockDTOList());
149 | assertEquals(mObj.getTestStockDTOList(), service.getStocks(null,"2022-09-06"));
150 | }
151 |
152 | /**
153 | ** Save Method ***
154 | */
155 | @Test
156 | public void whenSaveCalledWithValidRequest_ReturnsAllElements(){
157 | when(stockConverter.convertToStock(mObj.getTestFirstIBMStockDto(),"2022-09-06","IBM"))
158 | .thenReturn(mObj.getMockFirstIBMStock());
159 | assertEquals(mObj.getTestFirstIBMStockDto(),
160 | service.save(mObj.getTestFirstIBMStockDto(),"2022-09-06","IBM"));
161 | }
162 | @Test
163 | public void whenSaveCalledWithInValidRequest_ReturnsNull(){
164 | assertNull(service.save(mObj.getTestFirstIBMStockDto(), null, null));
165 | }
166 |
167 | /**
168 | ** Delete Method ***
169 | */
170 | @Test
171 | public void whenDeleteAllCalled_(){
172 | doNothing().when(stockRepository).deleteAll();
173 | service.deleteAll();
174 | }
175 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JAVA Spring
2 |
3 | * [Spring Framework](#springframework)
4 | * [The brief reasons why the Spring Framework is so popular and used are;](#why)
5 | * [Plain Old Java Object(POJO) in Briefly](#pojo)
6 | * [Inversion of Control(IoC) in Briefly](#ioc)
7 | * [Spring's IoC Container in Briefly](#sioc)
8 | * [Dependency Injection(DI) in Briefly](#di)
9 | 1. [Constructor Dependency Injection](#dic)
10 | 2. [Property(or Setter) Dependency Injection](#dip)
11 | 3. [Interface(or Method) Dependency Injection](#dii)
12 | 4. [[Bonus] Field Dependency Injection](#dif)
13 | * [Spring Boot](#springboot)
14 | * [Spring Boot Layered Architecture](#sbla)
15 | * [Presentation Layer](#pl)
16 | * [Business Layer](#bl)
17 | * [Persistence Layer](#pla)
18 | * [Entity Objects](#eo)
19 | * [Application Programming Interface(API)](#api)
20 | * [Representational State Transfer(REST)](#rest)
21 | * [REST API](#restapi)
22 | * [Challenge Project](#chpr)
23 | * [Information about on Database](#db)
24 | * [Request and Postman](#postman)
25 | * [An output example from the Challenge Project](#output)
26 |
27 |
28 | ## Spring Framework
29 |
30 | **Spring Framework** is an open source application framework which is leightweight has been designed by **Rod Johnson** and first version released in 2003.
31 |
32 | **The purpose of Spring Framework** is to enable easy, fast and reliable development of any robust and large-scale Java application. Additionally, it provides a bunch of different extensions that can be used to build all kinds of large-scale applications on Java EE (Java Enterprise Edition). Therefore, it is one of the most preferred frameworks in most enterprise Java applications.
33 |
34 | **The reason for the emergence of the Spring Framework** is that Java EE (new name Jakarta EE), which was widely used before the Spring Framework, has a very complex application development environment and a deep Java EE learning requirement due to this complexity. The fact that these requirements also increase the management cost of the applications has ensured that the Spring Framework has been kept in a short time against to Java EE.
35 |
36 |
37 | ### The brief reasons why the Spring Framework is so popular and used are;
38 | * It uses POJO(Plain Old Java Object), don’t need an enterprise container like an application server.
39 | * It's is Inversion of Control (IoC) and Dependency Injection (DI) features provide the foundation for a wide-ranging set of features and functionality.
40 | * It provides a great level of modularity.
41 | * Well-Designed Web Framework.
42 | * Spring application code tends to be very easy to make test cases for various testings.
43 | * Middle-tier objects can be easily organized.
44 |
45 |
46 |
47 | ### Plain Old Java Object(POJO) in Briefly
48 | POJO is an ordinary object that is not subject to any special restrictions.
49 | The POJO class does not have connections with another class, such as extends, implements.
50 | POJO file does not require any special classpath. It increases the readability and reusability of a Java program.
51 |
52 | Some Properties of POJO
53 | * The POJO class must be public.
54 | * It can have a public default constructor or arguments constructor.
55 | * POJO Classes can have any access modifies such as private, public, protected.
56 | * A POJO class should not extend predefined classes.
57 | * It should not implement prespecified interfaces.
58 | * It should not have any prespecified annotation.
59 | * All objects must have some public Getters and Setters to access the object values by other Java Programs.
60 |
61 | A Code Example of POJO
62 |
63 | ```java
64 | public class Human{
65 | private String name;
66 | private String lastName;
67 | private int age;
68 |
69 | public String getName() { return name; }
70 | public void setName(String name) { this.name = name; }
71 | public String getlastName() { return lastName; }
72 | public void setLastName(String lastName) { this.lastName = lastName; }
73 | public int getage() { return age; }
74 | public void setAge(int age) { this.age = age; }
75 | }
76 | ```
77 | ---------------------------------
78 |
79 |
80 |
81 | ### Inversion of Control(IoC) in Briefly
82 | When a class uses another class, the class controls the another class.
83 | For example, the save behavior of an object calls the save behavior of another object which is a component of the object which is created within itself in some situations.
84 | In some cases, we want to take that control back into our own hands.
85 | This is the inversion of control paradigm.
86 | There are different solutions to do Inversion of Control.
87 | However, the most common way to do IoC is usually to inject another object component inside the object by injecting it from outside instead of rendering it inside the object.
88 | In this way, we can set the save behavior of any desired object wanted to use the save behavior of the object.
89 | That is called Dependency Injection principle.
90 | Other ideas for implementing the IoC paradigm apart from Dependency Injection are Strategy Design Pattern, Service Lacator Design Pattern and Factory Design Pattern.
91 |
92 |
93 |
94 | ### Spring's IoC Container in Briefly
95 | Some of classes are used to carry data, while some of classes are used for their functionality.
96 | It is usually sufficient for us to generate only unique an object from the classes we use for their functionality (in this way, the object generation design is called Singleton Design Pattern).
97 | IoC container is a kind of memory space in Spring.
98 | Singleton objects whose functionality we want to use over and over again are placed in the IoC Container.
99 | When the objects placed in the IoC Container are desired to be used, a reference is assigned to the relevant field with the Dependency Injection principle.
100 | In this way, the objects that we want to use for their functionality are not constantly reproduced.
101 | The @Autowired annotation is usually used for the Dependency Injection method in Spring. With the @Autowired annotation, the address of the required object is taken from the memory and a reference is assigned to the required field.
102 |
103 |
104 |
105 | ### Dependency Injection(DI) in Briefly
106 | Dependency Injection is that needed object(s) inject to the dependent object when an object is dependent on another object(s).
107 | The main purpose of using DI principle is that needed object(s) can changed without changing dependent object when the needed object(s) to be changed.
108 | Likewise, when a change is made in the needed object(s), it is to prevent it from directly affecting dependent object.
109 | Dependency Injection must take the control of the creating and etc. of needed object(s) for being able to do these.
110 | This means that DI uses the IoC paradigsm.
111 |
112 | ### Injection can be done in 3 different ways in Dependency Injection
113 |
114 |
115 | * **Constructor Dependency Injection:** Needed class is provided through the dependency class' constructor.
116 |
117 | ```java
118 | public class Controller{
119 | private IServices service;
120 | public Controller(IServices service) {
121 | this.service=service;
122 | }
123 | }
124 | ```
125 | ---------------------------------
126 |
127 |
128 | * **Property(or Setter) Dependency Injection:** The injector supplies the needed object(s) through a public property of the dependency class.
129 |
130 | ```java
131 | public class Controller{
132 | private IServices service;
133 |
134 | public Controller() {}
135 |
136 | public IServices getService() {
137 | return this.service;
138 | }
139 | public void setService(IServices service) {
140 | this.service=service
141 | }
142 | }
143 | ```
144 | ---------------------------------
145 |
146 |
147 | * **Interface(or Method) Dependency Injection:** Provides a method that will pass the transmission of the needed object(s) to any dependent class.
148 | Dependent classes must implement the interface which have the setter method of the object(s) they need.
149 |
150 | ```java
151 | public interface IServicesDependency{
152 | void setDependecy(IServices service);
153 | }
154 | public class Controller implements IServicesDependency{
155 | private IServices service;
156 |
157 | public Controller() {}
158 |
159 | @Override
160 | public void setDependecy(IServices service) {
161 | this.service=service;
162 | }
163 | }
164 | ```
165 | ---------------------------------
166 |
167 |
168 | * **[Bonus] Field Dependency Injection:** Field Injection is a DI technique made thanks to the @Autowired annotation in Spring.
169 | In fact, Field Injection was mentioned indirectly while explaining the IoC Container.
170 | Dependent object takes the memory address of the needed object that already exists in the IoC Container and assigns the reference address to related field belong to dependent object thanks to @Autowired annotation.
171 |
172 | ```java
173 | public class Controller{
174 | @Autowired
175 | private IServices service;
176 | public Controller() {}
177 | }
178 | ```
179 | ---------------------------------
180 |
181 |
182 | ## Spring Boot
183 | The main difference between Spring Framework and Spring Boot is that Spring Framework is a library and Spring Boot is a tool.
184 | Spring Boot makes it faster and easier to develop applications with the Spring Framework.
185 | A few features of Spring Boot that make it faster and easier
186 | * Creates stand-alone applications.
187 | * SB comes with Tomcat, Jetty or Undertow embedded.
188 | * SB does not need XML configuration.
189 | * SB aims to reduce LOC (Lines of Code).
190 | * SB is easy to start.
191 | * Customization and management is simple.
192 |
193 |
194 |
195 | ### Spring Boot Layered Architecture
196 | This is used architectural structure in Spring Boot.
197 | In layered artichecture, classes are divided into certain groups/layers and each divided group/layer has its own task.
198 | The reason why the file structures are arranged in this way is that the reusability, maintainability and debugability of the projects(especially the complex ones) can be controlled and updated in a right way.
199 |
200 |
201 |
202 | The first of these layers is the **Presentation Layer**
203 | The Presentation Layer communicates with the client. The **@RestController** or **@Controller** annotations are used to indicate that the classes in the Presentation Layer belong to that layer. In this layer, requests(data) from the client are transferred to the next layer(Business Layer) via Database Transfer Objects(DTO) or data which is came from the Business Layer is returned to the client.
204 |
205 |
206 |
207 | The second of these layers is the **Business Layer**
208 | The Business Layer is the layer where the desired work is done. For example, calculating the discount of the price of the products in the cart, etc. in an e-commerce application.
209 | The **@Service** anonotation is used to indicate that the classes in the Business Layer belong to this layer.
210 | The desired solution is produced with the data transferred to it from the Presentation Layer via DTO in the Business layer. If the produced solution is needed to be returned directly to the client, it is returned to the Presentation layer with DTO in this layer. If the produced solution is needed to be saved in the database, it is transferred to the next layer (Persistence Layer) with Entity objects from this layer.
211 |
212 |
213 |
214 | The third of these layers is the **Persistence Layer**
215 | Persistence Layer communicates with the Database Layer. Hollow interfaces instead of classes are defined in this layer. Interfaces are defined with **@Repository** annotation in this layer. Spring makes the necessary implementations for the interfaces when it sees **@Repository** annotation and makes its interfaces with Repository annotation ready for use. Entity objects from the Business Layer are sent to the Database Layer or the data requested from the Database Layer are sent to the Business Layer as Entity objects in this layer.
216 | Persistence Layer and Presentation Layer cannot communicate directly with each other!
217 |
218 |
219 |
220 | **Entity Objects**
221 | Entity objects are defined with **@Entity** annotation. An Entity class corresponds to a table in database. For example, an AdminEntity class corresponds to the Admin table in the database. Fields defined with special annotations in Entity classes are created as columns in the database and the values of these fields are added/deleted or etc. to the relevant columns.
222 |
223 |
224 |
225 | ## Application Programming Interface(API)
226 | APIs allow the functions of one application to be used in another application.
227 | In this way, applications can be run that are independent of each other in an integrated way.
228 | In this respect, the APIs are like a puzzle.
229 | Different platforms can connected and meet their needs using their APIs and services.
230 | This means that APIs allows services and products to communicate with each other and leverage each other's data and functionality through a documented interface.
231 |
232 | A few advantages of APIs
233 | * Centralizing different platforms in one panel.
234 | * Scattered and large structures can be combined and managed.
235 | * APIs makes sharing and distributing content easier.
236 | * APIs enables the most used content and services to be customizable.
237 | * Contents can be automatically broadcast for each channel.
238 | * APIs makes service delivery more flexible.
239 | * Different versions of the same application can be developed on many different devices thanks to APIs.
240 |
241 |
242 |
243 | ## Representational State Transfer(REST)
244 | REST is an architecture that enables lightweight and easy Clint-Server communication with HTTP.
245 | Roy Fielding developed this architecture as a doctoral thesis in the 2000s.
246 | REST allows communication with a variable URL rather than a constant URL as in Simple Object Access Protocol (SOAP).
247 | If you want to get information from the http://theserver/example web address in SOAP, the relevant method should be run on this address.
248 | For example; GetUsers method
249 | If you want to get information in Rest, you can directly access the related method with the variable web address logic.
250 | For example; http://theserver/example/GetUser or http://theserver/example/GetUser/8.
251 |
252 |
253 |
254 | ### REST API
255 | A REST API is an API that conforms to the design principles or representative state transfer architecture style of REST.
256 | REST APIs are sometimes called RESTful APIs.
257 | REST APIs is used to get information from a web service or to provide information to a website.
258 | All communications over the REST API use HTTP request only.
259 |
260 | Working paradigm of Rest APIs A request is sent to the server by the client as HTTP POST, GET, PUT, PATCH, DELETE and etc. method were in the form of a web URL. These correspond to create, read, update and delete (or CRUD) operations respectively. After the server receives the request, it sends a like HTML, XML, Image, JSON or etc. recource to the client.
261 |
262 | **POST** is mostly used to create new record. Returns HTTP status 201 when successfully created.
263 |
264 | **GET** is used to read/get the representation of a record. It returns HTTP status 200 (OK) when secure. It usually returns a status of HTTP 404 (NOT FOUND) or HTTP 400 (BAD REQUEST) when the event of an error.
265 |
266 | **PUT** is used to update but If the record ID is chosen by the client rather than the server, it can also be used to create a record.
267 | On a successful update, it returns an HTTP status of 200 (or 204 if not returning any content in the body). PUT returns HTTP status 201 on successful a record creation If it is used to create a record.
268 |
269 | **PATCH** is used to modify. PATCH request should only contain changes to the record. It should not the entire record.
270 | This is similar to PUT but the body contains a set of instructions that explain how a record currently on the server must be modified to produce a new version.
271 | Therefore, PATCH body must not be just a modified part of the record but it must be in some kind of patch language like JSON Patch or XML Patch.
272 |
273 | **DELETE** is used by the URI to delete an identified record. It returns a 200 (OK) HTTP status on successful a record deletion.
274 |
275 |
276 |
277 |
278 | ## Challenge Project
279 |
280 | I have developed a Rest API where you can see the stock market share prices of companies which are done in the Challenge Project module. I got stock markets information from https://www.alphavantage.co/documentation/.
281 | Here is an example json object related to the data provided by this api;
282 | ```json
283 | {
284 | "Meta Data": {
285 | "1. Information": "Daily Time Series with Splits and Dividend Events",
286 | "2. Symbol": "IBM",
287 | "3. Last Refreshed": "2023-01-27",
288 | "4. Output Size": "Compact",
289 | "5. Time Zone": "US/Eastern"
290 | },
291 | "Time Series (Daily)": {
292 | "2023-01-27": {
293 | "1. open": "134.44",
294 | "2. high": "135.488",
295 | "3. low": "133.7701",
296 | "4. close": "134.39",
297 | "5. adjusted close": "134.39",
298 | "6. volume": "8143146",
299 | "7. dividend amount": "0.0000",
300 | "8. split coefficient": "1.0"
301 | },
302 | ...
303 | }
304 | }
305 | ```
306 |
307 | First of all, I populated my own database using Alphavantage's API. If there is no data in the database, all the information is filling the database into the database while the loader object is being created. If our database is not empty then the loader object adds that data to our database if a new data was added to the Alphavantage API the previous day. The h2 database is currently used as the database.
308 | If you want to use the Postgresql as the database then you can remove the comment lines in the **application.properties** section and add the h2 database settings to the comment line.
309 | If the postgresql database is not installed on your computer, you can go to the **'src/main/recources'** directory and run the
310 | ```bash
311 | docker-compose -f docker-compose.yml up -d
312 | ```
313 | command to pull the postgresql image to your own computer.
314 |
315 |
316 | You can see stock prices by making date and company code based requests to this Rest API with Postman. You can go to the **'src/main/recources/PostmanCollection'** directory and import the json file there to your Postman and use the collections I have already prepared.
317 | An image from the Postman's Collections;
318 | 
319 |
320 |
321 | An output example from the Challenge Project;
322 | ```json
323 | {
324 | "date": "2023-01-27",
325 | "symbol": "IBM",
326 | "1. open": "134.44",
327 | "2. high": "135.488",
328 | "3. low": "133.7701",
329 | "4. close": "134.39",
330 | "5. adjusted close": "134.39",
331 | "6. volume": "8143146"
332 | }
333 | ```
334 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | gov.tubitak
8 | tubitak-tasks
9 | pom
10 | 1.0-SNAPSHOT
11 |
12 | task3-h2
13 | ChallengeProject
14 |
15 |
16 |
17 | 18
18 | 18
19 | UTF-8
20 |
21 |
22 |
--------------------------------------------------------------------------------
/task3-h2/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 | task3-h2
7 | 1.0-SNAPSHOT
8 |
9 |
10 | org.springframework.boot
11 | spring-boot-starter-parent
12 | 3.0.0-M5
13 |
14 |
15 | Demo project for Spring Boot
16 |
17 | 17
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-web
23 |
24 |
25 |
26 | com.h2database
27 | h2
28 | runtime
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-data-jpa
33 |
34 |
35 | org.projectlombok
36 | lombok
37 | true
38 |
39 |
40 |
41 |
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-maven-plugin
46 |
47 |
48 |
49 | org.projectlombok
50 | lombok
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | spring-milestones
60 | Spring Milestones
61 | https://repo.spring.io/milestone
62 |
63 | false
64 |
65 |
66 |
67 |
68 |
69 | spring-milestones
70 | Spring Milestones
71 | https://repo.spring.io/milestone
72 |
73 | false
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/task3-h2/src/main/java/gov/tubitak/App.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
6 |
7 | @SpringBootApplication
8 | @EnableJpaRepositories
9 | public class App {
10 | public static void main(String[] args) {
11 | SpringApplication.run(App.class, args);
12 | }
13 | }
--------------------------------------------------------------------------------
/task3-h2/src/main/java/gov/tubitak/controllers/PersonController.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.controllers;
2 |
3 | import gov.tubitak.dto.PersonDto;
4 | import gov.tubitak.services.PersonService;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.*;
8 |
9 | import java.util.List;
10 |
11 | @RestController
12 | @RequestMapping("/users")
13 | @RequiredArgsConstructor
14 | public class PersonController {
15 | private final PersonService personService;
16 | @PostMapping
17 | public ResponseEntity add(@RequestBody PersonDto personDto){
18 | return ResponseEntity.ok(personService.save(personDto));
19 | }
20 | @GetMapping
21 | public ResponseEntity> getAll(){
22 | return ResponseEntity.ok(personService.getAll());
23 | }
24 | @GetMapping("/{id}")
25 | public ResponseEntity getById(@PathVariable(value = "id") Long id){
26 | return ResponseEntity.ok(personService.getById(id));
27 | }
28 | @DeleteMapping("/{id}")
29 | public ResponseEntity deleteById(@PathVariable(value = "id") Long id){
30 | personService.deleteById(id);
31 | return ResponseEntity.ok().build();
32 | }
33 | @PutMapping("/{id}")
34 | public ResponseEntity update(@PathVariable(value = "id") Long id, @RequestBody PersonDto updatedPerson){
35 | return ResponseEntity.ok(personService.update(id, updatedPerson));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/task3-h2/src/main/java/gov/tubitak/dto/PersonDto.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.dto;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 |
7 | @Data
8 | public class PersonDto {
9 | private Long personId;
10 | private String firstName;
11 | private String lastName;
12 | private List addresses;
13 | }
14 |
--------------------------------------------------------------------------------
/task3-h2/src/main/java/gov/tubitak/entity/Address.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.entity;
2 |
3 | import jakarta.persistence.*;
4 | import lombok.*;
5 |
6 | @Entity
7 | @Table(name = "person_address")
8 | @AllArgsConstructor
9 | @NoArgsConstructor
10 | @Getter
11 | @Setter
12 | @EqualsAndHashCode(of = {"addressId"})
13 | @ToString
14 | public class Address {
15 |
16 | @Id
17 | @SequenceGenerator(name = "seq_person_address", allocationSize = 1)
18 | @GeneratedValue(generator = "seq_person_address", strategy = GenerationType.SEQUENCE)
19 | private Long addressId;
20 |
21 | @Column(length = 300, name = "address")
22 | private String address;
23 |
24 | @Enumerated
25 | private AddressType addressType;
26 |
27 | @Column(name = "active")
28 | private Boolean isActive;
29 |
30 | @ManyToOne(fetch = FetchType.EAGER)
31 | @JoinColumn(name="person_address_id")
32 | private Person person;
33 |
34 | public enum AddressType{
35 | Home,
36 | WorkPlace,
37 | Other
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/task3-h2/src/main/java/gov/tubitak/entity/Person.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.entity;
2 |
3 | import jakarta.persistence.*;
4 | import lombok.*;
5 |
6 | import java.util.List;
7 |
8 | @Entity
9 | @Table(name = "person")
10 | @AllArgsConstructor
11 | @NoArgsConstructor
12 | @Getter
13 | @Setter
14 | @EqualsAndHashCode(of = {"personId"})
15 | @ToString
16 | public class Person {
17 | @Id
18 | @SequenceGenerator(name = "seq_person", allocationSize = 1)
19 | @GeneratedValue(generator = "seq_person", strategy = GenerationType.SEQUENCE)
20 | private Long personId;
21 |
22 | @Column(length = 20, name = "first_name")
23 | private String firstName;
24 |
25 | @Column(length = 20, name = "last_name")
26 | private String lastName;
27 |
28 | @OneToMany
29 | @JoinColumn(name = "person_address_id")
30 | private List addresses;
31 | }
32 |
--------------------------------------------------------------------------------
/task3-h2/src/main/java/gov/tubitak/repositories/AddressRepository.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.repositories;
2 |
3 | import gov.tubitak.entity.Address;
4 | import org.springframework.data.repository.CrudRepository;
5 |
6 | public interface AddressRepository extends CrudRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/task3-h2/src/main/java/gov/tubitak/repositories/PersonRepository.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.repositories;
2 |
3 | import gov.tubitak.entity.Person;
4 | import org.springframework.data.repository.CrudRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | @Repository
8 | public interface PersonRepository extends CrudRepository {
9 | }
10 |
--------------------------------------------------------------------------------
/task3-h2/src/main/java/gov/tubitak/services/Impl/PersonServiceImpl.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.services.Impl;
2 |
3 | import gov.tubitak.dto.PersonDto;
4 | import gov.tubitak.entity.Address;
5 | import gov.tubitak.entity.Person;
6 | import gov.tubitak.repositories.AddressRepository;
7 | import gov.tubitak.repositories.PersonRepository;
8 | import gov.tubitak.services.PersonService;
9 | import jakarta.persistence.EntityNotFoundException;
10 | import lombok.RequiredArgsConstructor;
11 | import org.springframework.data.domain.Page;
12 | import org.springframework.data.domain.Pageable;
13 | import org.springframework.stereotype.Service;
14 | import org.springframework.transaction.annotation.Transactional;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 | import java.util.stream.Collectors;
19 |
20 | @Service
21 | @RequiredArgsConstructor
22 | public class PersonServiceImpl implements PersonService {
23 | private final PersonRepository personRepository;
24 | private final AddressRepository addressRepository;
25 | private Person checkIdInRepository(Long id){
26 | return personRepository.findById(id)
27 | .orElseThrow(() -> new EntityNotFoundException("! The is not a user with "+id+" id number"));
28 | }
29 | private PersonDto addToRepository(Person person, PersonDto personDto){
30 | person.setFirstName(personDto.getFirstName());
31 | person.setLastName(personDto.getLastName());
32 | final Person personDb = personRepository.save(person);
33 |
34 | List listOfAddress = new ArrayList<>();
35 | personDto.getAddresses().forEach(item -> {
36 | Address address = new Address();
37 | address.setAddress(item);
38 | address.setAddressType(Address.AddressType.Other);
39 | address.setIsActive(true);
40 | address.setPerson(personDb);
41 | listOfAddress.add(address);
42 | });
43 | addressRepository.saveAll(listOfAddress);
44 | personDto.setPersonId(personDb.getPersonId());
45 | return personDto;
46 | }
47 |
48 | @Override
49 | @Transactional
50 | public PersonDto save(PersonDto personDto) {
51 | Person person = new Person();
52 | return addToRepository(person, personDto);
53 | }
54 | @Override
55 | public void deleteById(Long id) {
56 | checkIdInRepository(id);
57 | personRepository.deleteById(id);
58 | }
59 | @Override
60 | @Transactional
61 | public PersonDto update(Long id, PersonDto updatedPerson) {
62 | Person p = checkIdInRepository(id);
63 | return addToRepository(p, updatedPerson);
64 | }
65 |
66 | @Override
67 | public PersonDto getById(Long id) {
68 | Person person = checkIdInRepository(id);
69 | PersonDto personDto = new PersonDto();
70 | personDto.setPersonId(person.getPersonId());
71 | personDto.setFirstName(person.getFirstName());
72 | personDto.setLastName(person.getLastName());
73 | personDto.setAddresses(person.getAddresses().stream().map(Address::getAddress)
74 | .collect(Collectors.toList()));
75 | return personDto;
76 | }
77 |
78 | @Override
79 | public List getAll() {
80 | List peopleDto = new ArrayList<>();
81 | for (Person person : personRepository.findAll()){
82 | PersonDto personDto = new PersonDto();
83 | personDto.setPersonId(person.getPersonId());
84 | personDto.setFirstName(person.getFirstName());
85 | personDto.setLastName(person.getLastName());
86 | personDto.setAddresses(person.getAddresses().stream().map(Address::getAddress)
87 | .collect(Collectors.toList()));
88 | peopleDto.add(personDto);
89 | }
90 | return peopleDto;
91 | }
92 | @Override
93 | public Page getAll(Pageable pageable) {
94 | return null;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/task3-h2/src/main/java/gov/tubitak/services/PersonService.java:
--------------------------------------------------------------------------------
1 | package gov.tubitak.services;
2 |
3 | import gov.tubitak.dto.PersonDto;
4 | import org.springframework.data.domain.Page;
5 | import org.springframework.data.domain.Pageable;
6 | import java.util.List;
7 |
8 | public interface PersonService {
9 | PersonDto save(PersonDto personDto);
10 | void deleteById(Long id);
11 |
12 | PersonDto update(Long id, PersonDto updatedPerson);
13 | List getAll();
14 | Page getAll(Pageable pageable);
15 |
16 | PersonDto getById(Long id);
17 | }
18 |
--------------------------------------------------------------------------------
/task3-h2/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=8080
2 | spring.h2.console.enabled=true
3 | spring.datasource.url=jdbc:h2:mem:memDb
4 | spring.datasource.driverClassName=org.h2.Driver
5 | spring.datasource.username=sa
6 | spring.datasource.password=
--------------------------------------------------------------------------------