├── .gitattributes ├── .gitignore ├── config.properties ├── pom.xml └── src ├── main ├── java │ └── victor │ │ └── training │ │ └── exceptions │ │ ├── Biz.java │ │ ├── Config.java │ │ ├── GlobalExceptionHandler.java │ │ ├── InProduction.java │ │ ├── MyException.java │ │ ├── SpringBoot.java │ │ ├── Streams.java │ │ └── model │ │ ├── Customer.java │ │ ├── MemberCard.java │ │ └── Order.java └── resources │ ├── application.properties │ ├── messages.properties │ └── messages_RO.properties └── test └── java └── victor └── training └── exceptions └── BizTest.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .project 3 | .classpath 4 | .settings/ 5 | bin/ 6 | 7 | # IntelliJ 8 | .idea 9 | *.ipr 10 | *.iml 11 | *.iws 12 | 13 | # NetBeans 14 | nb-configuration.xml 15 | 16 | # Visual Studio Code 17 | .vscode 18 | .factorypath 19 | 20 | # OSX 21 | .DS_Store 22 | 23 | # Vim 24 | *.swp 25 | *.swo 26 | 27 | # patch 28 | *.orig 29 | *.rej 30 | 31 | # Maven 32 | target/ 33 | pom.xml.tag 34 | pom.xml.releaseBackup 35 | pom.xml.versionsBackup 36 | release.properties 37 | /app.log 38 | /app.log.*.gz 39 | -------------------------------------------------------------------------------- /config.properties: -------------------------------------------------------------------------------- 1 | last.promo.date=xxx2021-01-30 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | victor.training 8 | exceptions-guide 9 | 1.0.0 10 | 11 | 12 | 15 13 | 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-web 19 | 20 | 21 | org.projectlombok 22 | lombok 23 | 24 | 1.18.16 25 | 26 | 27 | commons-io 28 | commons-io 29 | 2.0 30 | 31 | 32 | junit 33 | junit 34 | 4.10 35 | 36 | 37 | org.jooq 38 | jool 39 | 0.9.14 40 | 41 | 42 | io.vavr 43 | vavr 44 | 0.10.3 45 | 46 | 47 | commons-lang 48 | commons-lang 49 | 2.6 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-devtools 54 | runtime 55 | true 56 | 57 | 58 | 59 | 60 | 61 | 62 | spring-boot-dependencies 63 | org.springframework.boot 64 | import 65 | pom 66 | 2.3.4.RELEASE 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-maven-plugin 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/Biz.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions; 2 | 3 | import org.apache.commons.lang.time.DateUtils; 4 | import org.springframework.stereotype.Service; 5 | import victor.training.exceptions.model.Customer; 6 | import victor.training.exceptions.model.Order; 7 | 8 | import java.text.ParseException; 9 | import java.util.Date; 10 | 11 | /** 12 | * @author Bill G. 13 | */ 14 | @Service 15 | public class Biz { 16 | 17 | public void applyDiscount(Order order, Customer customer) { 18 | if (order.getOfferDate().before(Config.getLastPromoDate()) 19 | && customer.getMemberCard().isPresent()) { 20 | System.out.println("APPLYING DISCOUNT"); 21 | order.setPrice(order.getPrice() * (100 - 2 * customer.getMemberCard().get().getFidelityDiscount()) / 100); 22 | } else { 23 | System.out.println("NO DISCOUNT"); 24 | } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/Config.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions; 2 | 3 | import lombok.SneakyThrows; 4 | import org.springframework.stereotype.Service; 5 | import victor.training.exceptions.MyException.ErrorCode; 6 | 7 | import java.io.*; 8 | import java.text.ParseException; 9 | import java.text.SimpleDateFormat; 10 | import java.util.Date; 11 | import java.util.Properties; 12 | 13 | /** 14 | * @author Alan T. 15 | */ 16 | public class Config { 17 | 18 | 19 | @SneakyThrows 20 | public static Date getLastPromoDate() { 21 | // try { 22 | long userInputUsefulToReportBackToHim = 1; 23 | 24 | // try { 25 | Properties properties = new Properties(); 26 | try (Reader reader = new FileReader("config.properties")) { 27 | properties.load(reader); 28 | } 29 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 30 | return format.parse(properties.getProperty("last.promo.date")); 31 | // } catch (IOException | ParseException e) { 32 | // throw new RuntimeException(e); 33 | // } 34 | // } catch (Throwable var8) { 35 | // throw var8; 36 | // } 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.context.MessageSource; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.bind.annotation.ResponseStatus; 8 | import org.springframework.web.bind.annotation.RestControllerAdvice; 9 | import victor.training.exceptions.MyException.ErrorCode; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | 13 | @Slf4j 14 | @RequiredArgsConstructor 15 | @RestControllerAdvice 16 | public class GlobalExceptionHandler { 17 | 18 | @ExceptionHandler(Exception.class) 19 | @ResponseStatus 20 | public String handleRuntime(Exception e, HttpServletRequest request) { 21 | String userMessage = messageSource.getMessage(ErrorCode.GENERAL.name(), null, request.getLocale()); 22 | log.error("Unexpected " + userMessage, e); 23 | return userMessage; 24 | } 25 | private final MessageSource messageSource; 26 | 27 | @ExceptionHandler(MyException.class) 28 | @ResponseStatus 29 | public String handleMyException(MyException e, HttpServletRequest request) { 30 | String userMessage = messageSource.getMessage(e.getCode().name(), e.getParams(), request.getLocale()); 31 | log.error("Unexpected " + userMessage, e); 32 | return userMessage; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/InProduction.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import victor.training.exceptions.model.Customer; 5 | import victor.training.exceptions.model.MemberCard; 6 | import victor.training.exceptions.model.Order; 7 | 8 | import java.util.Date; 9 | 10 | @Slf4j 11 | public class InProduction { 12 | 13 | private static Biz biz = new Biz(); 14 | 15 | public static void main(String[] args) { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/MyException.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions; 2 | 3 | 4 | class MyRecoverableException extends MyException { 5 | 6 | public MyRecoverableException(Throwable cause, Object... params) { 7 | super(ErrorCode.RECOVERABLE_ERR1, cause, params); 8 | } 9 | } 10 | 11 | public class MyException extends RuntimeException { 12 | public enum ErrorCode { 13 | GENERAL, 14 | RECOVERABLE_ERR1, 15 | BAD_CONFIG; 16 | 17 | } 18 | private final ErrorCode code; 19 | 20 | private final Object[] params; 21 | public MyException(ErrorCode code, Throwable cause, Object... params) { 22 | super(cause); 23 | this.code = code; 24 | this.params = params; 25 | } 26 | 27 | public MyException(Exception cause) { 28 | this(ErrorCode.GENERAL, cause); 29 | } 30 | 31 | public Object[] getParams() { 32 | return params; 33 | } 34 | 35 | public ErrorCode getCode() { 36 | return code; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/SpringBoot.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import victor.training.exceptions.model.Customer; 10 | import victor.training.exceptions.model.MemberCard; 11 | import victor.training.exceptions.model.Order; 12 | 13 | import java.util.Date; 14 | 15 | 16 | @SpringBootApplication 17 | @Slf4j 18 | @RequiredArgsConstructor 19 | @RestController 20 | public class SpringBoot { 21 | public static void main(String[] args) { 22 | SpringApplication.run(SpringBoot.class, args); 23 | } 24 | private final Biz biz; 25 | 26 | @GetMapping 27 | public void exceptional() { 28 | Order order = new Order(null).setPrice(1000); 29 | 30 | biz.applyDiscount(order, new Customer().setMemberCard(new MemberCard())); 31 | 32 | System.out.println("Final Price " + order.getPrice()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/Streams.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions; 2 | 3 | import io.vavr.control.Try; 4 | import org.jooq.lambda.Unchecked; 5 | 6 | import java.text.SimpleDateFormat; 7 | import java.util.Date; 8 | import java.util.List; 9 | import java.util.function.Function; 10 | 11 | import static java.util.Arrays.asList; 12 | import static java.util.stream.Collectors.toList; 13 | 14 | public class Streams { 15 | 16 | public static void main(String[] args) { 17 | List dateList = asList("2020-10-11", "2020-nov-12", "2020-xxx12-01"); 18 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 19 | 20 | // TODO parse and print all dates 21 | 22 | // List dates = dateList.stream().map(Unchecked.function(format::parse)).collect(toList()); 23 | 24 | 25 | List> tries = dateList.stream().map(s -> Try.of(() -> format.parse(s))).collect(toList()); 26 | 27 | if (tries.stream().mapToInt(t->t.isSuccess()?1:0).average().getAsDouble() > .5) { 28 | List dates1 = tries.stream().filter(Try::isSuccess).map(Try::get).collect(toList()); 29 | System.out.println(dates1); 30 | } 31 | 32 | 33 | } 34 | 35 | // private static Function wrapEx(ThrowingFunction f) { 36 | // return t -> { 37 | // try { 38 | // return f.apply(t); 39 | // } catch (Throwable throwable) { 40 | // throw new RuntimeException(throwable); 41 | // } 42 | // }; 43 | // } 44 | // 45 | // interface ThrowingFunction { 46 | // R apply(T t) throws Throwable; 47 | // } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/model/Customer.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions.model; 2 | 3 | import java.util.Optional; 4 | 5 | import static java.util.Optional.ofNullable; 6 | 7 | public class Customer { 8 | private String name; 9 | private MemberCard memberCard; 10 | 11 | public Optional getMemberCard() { 12 | return ofNullable(memberCard); 13 | } 14 | 15 | public Customer setMemberCard(MemberCard memberCard) { 16 | this.memberCard = memberCard; 17 | return this; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/model/MemberCard.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions.model; 2 | 3 | public class MemberCard { 4 | private int fidelityDiscount = 1; 5 | 6 | public int getFidelityDiscount() { 7 | return fidelityDiscount; 8 | } 9 | 10 | public MemberCard setFidelityDiscount(int fidelityDiscount) { 11 | this.fidelityDiscount = fidelityDiscount; 12 | return this; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/victor/training/exceptions/model/Order.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions.model; 2 | 3 | import java.util.Date; 4 | import java.util.Objects; 5 | 6 | import static java.util.Objects.requireNonNull; 7 | 8 | public class Order { 9 | private int price; 10 | private Date offerDate; 11 | 12 | public Order(Date offerDate) { 13 | this.offerDate = requireNonNull(offerDate); 14 | } 15 | 16 | public int getPrice() { 17 | return price; 18 | } 19 | 20 | public Order setPrice(int price) { 21 | this.price = price; 22 | return this; 23 | } 24 | 25 | public Date getOfferDate() { 26 | return offerDate; 27 | } 28 | 29 | public Order setOfferDate(Date offerDate) { 30 | this.offerDate = requireNonNull(offerDate); 31 | return this; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.file.name=app.log -------------------------------------------------------------------------------- /src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | GENERAL=Internal Error. Please check the logs. 2 | BAD_CONFIG=Bad {0} app config -------------------------------------------------------------------------------- /src/main/resources/messages_RO.properties: -------------------------------------------------------------------------------- 1 | GENERAL=E Romania. Mai crapa. Vezi logu. 2 | BAD_CONFIG=Varza configuratie -------------------------------------------------------------------------------- /src/test/java/victor/training/exceptions/BizTest.java: -------------------------------------------------------------------------------- 1 | package victor.training.exceptions; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import victor.training.exceptions.model.Customer; 6 | import victor.training.exceptions.model.MemberCard; 7 | import victor.training.exceptions.model.Order; 8 | 9 | import java.util.Date; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | public class BizTest { 14 | @Test 15 | public void test() { 16 | System.setProperty("last.promo.date", "2021-02-30"); 17 | Biz biz = new Biz(); 18 | 19 | Customer customer = new Customer() 20 | .setMemberCard(new MemberCard() 21 | .setFidelityDiscount(2)); 22 | Order order = new Order(new Date()) 23 | .setPrice(1000); 24 | 25 | biz.applyDiscount(order, customer); 26 | System.out.println("Final Price in tests: " + order.getPrice()); 27 | assertEquals(960, order.getPrice()); 28 | } 29 | } 30 | --------------------------------------------------------------------------------