├── .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 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 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 | ![UML](https://github.com/KeremTAN/Spring_JAVA/blob/main/ChallengeProject/src/main/resources/PostmanCollections/collections.png) 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= --------------------------------------------------------------------------------