From 33b60605d778d35ae48d0a177be3862e5d377393 Mon Sep 17 00:00:00 2001 From: Matt Zhang Date: Thu, 7 Mar 2019 23:44:32 +1100 Subject: [PATCH 01/31] BAEL-2569 : EnvironmentPostProcessor in Spring Boot --- .../PriceCalculationApplication.java | 59 +++++++++++++++ ...ceCalculationEnvironmentPostProcessor.java | 71 +++++++++++++++++++ .../PriceCalculationAutoConfig.java | 32 +++++++++ .../calculator/GrossPriceCalculator.java | 23 ++++++ .../calculator/NetPriceCalculator.java | 17 +++++ .../calculator/PriceCalculator.java | 5 ++ .../service/PriceCalculationService.java | 17 +++++ .../main/resources/META-INF/spring.factories | 8 ++- 8 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java create mode 100644 spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java create mode 100644 spring-boot/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java create mode 100644 spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java create mode 100644 spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java create mode 100644 spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java create mode 100644 spring-boot/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java new file mode 100644 index 0000000000..01be08d6ae --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java @@ -0,0 +1,59 @@ +package com.baeldung.environmentpostprocessor; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import com.baeldung.environmentpostprocessor.service.PriceCalculationService; + +@SpringBootApplication +public class PriceCalculationApplication implements CommandLineRunner { + + @Autowired + PriceCalculationService priceCalculationService; + + private static final Logger logger = LoggerFactory.getLogger(PriceCalculationApplication.class); + + public static void main(String[] args) { + SpringApplication.run(PriceCalculationApplication.class, args); + } + + @Override + public void run(String... args) throws Exception { + + List params = Arrays.stream(args) + .collect(Collectors.toList()); + if (verifyArguments(params)) { + double singlePrice = Double.valueOf(params.get(0)); + int quantity = Integer.valueOf(params.get(1)); + priceCalculationService.productTotalPrice(singlePrice, quantity); + } else { + logger.error("Invalid arguments " + params.toString()); + } + + } + + private boolean verifyArguments(List args) { + boolean successful = true; + if (args.size() != 2) { + successful = false; + return successful; + } + try { + double singlePrice = Double.valueOf(args.get(0)); + int quantity = Integer.valueOf(args.get(1)); + } catch (NumberFormatException e) { + successful = false; + } + return successful; + + } + +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java new file mode 100644 index 0000000000..1b3099453e --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java @@ -0,0 +1,71 @@ +package com.baeldung.environmentpostprocessor; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.StandardEnvironment; + +public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { + + private static final Logger logger = LoggerFactory.getLogger(PriceCalculationEnvironmentPostProcessor.class); + + public static final int DEFAULT_ORDER = Ordered.LOWEST_PRECEDENCE; + private int order = DEFAULT_ORDER; + private static final String PROPERTY_PREFIX = "com.baeldung.environmentpostprocessor."; + private static final String OS_ENV_PROPERTY_CALCUATION_MODE = "calculation_mode"; + private static final String OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE = "gross_calculation_tax_rate"; + private static final String OS_ENV_PROPERTY_CALCUATION_MODE_DEFAULT_VALUE = "NET"; + private static final double OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE = 0; + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + + PropertySource systemEnvironmentPropertySource = environment.getPropertySources() + .get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); + + Map priceCalculationConfiguration = new LinkedHashMap<>(); + if (isActive(systemEnvironmentPropertySource)) { + priceCalculationConfiguration.put(key(OS_ENV_PROPERTY_CALCUATION_MODE), systemEnvironmentPropertySource.getProperty(OS_ENV_PROPERTY_CALCUATION_MODE)); + priceCalculationConfiguration.put(key(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE), systemEnvironmentPropertySource.getProperty(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE)); + } else { + logger.warn("System environment variables [calculation_mode,gross_calculation_tax_rate] not detected, fallback to default value [calcuation_mode={},gross_calcuation_tax_rate={}]", OS_ENV_PROPERTY_CALCUATION_MODE_DEFAULT_VALUE, + OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + priceCalculationConfiguration.put(key(OS_ENV_PROPERTY_CALCUATION_MODE), OS_ENV_PROPERTY_CALCUATION_MODE_DEFAULT_VALUE); + priceCalculationConfiguration.put(key(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE), OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + } + + PropertySource priceCalcuationPropertySource = new MapPropertySource("priceCalcuationPS", priceCalculationConfiguration); + environment.getPropertySources() + .addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, priceCalcuationPropertySource); + + } + + private String key(String key) { + return PROPERTY_PREFIX + key.replaceAll("\\_", "."); + } + + private boolean isActive(PropertySource systemEnvpropertySource) { + if (systemEnvpropertySource.containsProperty(OS_ENV_PROPERTY_CALCUATION_MODE) && systemEnvpropertySource.containsProperty(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE)) { + return true; + } else + return false; + } + + public void setOrder(int order) { + this.order = order; + } + + @Override + public int getOrder() { + return order; + } + +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java new file mode 100644 index 0000000000..c884f043a0 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java @@ -0,0 +1,32 @@ +package com.baeldung.environmentpostprocessor.autoconfig; + +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; + +import com.baeldung.environmentpostprocessor.calculator.GrossPriceCalculator; +import com.baeldung.environmentpostprocessor.calculator.NetPriceCalculator; +import com.baeldung.environmentpostprocessor.calculator.PriceCalculator; + +@Configuration +@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) +public class PriceCalculationAutoConfig { + + @Bean + @ConditionalOnProperty(name = "com.baeldung.environmentpostprocessor.calculation.mode", havingValue = "NET") + @ConditionalOnMissingBean + public PriceCalculator getNetPriceCalculator() { + return new NetPriceCalculator(); + } + + @Bean + @ConditionalOnProperty(name = "com.baeldung.environmentpostprocessor.calculation.mode", havingValue = "GROSS") + @ConditionalOnMissingBean + public PriceCalculator getGrossPriceCalculator() { + return new GrossPriceCalculator(); + } + +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java new file mode 100644 index 0000000000..f8f797bd66 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java @@ -0,0 +1,23 @@ +package com.baeldung.environmentpostprocessor.calculator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; + +public class GrossPriceCalculator implements PriceCalculator { + + private static final Logger logger = LoggerFactory.getLogger(GrossPriceCalculator.class); + + @Value("${com.baeldung.environmentpostprocessor.gross.calculation.tax.rate}") + double taxRate; + + @Override + public double calculate(double singlePrice, int quantity) { + logger.info("Gross based price calculation with input parameters [singlePrice = {},quantity= {} ], {} percent tax applied.", singlePrice, quantity, taxRate * 100); + double netPrice = singlePrice * quantity; + double result = Math.round(netPrice * (1 + taxRate)); + logger.info("Calcuation result is {}", result); + return result; + } + +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java new file mode 100644 index 0000000000..263dff6247 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java @@ -0,0 +1,17 @@ +package com.baeldung.environmentpostprocessor.calculator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetPriceCalculator implements PriceCalculator { + + private static final Logger logger = LoggerFactory.getLogger(GrossPriceCalculator.class); + + @Override + public double calculate(double singlePrice, int quantity) { + logger.info("Net based price calculation with input parameters [singlePrice = {},quantity= {} ], NO tax applied.", singlePrice, quantity); + double result = Math.round(singlePrice * quantity); + logger.info("Calcuation result is {}", result); + return result; + } +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java new file mode 100644 index 0000000000..9d7bef93a4 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java @@ -0,0 +1,5 @@ +package com.baeldung.environmentpostprocessor.calculator; + +public interface PriceCalculator { + public double calculate(double singlePrice, int quantity); +} diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java new file mode 100644 index 0000000000..0e4eb39506 --- /dev/null +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java @@ -0,0 +1,17 @@ +package com.baeldung.environmentpostprocessor.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baeldung.environmentpostprocessor.calculator.PriceCalculator; + +@Service +public class PriceCalculationService { + + @Autowired + PriceCalculator priceCalculator; + + public double productTotalPrice(double singlePrice, int quantity) { + return priceCalculator.calculate(singlePrice, quantity); + } +} diff --git a/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot/src/main/resources/META-INF/spring.factories index e3d3aa4c8e..d8a01bbf82 100644 --- a/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot/src/main/resources/META-INF/spring.factories @@ -1 +1,7 @@ -org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer \ No newline at end of file +org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.baeldung.environmentpostprocessor.autoconfig.PriceCalculationAutoConfig + +org.springframework.boot.env.EnvironmentPostProcessor=\ +com.baeldung.environmentpostprocessor.PriceCalculationEnvironmentPostProcessor + From bbb98f7a91a91336fb47ae71651400b2b8516bab Mon Sep 17 00:00:00 2001 From: Matt Zhang Date: Mon, 11 Mar 2019 23:49:35 +1100 Subject: [PATCH 02/31] BAEL-2569 add test --- ...ationEnvironmentPostProcessorLiveTest.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java diff --git a/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java b/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java new file mode 100644 index 0000000000..352e7941fb --- /dev/null +++ b/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java @@ -0,0 +1,29 @@ +package com.baeldung.environmentpostprocessor; + +import static org.junit.Assert.assertTrue; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.baeldung.environmentpostprocessor.service.PriceCalculationService; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PriceCalculationApplication.class) +public class PriceCalculationEnvironmentPostProcessorLiveTest { + + @Autowired + PriceCalculationService pcService; + + + @Test + public void WhenSetGrossEnvironmentVariable_ThenTaxApplied() { + double total = pcService.productTotalPrice(100, 4); + + Assert.assertEquals(400.0,total); + } + +} From a0227300bf92b3609a554916c8f70aa710d09900 Mon Sep 17 00:00:00 2001 From: "Matt Zhang (EXT)" Date: Wed, 13 Mar 2019 11:56:26 +1100 Subject: [PATCH 03/31] BAEL-2569 update test --- ...CalculationEnvironmentPostProcessorLiveTest.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java b/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java index 352e7941fb..54af217346 100644 --- a/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java +++ b/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java @@ -1,8 +1,7 @@ package com.baeldung.environmentpostprocessor; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -14,16 +13,14 @@ import com.baeldung.environmentpostprocessor.service.PriceCalculationService; @RunWith(SpringRunner.class) @SpringBootTest(classes = PriceCalculationApplication.class) public class PriceCalculationEnvironmentPostProcessorLiveTest { - + @Autowired PriceCalculationService pcService; - - + @Test - public void WhenSetGrossEnvironmentVariable_ThenTaxApplied() { + public void whenSetNetEnvironmentVariablebyDefault_thenNoTaxApplied() { double total = pcService.productTotalPrice(100, 4); - - Assert.assertEquals(400.0,total); + assertEquals(400.0, total, 0); } } From 9f8058a5603ced4177f5bc42ca7b8dbd408a5953 Mon Sep 17 00:00:00 2001 From: Matt Zhang Date: Fri, 29 Mar 2019 23:46:43 +1100 Subject: [PATCH 04/31] BAEL-2569 refactoring the class PriceCalculationEnvironmentPostProcessor --- ...ceCalculationEnvironmentPostProcessor.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java index 1b3099453e..42cbd1e90f 100644 --- a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java @@ -8,17 +8,17 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; -public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { +@Order(Ordered.LOWEST_PRECEDENCE) +public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPostProcessor { private static final Logger logger = LoggerFactory.getLogger(PriceCalculationEnvironmentPostProcessor.class); - public static final int DEFAULT_ORDER = Ordered.LOWEST_PRECEDENCE; - private int order = DEFAULT_ORDER; private static final String PROPERTY_PREFIX = "com.baeldung.environmentpostprocessor."; private static final String OS_ENV_PROPERTY_CALCUATION_MODE = "calculation_mode"; private static final String OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE = "gross_calculation_tax_rate"; @@ -28,26 +28,34 @@ public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPost @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - PropertySource systemEnvironmentPropertySource = environment.getPropertySources() + PropertySource systemEnvPropertySource = environment.getPropertySources() .get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); - Map priceCalculationConfiguration = new LinkedHashMap<>(); - if (isActive(systemEnvironmentPropertySource)) { - priceCalculationConfiguration.put(key(OS_ENV_PROPERTY_CALCUATION_MODE), systemEnvironmentPropertySource.getProperty(OS_ENV_PROPERTY_CALCUATION_MODE)); - priceCalculationConfiguration.put(key(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE), systemEnvironmentPropertySource.getProperty(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE)); + Map mapPropertySource = new LinkedHashMap<>(); + if (isActive(systemEnvPropertySource)) { + populatePropertySource(systemEnvPropertySource, mapPropertySource); } else { logger.warn("System environment variables [calculation_mode,gross_calculation_tax_rate] not detected, fallback to default value [calcuation_mode={},gross_calcuation_tax_rate={}]", OS_ENV_PROPERTY_CALCUATION_MODE_DEFAULT_VALUE, OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); - priceCalculationConfiguration.put(key(OS_ENV_PROPERTY_CALCUATION_MODE), OS_ENV_PROPERTY_CALCUATION_MODE_DEFAULT_VALUE); - priceCalculationConfiguration.put(key(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE), OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + populateDefaultPropertySource(mapPropertySource); } - PropertySource priceCalcuationPropertySource = new MapPropertySource("priceCalcuationPS", priceCalculationConfiguration); + PropertySource priceCalcuationPropertySource = new MapPropertySource("priceCalcuationPS", mapPropertySource); environment.getPropertySources() .addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, priceCalcuationPropertySource); } + private void populatePropertySource(PropertySource source, Map target) { + target.put(key(OS_ENV_PROPERTY_CALCUATION_MODE), source.getProperty(OS_ENV_PROPERTY_CALCUATION_MODE)); + target.put(key(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE), source.getProperty(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE)); + } + + private void populateDefaultPropertySource(Map target) { + target.put(key(OS_ENV_PROPERTY_CALCUATION_MODE), OS_ENV_PROPERTY_CALCUATION_MODE_DEFAULT_VALUE); + target.put(key(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE), OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + } + private String key(String key) { return PROPERTY_PREFIX + key.replaceAll("\\_", "."); } @@ -59,13 +67,4 @@ public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPost return false; } - public void setOrder(int order) { - this.order = order; - } - - @Override - public int getOrder() { - return order; - } - } From 99a3aa5bab5e066bd8470ac2619160aaab19e788 Mon Sep 17 00:00:00 2001 From: Matt Zhang Date: Sun, 31 Mar 2019 22:42:32 +1100 Subject: [PATCH 05/31] BAEL-2569: changes to class PriceCalculationEnvironmentPostProcessor --- ...ceCalculationEnvironmentPostProcessor.java | 69 +++++++++++-------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java index 42cbd1e90f..ca6d6cc28f 100644 --- a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java +++ b/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java @@ -1,7 +1,12 @@ package com.baeldung.environmentpostprocessor; +import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME; + +import java.util.Arrays; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,56 +17,62 @@ import org.springframework.core.annotation.Order; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; -import org.springframework.core.env.StandardEnvironment; @Order(Ordered.LOWEST_PRECEDENCE) public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPostProcessor { private static final Logger logger = LoggerFactory.getLogger(PriceCalculationEnvironmentPostProcessor.class); - private static final String PROPERTY_PREFIX = "com.baeldung.environmentpostprocessor."; - private static final String OS_ENV_PROPERTY_CALCUATION_MODE = "calculation_mode"; - private static final String OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE = "gross_calculation_tax_rate"; - private static final String OS_ENV_PROPERTY_CALCUATION_MODE_DEFAULT_VALUE = "NET"; - private static final double OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE = 0; + private static final String PREFIX = "com.baeldung.environmentpostprocessor."; + private static final String CALCUATION_MODE = "calculation_mode"; + private static final String GROSS_CALCULATION_TAX_RATE = "gross_calculation_tax_rate"; + private static final String CALCUATION_MODE_DEFAULT_VALUE = "NET"; + private static final double GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE = 0; + + List names = Arrays.asList(CALCUATION_MODE, GROSS_CALCULATION_TAX_RATE); + + private static Map defaults = new LinkedHashMap<>(); + static { + defaults.put(CALCUATION_MODE, CALCUATION_MODE_DEFAULT_VALUE); + defaults.put(GROSS_CALCULATION_TAX_RATE, GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + } @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - PropertySource systemEnvPropertySource = environment.getPropertySources() - .get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); + PropertySource system = environment.getPropertySources() + .get(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); - Map mapPropertySource = new LinkedHashMap<>(); - if (isActive(systemEnvPropertySource)) { - populatePropertySource(systemEnvPropertySource, mapPropertySource); - } else { - logger.warn("System environment variables [calculation_mode,gross_calculation_tax_rate] not detected, fallback to default value [calcuation_mode={},gross_calcuation_tax_rate={}]", OS_ENV_PROPERTY_CALCUATION_MODE_DEFAULT_VALUE, - OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); - populateDefaultPropertySource(mapPropertySource); + Map prefixed = new LinkedHashMap<>(); + + if (!hasOurPriceProperties(system)) { + // Baeldung-internal code so this doesn't break other examples + logger.warn("System environment variables [calculation_mode,gross_calculation_tax_rate] not detected, fallback to default value [calcuation_mode={},gross_calcuation_tax_rate={}]", CALCUATION_MODE_DEFAULT_VALUE, + GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + prefixed = names.stream() + .collect(Collectors.toMap(this::rename, this::getDefaultValue)); + environment.getPropertySources() + .addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new MapPropertySource("prefixer", prefixed)); + return; } - PropertySource priceCalcuationPropertySource = new MapPropertySource("priceCalcuationPS", mapPropertySource); + prefixed = names.stream() + .collect(Collectors.toMap(this::rename, system::getProperty)); environment.getPropertySources() - .addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, priceCalcuationPropertySource); + .addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new MapPropertySource("prefixer", prefixed)); } - private void populatePropertySource(PropertySource source, Map target) { - target.put(key(OS_ENV_PROPERTY_CALCUATION_MODE), source.getProperty(OS_ENV_PROPERTY_CALCUATION_MODE)); - target.put(key(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE), source.getProperty(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE)); + private Object getDefaultValue(String key) { + return defaults.get(key); } - private void populateDefaultPropertySource(Map target) { - target.put(key(OS_ENV_PROPERTY_CALCUATION_MODE), OS_ENV_PROPERTY_CALCUATION_MODE_DEFAULT_VALUE); - target.put(key(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE), OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE); + private String rename(String key) { + return PREFIX + key.replaceAll("\\_", "."); } - private String key(String key) { - return PROPERTY_PREFIX + key.replaceAll("\\_", "."); - } - - private boolean isActive(PropertySource systemEnvpropertySource) { - if (systemEnvpropertySource.containsProperty(OS_ENV_PROPERTY_CALCUATION_MODE) && systemEnvpropertySource.containsProperty(OS_ENV_PROPERTY_GROSS_CALCULATION_TAX_RATE)) { + private boolean hasOurPriceProperties(PropertySource system) { + if (system.containsProperty(CALCUATION_MODE) && system.containsProperty(GROSS_CALCULATION_TAX_RATE)) { return true; } else return false; From f5ac80e332dca0488c81bf7ee86fce2114aaa068 Mon Sep 17 00:00:00 2001 From: Matt Zhang Date: Sun, 7 Apr 2019 22:42:15 +1000 Subject: [PATCH 06/31] BAEL-2569 move code to spring-boot-ops module --- .../PriceCalculationApplication.java | 2 +- .../PriceCalculationEnvironmentPostProcessor.java | 0 .../autoconfig/PriceCalculationAutoConfig.java | 0 .../calculator/GrossPriceCalculator.java | 0 .../calculator/NetPriceCalculator.java | 0 .../calculator/PriceCalculator.java | 0 .../service/PriceCalculationService.java | 0 .../src/main/resources/META-INF/spring.factories | 6 ++++++ .../PriceCalculationEnvironmentPostProcessorLiveTest.java | 0 spring-boot/src/main/resources/META-INF/spring.factories | 5 ----- 10 files changed, 7 insertions(+), 6 deletions(-) rename {spring-boot => spring-boot-ops}/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java (96%) rename {spring-boot => spring-boot-ops}/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java (100%) rename {spring-boot => spring-boot-ops}/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java (100%) rename {spring-boot => spring-boot-ops}/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java (100%) rename {spring-boot => spring-boot-ops}/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java (100%) rename {spring-boot => spring-boot-ops}/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java (100%) rename {spring-boot => spring-boot-ops}/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java (100%) create mode 100644 spring-boot-ops/src/main/resources/META-INF/spring.factories rename {spring-boot => spring-boot-ops}/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java (100%) diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java similarity index 96% rename from spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java rename to spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java index 01be08d6ae..ed912d8c0a 100644 --- a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java +++ b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationApplication.java @@ -35,7 +35,7 @@ public class PriceCalculationApplication implements CommandLineRunner { int quantity = Integer.valueOf(params.get(1)); priceCalculationService.productTotalPrice(singlePrice, quantity); } else { - logger.error("Invalid arguments " + params.toString()); + logger.warn("Invalid arguments " + params.toString()); } } diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java rename to spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessor.java diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java rename to spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/autoconfig/PriceCalculationAutoConfig.java diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java rename to spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/GrossPriceCalculator.java diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java rename to spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/NetPriceCalculator.java diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java rename to spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/calculator/PriceCalculator.java diff --git a/spring-boot/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java b/spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java similarity index 100% rename from spring-boot/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java rename to spring-boot-ops/src/main/java/com/baeldung/environmentpostprocessor/service/PriceCalculationService.java diff --git a/spring-boot-ops/src/main/resources/META-INF/spring.factories b/spring-boot-ops/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..c36b67f8d7 --- /dev/null +++ b/spring-boot-ops/src/main/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.baeldung.environmentpostprocessor.autoconfig.PriceCalculationAutoConfig + +org.springframework.boot.env.EnvironmentPostProcessor=\ +com.baeldung.environmentpostprocessor.PriceCalculationEnvironmentPostProcessor + diff --git a/spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java b/spring-boot-ops/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java similarity index 100% rename from spring-boot/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java rename to spring-boot-ops/src/test/java/com/baeldung/environmentpostprocessor/PriceCalculationEnvironmentPostProcessorLiveTest.java diff --git a/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot/src/main/resources/META-INF/spring.factories index d8a01bbf82..336477df96 100644 --- a/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot/src/main/resources/META-INF/spring.factories @@ -1,7 +1,2 @@ org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -com.baeldung.environmentpostprocessor.autoconfig.PriceCalculationAutoConfig - -org.springframework.boot.env.EnvironmentPostProcessor=\ -com.baeldung.environmentpostprocessor.PriceCalculationEnvironmentPostProcessor From 608db42334c844b1b503bde30d9423423ec840b2 Mon Sep 17 00:00:00 2001 From: Matt Zhang Date: Sat, 18 May 2019 19:24:25 +1000 Subject: [PATCH 07/31] BAEL-2878 Guide to Spring's ApplicationContextRunner --- .../service/CustomService.java | 10 +++ .../service/DefaultService.java | 10 +++ .../service/SimpleService.java | 7 ++ .../ConditionalOnBeanTest.java | 77 +++++++++++++++++++ .../ConditionalOnClassTest.java | 76 ++++++++++++++++++ .../ConditionalOnPropertyTest.java | 64 +++++++++++++++ .../ConditionalOnPropertyTest.properties | 1 + 7 files changed, 245 insertions(+) create mode 100644 spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/CustomService.java create mode 100644 spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/DefaultService.java create mode 100644 spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/SimpleService.java create mode 100644 spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanTest.java create mode 100644 spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassTest.java create mode 100644 spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyTest.java create mode 100644 spring-boot-autoconfiguration/src/test/resources/ConditionalOnPropertyTest.properties diff --git a/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/CustomService.java b/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/CustomService.java new file mode 100644 index 0000000000..634e49fed3 --- /dev/null +++ b/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/CustomService.java @@ -0,0 +1,10 @@ +package com.baeldung.autoconfiguration.service; + +public class CustomService implements SimpleService { + + @Override + public String serve() { + return "Custom Service"; + } + +} diff --git a/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/DefaultService.java b/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/DefaultService.java new file mode 100644 index 0000000000..ee91bcb051 --- /dev/null +++ b/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/DefaultService.java @@ -0,0 +1,10 @@ +package com.baeldung.autoconfiguration.service; + +public class DefaultService implements SimpleService { + + @Override + public String serve() { + return "Default Service"; + } + +} diff --git a/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/SimpleService.java b/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/SimpleService.java new file mode 100644 index 0000000000..b6c72d7159 --- /dev/null +++ b/spring-boot-autoconfiguration/src/main/java/com/baeldung/autoconfiguration/service/SimpleService.java @@ -0,0 +1,7 @@ +package com.baeldung.autoconfiguration.service; + +public interface SimpleService { + + public String serve(); + +} diff --git a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanTest.java b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanTest.java new file mode 100644 index 0000000000..313d1253c5 --- /dev/null +++ b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanTest.java @@ -0,0 +1,77 @@ +package com.baeldung.autoconfiguration; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +public class ConditionalOnBeanTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + @Test + public void whenDependentBeanIsPresent_thenConditionalBeanCreated() { + this.contextRunner.withUserConfiguration(basicConfiguration.class, ConditionalOnBeanConfiguration.class) + .run((context) -> { + assertThat(context).hasBean("created"); + assertThat(context).getBean("created") + .isEqualTo("This is always created"); + assertThat(context).hasBean("createOnBean"); + assertThat(context).getBean("createOnBean") + .isEqualTo("This is created when bean (name=created) is present"); + }); + } + + @Test + public void whenDependentBeanIsPresent_thenConditionalMissingBeanIgnored() { + this.contextRunner.withUserConfiguration(basicConfiguration.class, ConditionalOnMissingBeanConfiguration.class) + .run((context) -> { + assertThat(context).hasBean("created"); + assertThat(context).getBean("created") + .isEqualTo("This is always created"); + assertThat(context).doesNotHaveBean("createOnMissingBean"); + }); + } + + @Test + public void whenDependentBeanIsNotPresent_thenConditionalMissingBeanCreated() { + this.contextRunner.withUserConfiguration(ConditionalOnMissingBeanConfiguration.class) + .run((context) -> { + assertThat(context).hasBean("createOnMissingBean"); + assertThat(context).getBean("createOnMissingBean") + .isEqualTo("This is created when bean (name=created) is missing"); + assertThat(context).doesNotHaveBean("created"); + }); + } + + @Configuration + protected static class basicConfiguration { + @Bean + public String created() { + return "This is always created"; + } + } + + @Configuration + @ConditionalOnBean(name = "created") + protected static class ConditionalOnBeanConfiguration { + @Bean + public String createOnBean() { + return "This is created when bean (name=created) is present"; + } + } + + @Configuration + @ConditionalOnMissingBean(name = "created") + protected static class ConditionalOnMissingBeanConfiguration { + @Bean + public String createOnMissingBean() { + return "This is created when bean (name=created) is missing"; + } + } + +} diff --git a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassTest.java b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassTest.java new file mode 100644 index 0000000000..7f01ea85d4 --- /dev/null +++ b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassTest.java @@ -0,0 +1,76 @@ +package com.baeldung.autoconfiguration; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +public class ConditionalOnClassTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + @Test + public void whenDependentClassIsPresent_thenBeanCreated() { + this.contextRunner.withUserConfiguration(ConditionalOnClassConfiguration.class) + .run(context -> { + assertThat(context).hasBean("created"); + assertThat(context.getBean("created")).isEqualTo("This is created when ConditionalOnClassTest is present on the classpath"); + }); + } + + @Test + public void whenDependentClassIsPresent_thenBeanMissing() { + this.contextRunner.withUserConfiguration(ConditionalOnMissingClassConfiguration.class) + .run(context -> { + assertThat(context).doesNotHaveBean("missed"); + }); + } + + @Test + public void whenDependentClassIsNotPresent_thenBeanMissing() { + this.contextRunner.withUserConfiguration(ConditionalOnClassConfiguration.class) + .withClassLoader(new FilteredClassLoader(ConditionalOnClassTest.class)) + .run((context) -> { + assertThat(context).doesNotHaveBean("created"); + assertThat(context).doesNotHaveBean(ConditionalOnClassTest.class); + + }); + } + + @Test + public void whenDependentClassIsNotPresent_thenBeanCreated() { + this.contextRunner.withUserConfiguration(ConditionalOnMissingClassConfiguration.class) + .withClassLoader(new FilteredClassLoader(ConditionalOnClassTest.class)) + .run((context) -> { + assertThat(context).hasBean("missed"); + assertThat(context).getBean("missed") + .isEqualTo("This is missed when ConditionalOnClassTest is present on the classpath"); + assertThat(context).doesNotHaveBean(ConditionalOnClassTest.class); + + }); + } + + @Configuration + @ConditionalOnClass(ConditionalOnClassTest.class) + protected static class ConditionalOnClassConfiguration { + @Bean + public String created() { + return "This is created when ConditionalOnClassTest is present on the classpath"; + } + } + + @Configuration + @ConditionalOnMissingClass("com.baeldung.autoconfiguration.ConditionalOnClassTest") + protected static class ConditionalOnMissingClassConfiguration { + @Bean + public String missed() { + return "This is missed when ConditionalOnClassTest is present on the classpath"; + } + } + +} diff --git a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyTest.java b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyTest.java new file mode 100644 index 0000000000..2c09b72dda --- /dev/null +++ b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyTest.java @@ -0,0 +1,64 @@ +package com.baeldung.autoconfiguration; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.TestPropertySource; + +import com.baeldung.autoconfiguration.service.CustomService; +import com.baeldung.autoconfiguration.service.DefaultService; +import com.baeldung.autoconfiguration.service.SimpleService; + +public class ConditionalOnPropertyTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + @Test + public void whenGivenCustomPropertyValue_thenCustomServiceCreated() { + this.contextRunner.withPropertyValues("com.baeldung.service=custom") + .withUserConfiguration(SimpleServiceConfiguration.class) + .run(context -> { + assertThat(context).hasBean("customService"); + SimpleService simpleService = context.getBean(CustomService.class); + assertThat(simpleService.serve()).isEqualTo("Custom Service"); + assertThat(context).doesNotHaveBean("defaultService"); + }); + } + + @Test + public void whenGivenDefaultPropertyValue_thenDefaultServiceCreated() { + this.contextRunner.withPropertyValues("com.baeldung.service=default") + .withUserConfiguration(SimpleServiceConfiguration.class) + .run(context -> { + assertThat(context).hasBean("defaultService"); + SimpleService simpleService = context.getBean(DefaultService.class); + assertThat(simpleService.serve()).isEqualTo("Default Service"); + assertThat(context).doesNotHaveBean("customService"); + }); + } + + @Configuration + @TestPropertySource("classpath:ConditionalOnPropertyTest.properties") + protected static class SimpleServiceConfiguration { + + @Bean + @ConditionalOnProperty(name = "com.baeldung.service", havingValue = "default") + @ConditionalOnMissingBean + public DefaultService defaultService() { + return new DefaultService(); + } + + @Bean + @ConditionalOnProperty(name = "com.baeldung.service", havingValue = "custom") + @ConditionalOnMissingBean + public CustomService customService() { + return new CustomService(); + } + } + +} diff --git a/spring-boot-autoconfiguration/src/test/resources/ConditionalOnPropertyTest.properties b/spring-boot-autoconfiguration/src/test/resources/ConditionalOnPropertyTest.properties new file mode 100644 index 0000000000..b6334bc1ce --- /dev/null +++ b/spring-boot-autoconfiguration/src/test/resources/ConditionalOnPropertyTest.properties @@ -0,0 +1 @@ +com.baeldung.service=custom \ No newline at end of file From 567fe3151ce7c232314dc7b8a8dcabffdf08ad2e Mon Sep 17 00:00:00 2001 From: Chirag Dewan Date: Sat, 18 May 2019 19:20:02 +0530 Subject: [PATCH 08/31] BAEL2941: Using JUnit SpringJUnit4ClassRunner with Parametrized --- testing-modules/spring-testing/pom.xml | 12 +++ .../java/com/baeldung/config/WebConfig.java | 17 +++++ .../parameterized/EmployeeRoleController.java | 32 ++++++++ .../RoleControllerIntegrationTest.java | 49 +++++++++++++ ...ParameterizedClassRuleIntegrationTest.java | 73 +++++++++++++++++++ ...ontrollerParameterizedIntegrationTest.java | 69 ++++++++++++++++++ 6 files changed, 252 insertions(+) create mode 100644 testing-modules/spring-testing/src/main/java/com/baeldung/config/WebConfig.java create mode 100644 testing-modules/spring-testing/src/main/java/com/baeldung/controller/parameterized/EmployeeRoleController.java create mode 100644 testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerIntegrationTest.java create mode 100644 testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerParameterizedClassRuleIntegrationTest.java create mode 100644 testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerParameterizedIntegrationTest.java diff --git a/testing-modules/spring-testing/pom.xml b/testing-modules/spring-testing/pom.xml index 630aed0c81..10d34f169b 100644 --- a/testing-modules/spring-testing/pom.xml +++ b/testing-modules/spring-testing/pom.xml @@ -44,6 +44,11 @@ spring-context LATEST + + org.springframework + spring-webmvc + ${spring.version} + org.eclipse.persistence javax.persistence @@ -66,6 +71,11 @@ ${awaitility.version} test + + javax.servlet + javax.servlet-api + ${servlet.api.version} + @@ -84,6 +94,8 @@ 2.0.0.0 3.1.6 5.4.0 + 5.1.4.RELEASE + 4.0.1 \ No newline at end of file diff --git a/testing-modules/spring-testing/src/main/java/com/baeldung/config/WebConfig.java b/testing-modules/spring-testing/src/main/java/com/baeldung/config/WebConfig.java new file mode 100644 index 0000000000..eca0aed57f --- /dev/null +++ b/testing-modules/spring-testing/src/main/java/com/baeldung/config/WebConfig.java @@ -0,0 +1,17 @@ +package com.baeldung.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import javax.servlet.ServletContext; + +@EnableWebMvc +@Configuration +@ComponentScan(basePackages = {"com.baeldung.controller.parameterized"}) +public class WebConfig { + + @Autowired + private ServletContext ctx; +} diff --git a/testing-modules/spring-testing/src/main/java/com/baeldung/controller/parameterized/EmployeeRoleController.java b/testing-modules/spring-testing/src/main/java/com/baeldung/controller/parameterized/EmployeeRoleController.java new file mode 100644 index 0000000000..0f1ed9e61d --- /dev/null +++ b/testing-modules/spring-testing/src/main/java/com/baeldung/controller/parameterized/EmployeeRoleController.java @@ -0,0 +1,32 @@ +package com.baeldung.controller.parameterized; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.HashMap; +import java.util.Map; + +@Controller +public class EmployeeRoleController { + + private static Map userRoleCache = new HashMap<>(); + + static { + userRoleCache.put("John", Role.ADMIN); + userRoleCache.put("Doe", Role.EMPLOYEE); + } + + @RequestMapping(value = "/role/{name}", method = RequestMethod.GET, produces = "application/text") + @ResponseBody + public String getEmployeeRole(@PathVariable("name") String employeeName) { + + return userRoleCache.get(employeeName).toString(); + } + + private enum Role { + ADMIN, EMPLOYEE + } +} diff --git a/testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerIntegrationTest.java b/testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerIntegrationTest.java new file mode 100644 index 0000000000..c362067cc0 --- /dev/null +++ b/testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerIntegrationTest.java @@ -0,0 +1,49 @@ +package com.baeldung.controller.parameterized; + +import com.baeldung.config.WebConfig; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +@RunWith(SpringJUnit4ClassRunner.class) +@WebAppConfiguration +@ContextConfiguration(classes = WebConfig.class) +public class RoleControllerIntegrationTest { + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + private static final String CONTENT_TYPE = "application/text;charset=ISO-8859-1"; + + @Before + public void setup() throws Exception { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + @Test + public void givenEmployeeNameJohnWhenInvokeRoleThenReturnAdmin() throws Exception { + this.mockMvc.perform(MockMvcRequestBuilders.get("/role/John")).andDo(print()).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE)) + .andExpect(MockMvcResultMatchers.content().string("ADMIN")); + } + + @Test + public void givenEmployeeNameDoeWhenInvokeRoleThenReturnEmployee() throws Exception { + this.mockMvc.perform(MockMvcRequestBuilders.get("/role/Doe")).andDo(print()).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE)) + .andExpect(MockMvcResultMatchers.content().string("EMPLOYEE")); + } + +} \ No newline at end of file diff --git a/testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerParameterizedClassRuleIntegrationTest.java b/testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerParameterizedClassRuleIntegrationTest.java new file mode 100644 index 0000000000..eca294a742 --- /dev/null +++ b/testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerParameterizedClassRuleIntegrationTest.java @@ -0,0 +1,73 @@ +package com.baeldung.controller.parameterized; + +import com.baeldung.config.WebConfig; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestContextManager; +import org.springframework.test.context.junit4.rules.SpringClassRule; +import org.springframework.test.context.junit4.rules.SpringMethodRule; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.util.ArrayList; +import java.util.Collection; + +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +@RunWith(Parameterized.class) +@WebAppConfiguration +@ContextConfiguration(classes = WebConfig.class) +public class RoleControllerParameterizedClassRuleIntegrationTest { + + private static final String CONTENT_TYPE = "application/text;charset=ISO-8859-1"; + + @ClassRule + public static final SpringClassRule scr = new SpringClassRule(); + + @Rule + public final SpringMethodRule smr = new SpringMethodRule(); + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + @Parameter(value = 0) + public String name; + + @Parameter(value = 1) + public String role; + + @Parameters + public static Collection data() { + Collection params = new ArrayList(); + params.add(new Object[]{"John", "ADMIN"}); + params.add(new Object[]{"Doe", "EMPLOYEE"}); + + return params; + } + + @Before + public void setup() throws Exception { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + @Test + public void givenEmployeeNameWhenInvokeRoleThenReturnRole() throws Exception { + this.mockMvc.perform(MockMvcRequestBuilders.get("/role/" + name)).andDo(print()).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE)) + .andExpect(MockMvcResultMatchers.content().string(role)); + } + +} \ No newline at end of file diff --git a/testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerParameterizedIntegrationTest.java b/testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerParameterizedIntegrationTest.java new file mode 100644 index 0000000000..1458b24b06 --- /dev/null +++ b/testing-modules/spring-testing/src/test/java/com/baeldung/controller/parameterized/RoleControllerParameterizedIntegrationTest.java @@ -0,0 +1,69 @@ +package com.baeldung.controller.parameterized; + +import com.baeldung.config.WebConfig; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestContextManager; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.util.ArrayList; +import java.util.Collection; + +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +@RunWith(Parameterized.class) +@WebAppConfiguration +@ContextConfiguration(classes = WebConfig.class) +public class RoleControllerParameterizedIntegrationTest { + + private static final String CONTENT_TYPE = "application/text;charset=ISO-8859-1"; + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + private TestContextManager testContextManager; + + @Parameter(value = 0) + public String name; + + @Parameter(value = 1) + public String role; + + @Parameters + public static Collection data() { + Collection params = new ArrayList(); + params.add(new Object[]{"John", "ADMIN"}); + params.add(new Object[]{"Doe", "EMPLOYEE"}); + + return params; + } + + @Before + public void setup() throws Exception { + this.testContextManager = new TestContextManager(getClass()); + this.testContextManager.prepareTestInstance(this); + + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + @Test + public void givenEmployeeNameWhenInvokeRoleThenReturnRole() throws Exception { + this.mockMvc.perform(MockMvcRequestBuilders.get("/role/" + name)).andDo(print()).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE)) + .andExpect(MockMvcResultMatchers.content().string(role)); + } + +} \ No newline at end of file From 552b2b2fa941f313d38ae44588dec44d3b0d82df Mon Sep 17 00:00:00 2001 From: Liesheng Long Date: Mon, 20 May 2019 02:24:51 -0400 Subject: [PATCH 09/31] sample code for article "Java Optional As Return Type" --- core-java-modules/core-java-8-2/pom.xml | 16 ++++++- .../HandleOptionalTypeExample.java | 41 ++++++++++++++++++ .../OptionalToJsonExample.java | 20 +++++++++ .../PersistOptionalTypeExample.java | 24 +++++++++++ .../PersistOptionalTypeExample2.java | 22 ++++++++++ .../PersistUserNoOptionalExample.java | 22 ++++++++++ .../SerializeOptionalTypeExample.java | 42 +++++++++++++++++++ .../com/baeldung/optionalReturnType/User.java | 31 ++++++++++++++ .../optionalReturnType/UserOptional.java | 35 ++++++++++++++++ .../optionalReturnType/UserOptionalField.java | 31 ++++++++++++++ .../main/resources/META-INF/persistence.xml | 32 ++++++++++++++ 11 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/HandleOptionalTypeExample.java create mode 100644 core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/OptionalToJsonExample.java create mode 100644 core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java create mode 100644 core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample2.java create mode 100644 core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserNoOptionalExample.java create mode 100644 core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/SerializeOptionalTypeExample.java create mode 100644 core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/User.java create mode 100644 core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptional.java create mode 100644 core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptionalField.java create mode 100644 core-java-modules/core-java-8-2/src/main/resources/META-INF/persistence.xml diff --git a/core-java-modules/core-java-8-2/pom.xml b/core-java-modules/core-java-8-2/pom.xml index fbaf795b95..862b739530 100644 --- a/core-java-modules/core-java-8-2/pom.xml +++ b/core-java-modules/core-java-8-2/pom.xml @@ -30,7 +30,21 @@ icu4j ${icu.version} - + + org.hibernate + hibernate-core + 5.4.0.Final + + + com.h2database + h2 + 1.4.197 + + + com.fasterxml.jackson.core + jackson-databind + 2.9.8 + diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/HandleOptionalTypeExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/HandleOptionalTypeExample.java new file mode 100644 index 0000000000..a49909901b --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/HandleOptionalTypeExample.java @@ -0,0 +1,41 @@ +package com.baeldung.optionalReturnType; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class HandleOptionalTypeExample { + static Map usersByName = new HashMap(); + static { + User user1 = new User(); + user1.setUserId(1l); + user1.setFirstName("baeldung"); + usersByName.put("baeldung", user1); + } + + public static void main(String[] args) { + changeUserName("baeldung", "baeldung-new"); + changeUserName("user", "user-new"); + } + + public static void changeUserName(String oldFirstName, String newFirstName) { + Optional userOpt = findUserByName(oldFirstName); + if(userOpt.isPresent()){ + User user = userOpt.get(); + user.setFirstName(newFirstName); + + System.out.println("user with name "+oldFirstName+" is changed to "+ user.getFirstName()); + } else { + //user is missing + System.out.println("user with name "+oldFirstName+" is not found."); + } + } + + public static Optional findUserByName(String name){ + //look up the user in the database, the user object below could be null + User user=usersByName.get(name); + Optional opt = Optional.ofNullable(user); + + return opt; + } +} diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/OptionalToJsonExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/OptionalToJsonExample.java new file mode 100644 index 0000000000..cec5ba5ce1 --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/OptionalToJsonExample.java @@ -0,0 +1,20 @@ +package com.baeldung.optionalReturnType; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class OptionalToJsonExample { + public static void main(String[] args) { + UserOptional user = new UserOptional(); + user.setUserId(1l); + user.setFirstName("Bael Dung"); + + ObjectMapper om = new ObjectMapper(); + try { + System.out.print("user in json is:"+om.writeValueAsString(user)); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java new file mode 100644 index 0000000000..afe46ca7eb --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java @@ -0,0 +1,24 @@ +package com.baeldung.optionalReturnType; + +import java.util.Optional; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +public class PersistOptionalTypeExample { + static String persistenceUnit = "com.baeldung.optionalReturnType"; + static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); + + static EntityManager entityManager = emf.createEntityManager(); + + public static void main(String[] args) { + UserOptionalField user1 = new UserOptionalField(); + user1.setUserId(1l); + user1.setFirstName(Optional.of("Bael Dung")); + entityManager.persist(user1); + + UserOptional user2 = entityManager.find(UserOptional.class, 1l); + System.out.print("User2.firstName:"+user2.getFirstName()); + } +} diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample2.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample2.java new file mode 100644 index 0000000000..0662b692a8 --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample2.java @@ -0,0 +1,22 @@ +package com.baeldung.optionalReturnType; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +public class PersistOptionalTypeExample2 { + static String persistenceUnit = "com.baeldung.optionalReturnType"; + static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); + + static EntityManager em = emf.createEntityManager(); + + public static void main(String[] args) { + UserOptional user1 = new UserOptional(); + user1.setUserId(1l); + user1.setFirstName("Bael Dung"); + em.persist(user1); + + UserOptional user2 = em.find(UserOptional.class, 1l); + System.out.print("User2.firstName:"+user2.getFirstName()); + } +} diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserNoOptionalExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserNoOptionalExample.java new file mode 100644 index 0000000000..dba67feecd --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserNoOptionalExample.java @@ -0,0 +1,22 @@ +package com.baeldung.optionalReturnType; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +public class PersistUserNoOptionalExample { + static String persistenceUnit = "com.baeldung.optionalReturnType"; + static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); + + static EntityManager em = emf.createEntityManager(); + + public static void main(String[] args) { + User user1 = new User(); + user1.setUserId(1l); + user1.setFirstName("Bael Dung"); + em.persist(user1); + + User user2 = em.find(User.class, 1l); + System.out.print("User2.firstName:"+user2.getFirstName()); + } +} diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/SerializeOptionalTypeExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/SerializeOptionalTypeExample.java new file mode 100644 index 0000000000..7ad4a5325e --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/SerializeOptionalTypeExample.java @@ -0,0 +1,42 @@ +package com.baeldung.optionalReturnType; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Optional; + +public class SerializeOptionalTypeExample { + public static void main(String[] args) { + User user1 = new User(); + user1.setUserId(1l); + user1.setFirstName("baeldung"); + + serializeObject(user1, "user1.ser"); + + + UserOptionalField user2 = new UserOptionalField(); + user2.setUserId(1l); + user2.setFirstName(Optional.of("baeldung")); + + serializeObject(user2, "user2.ser"); + + } + + public static void serializeObject(Object object, String fileName) { + // Serialization + try { + FileOutputStream file = new FileOutputStream(fileName); + ObjectOutputStream out = new ObjectOutputStream(file); + + out.writeObject(object); + + out.close(); + file.close(); + + System.out.println("Object "+object.toString()+ " has been serialized to file "+fileName); + + } catch(IOException e) { + e.printStackTrace(); + } + } +} diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/User.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/User.java new file mode 100644 index 0000000000..42bedb4817 --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/User.java @@ -0,0 +1,31 @@ +package com.baeldung.optionalReturnType; + +import java.io.Serializable; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class User implements Serializable { + @Id + private long userId; + + private String firstName; + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + +} diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptional.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptional.java new file mode 100644 index 0000000000..c48781ea80 --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptional.java @@ -0,0 +1,35 @@ +package com.baeldung.optionalReturnType; + +import java.io.Serializable; +import java.util.Optional; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class UserOptional implements Serializable { + @Id + private long userId; + + @Column(nullable = true) + private String firstName; + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public Optional getFirstName() { + return Optional.ofNullable(firstName); + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + Optional.ofNullable(firstName); + } + +} diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptionalField.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptionalField.java new file mode 100644 index 0000000000..0778a8bb99 --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptionalField.java @@ -0,0 +1,31 @@ +package com.baeldung.optionalReturnType; + +import java.io.Serializable; +import java.util.Optional; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class UserOptionalField implements Serializable { + @Id + private long userId; + + private Optional firstName; + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public Optional getFirstName() { + return firstName; + } + + public void setFirstName(Optional firstName) { + this.firstName = firstName; + } +} diff --git a/core-java-modules/core-java-8-2/src/main/resources/META-INF/persistence.xml b/core-java-modules/core-java-8-2/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000..3a05c733ee --- /dev/null +++ b/core-java-modules/core-java-8-2/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,32 @@ + + + + + Persist Optional Return Type Demo + org.hibernate.jpa.HibernatePersistenceProvider + com.baeldung.optionalReturnType.UserNoOptional + com.baeldung.optionalReturnType.UserOptional + com.baeldung.optionalReturnType.UserOptionalField + true + + + + + + + + + + + + + \ No newline at end of file From 6754e4cd218f2ba032ef798e48c9a26410a159a7 Mon Sep 17 00:00:00 2001 From: Matt Zhang Date: Mon, 20 May 2019 21:37:55 +1000 Subject: [PATCH 10/31] BAEL-2878 rename the test --- ... => ConditionalOnBeanIntegrationTest.java} | 2 +- ...=> ConditionalOnClassIntegrationTest.java} | 22 +++++++++---------- ...ConditionalOnPropertyIntegrationTest.java} | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) rename spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/{ConditionalOnBeanTest.java => ConditionalOnBeanIntegrationTest.java} (98%) rename spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/{ConditionalOnClassTest.java => ConditionalOnClassIntegrationTest.java} (80%) rename spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/{ConditionalOnPropertyTest.java => ConditionalOnPropertyIntegrationTest.java} (98%) diff --git a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanTest.java b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanIntegrationTest.java similarity index 98% rename from spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanTest.java rename to spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanIntegrationTest.java index 313d1253c5..c94b432b9d 100644 --- a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanTest.java +++ b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanIntegrationTest.java @@ -9,7 +9,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -public class ConditionalOnBeanTest { +public class ConditionalOnBeanIntegrationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); diff --git a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassTest.java b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassIntegrationTest.java similarity index 80% rename from spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassTest.java rename to spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassIntegrationTest.java index 7f01ea85d4..f2866867f2 100644 --- a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassTest.java +++ b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnClassIntegrationTest.java @@ -10,7 +10,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -public class ConditionalOnClassTest { +public class ConditionalOnClassIntegrationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); @@ -19,7 +19,7 @@ public class ConditionalOnClassTest { this.contextRunner.withUserConfiguration(ConditionalOnClassConfiguration.class) .run(context -> { assertThat(context).hasBean("created"); - assertThat(context.getBean("created")).isEqualTo("This is created when ConditionalOnClassTest is present on the classpath"); + assertThat(context.getBean("created")).isEqualTo("This is created when ConditionalOnClassIntegrationTest is present on the classpath"); }); } @@ -34,10 +34,10 @@ public class ConditionalOnClassTest { @Test public void whenDependentClassIsNotPresent_thenBeanMissing() { this.contextRunner.withUserConfiguration(ConditionalOnClassConfiguration.class) - .withClassLoader(new FilteredClassLoader(ConditionalOnClassTest.class)) + .withClassLoader(new FilteredClassLoader(ConditionalOnClassIntegrationTest.class)) .run((context) -> { assertThat(context).doesNotHaveBean("created"); - assertThat(context).doesNotHaveBean(ConditionalOnClassTest.class); + assertThat(context).doesNotHaveBean(ConditionalOnClassIntegrationTest.class); }); } @@ -45,31 +45,31 @@ public class ConditionalOnClassTest { @Test public void whenDependentClassIsNotPresent_thenBeanCreated() { this.contextRunner.withUserConfiguration(ConditionalOnMissingClassConfiguration.class) - .withClassLoader(new FilteredClassLoader(ConditionalOnClassTest.class)) + .withClassLoader(new FilteredClassLoader(ConditionalOnClassIntegrationTest.class)) .run((context) -> { assertThat(context).hasBean("missed"); assertThat(context).getBean("missed") - .isEqualTo("This is missed when ConditionalOnClassTest is present on the classpath"); - assertThat(context).doesNotHaveBean(ConditionalOnClassTest.class); + .isEqualTo("This is missed when ConditionalOnClassIntegrationTest is present on the classpath"); + assertThat(context).doesNotHaveBean(ConditionalOnClassIntegrationTest.class); }); } @Configuration - @ConditionalOnClass(ConditionalOnClassTest.class) + @ConditionalOnClass(ConditionalOnClassIntegrationTest.class) protected static class ConditionalOnClassConfiguration { @Bean public String created() { - return "This is created when ConditionalOnClassTest is present on the classpath"; + return "This is created when ConditionalOnClassIntegrationTest is present on the classpath"; } } @Configuration - @ConditionalOnMissingClass("com.baeldung.autoconfiguration.ConditionalOnClassTest") + @ConditionalOnMissingClass("com.baeldung.autoconfiguration.ConditionalOnClassIntegrationTest") protected static class ConditionalOnMissingClassConfiguration { @Bean public String missed() { - return "This is missed when ConditionalOnClassTest is present on the classpath"; + return "This is missed when ConditionalOnClassIntegrationTest is present on the classpath"; } } diff --git a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyTest.java b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyIntegrationTest.java similarity index 98% rename from spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyTest.java rename to spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyIntegrationTest.java index 2c09b72dda..c0733722dc 100644 --- a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyTest.java +++ b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnPropertyIntegrationTest.java @@ -14,7 +14,7 @@ import com.baeldung.autoconfiguration.service.CustomService; import com.baeldung.autoconfiguration.service.DefaultService; import com.baeldung.autoconfiguration.service.SimpleService; -public class ConditionalOnPropertyTest { +public class ConditionalOnPropertyIntegrationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); From 2c9c96a811f2cd1ebf90af4f2f042e795c598eb6 Mon Sep 17 00:00:00 2001 From: Liesheng Long Date: Mon, 20 May 2019 21:59:47 -0400 Subject: [PATCH 11/31] fixed some code --- .../optionalReturnType/PersistOptionalTypeExample.java | 2 ++ ...sistUserNoOptionalExample.java => PersistUserExample.java} | 2 +- .../core-java-8-2/src/main/resources/META-INF/persistence.xml | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) rename core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/{PersistUserNoOptionalExample.java => PersistUserExample.java} (93%) diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java index afe46ca7eb..681fae565b 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java @@ -12,6 +12,8 @@ public class PersistOptionalTypeExample { static EntityManager entityManager = emf.createEntityManager(); + //to run this app, uncomment the follow line in META-INF/persistence.xml + //com.baeldung.optionalReturnType.UserOptionalField public static void main(String[] args) { UserOptionalField user1 = new UserOptionalField(); user1.setUserId(1l); diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserNoOptionalExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserExample.java similarity index 93% rename from core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserNoOptionalExample.java rename to core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserExample.java index dba67feecd..af17f83c6e 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserNoOptionalExample.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserExample.java @@ -4,7 +4,7 @@ import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; -public class PersistUserNoOptionalExample { +public class PersistUserExample { static String persistenceUnit = "com.baeldung.optionalReturnType"; static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); diff --git a/core-java-modules/core-java-8-2/src/main/resources/META-INF/persistence.xml b/core-java-modules/core-java-8-2/src/main/resources/META-INF/persistence.xml index 3a05c733ee..e8cd723ec2 100644 --- a/core-java-modules/core-java-8-2/src/main/resources/META-INF/persistence.xml +++ b/core-java-modules/core-java-8-2/src/main/resources/META-INF/persistence.xml @@ -9,9 +9,11 @@ transaction-type="RESOURCE_LOCAL"> Persist Optional Return Type Demo org.hibernate.jpa.HibernatePersistenceProvider - com.baeldung.optionalReturnType.UserNoOptional + com.baeldung.optionalReturnType.User com.baeldung.optionalReturnType.UserOptional + true From 2c79a4a97f841a1335a031a041f78631b95b0003 Mon Sep 17 00:00:00 2001 From: Alessio Stalla Date: Tue, 21 May 2019 19:05:11 +0200 Subject: [PATCH 12/31] First Hibernate Validator specific constraints tests. --- persistence-modules/hibernate-mapping/pom.xml | 20 ++---- .../hibernate/persistmaps/mapkey/User.java | 22 ++++++ .../UserAdditionalValidationUnitTest.java | 72 +++++++++++++++++++ 3 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserAdditionalValidationUnitTest.java diff --git a/persistence-modules/hibernate-mapping/pom.xml b/persistence-modules/hibernate-mapping/pom.xml index 6bab3c5b1f..67eda5bf72 100644 --- a/persistence-modules/hibernate-mapping/pom.xml +++ b/persistence-modules/hibernate-mapping/pom.xml @@ -5,9 +5,9 @@ com.baeldung - parent-modules + persistence-modules 1.0.0-SNAPSHOT - ../../ + .. hibernate-mapping @@ -31,17 +31,12 @@ h2 ${h2.version} - + org.hibernate hibernate-validator ${hibernate-validator.version} - - javax.el - javax.el-api - ${javax.el-api.version} - org.glassfish javax.el @@ -60,11 +55,10 @@ - 5.3.7.Final + 5.3.10.Final 3.8.0 - 5.3.3.Final - 2.2.5 - 3.0.1-b08 + 6.0.16.Final + 3.0.1-b11 - \ No newline at end of file + diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java index f6e8f1cdd6..961fc944a4 100644 --- a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java @@ -6,6 +6,7 @@ import javax.persistence.Id; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.Length; +import org.hibernate.validator.constraints.CreditCardNumber; @Entity public class User { @@ -23,6 +24,12 @@ public class User { @Size(min = 3, max = 5) private String city; + @CreditCardNumber + private String creditCardNumber; + + @CreditCardNumber(ignoreNonDigitCharacters = true) + private String lenientCreditCardNumber; + public User(String firstName, String middleName, String lastName, String city) { super(); this.firstName = firstName; @@ -63,4 +70,19 @@ public class User { this.city = city; } + public String getCreditCardNumber() { + return creditCardNumber; + } + + public void setCreditCardNumber(String creditCardNumber) { + this.creditCardNumber = creditCardNumber; + } + + public String getLenientCreditCardNumber() { + return lenientCreditCardNumber; + } + + public void setLenientCreditCardNumber(String lenientCreditCardNumber) { + this.lenientCreditCardNumber = lenientCreditCardNumber; + } } diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserAdditionalValidationUnitTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserAdditionalValidationUnitTest.java new file mode 100644 index 0000000000..aaf52fe765 --- /dev/null +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserAdditionalValidationUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.hibernate.validation; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.Strategy; +import com.baeldung.hibernate.persistmaps.mapkey.User; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.persistence.PersistenceException; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class UserAdditionalValidationUnitTest { + + private static Validator validator; + private static SessionFactory sessionFactory; + private Session session; + private Set> constraintViolations; + + @BeforeClass + public static void before() { + ValidatorFactory config = Validation.buildDefaultValidatorFactory(); + validator = config.getValidator(); + sessionFactory = HibernateUtil.getSessionFactory(Strategy.MAP_KEY_BASED); + } + + @Before + public void setUp() { + session = sessionFactory.openSession(); + session.beginTransaction(); + } + + @Test + public void whenValidationWithCCNAndNullCCN_thenNoConstraintViolation() { + User user = new User("John", "Paul", "Butler", "York"); + constraintViolations = validator.validateProperty(user, "creditCardNumber"); + assertTrue(constraintViolations.isEmpty()); + } + + @Test + public void whenValidationWithCCNAndValidCCN_thenNoConstraintViolation() { + User user = new User("John", "Paul", "Butler", "York"); + user.setCreditCardNumber("79927398713"); + constraintViolations = validator.validateProperty(user, "creditCardNumber"); + assertTrue(constraintViolations.isEmpty()); + } + + @Test + public void whenValidationWithCCNAndInvalidCCN_thenConstraintViolation() { + User user = new User("John", "Paul", "Butler", "York"); + user.setCreditCardNumber("79927398714"); + constraintViolations = validator.validateProperty(user, "creditCardNumber"); + assertEquals(constraintViolations.size(), 1); + } + + @Test + public void whenValidationWithLenientCCNAndValidCCNWithDashes_thenNoConstraintViolation() { + User user = new User("John", "Paul", "Butler", "York"); + user.setLenientCreditCardNumber("7992-7398-713"); + constraintViolations = validator.validateProperty(user, "lenientCreditCardNumber"); + assertTrue(constraintViolations.isEmpty()); + } +} From a5a99c28b1e5c3229cb6d2765a85c64bb35fdef6 Mon Sep 17 00:00:00 2001 From: Liesheng Long Date: Thu, 23 May 2019 20:09:03 -0400 Subject: [PATCH 13/31] formatting the source code --- .../HandleOptionalTypeExample.java | 64 +++++++++---------- .../OptionalToJsonExample.java | 25 ++++---- .../PersistOptionalTypeExample.java | 32 +++++----- .../PersistOptionalTypeExample2.java | 28 ++++---- .../PersistUserExample.java | 28 ++++---- .../SerializeOptionalTypeExample.java | 61 +++++++++--------- .../com/baeldung/optionalReturnType/User.java | 36 +++++------ .../optionalReturnType/UserOptional.java | 40 ++++++------ .../optionalReturnType/UserOptionalField.java | 34 +++++----- 9 files changed, 173 insertions(+), 175 deletions(-) diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/HandleOptionalTypeExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/HandleOptionalTypeExample.java index a49909901b..c472bab077 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/HandleOptionalTypeExample.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/HandleOptionalTypeExample.java @@ -5,37 +5,37 @@ import java.util.Map; import java.util.Optional; public class HandleOptionalTypeExample { - static Map usersByName = new HashMap(); - static { - User user1 = new User(); - user1.setUserId(1l); - user1.setFirstName("baeldung"); - usersByName.put("baeldung", user1); - } - - public static void main(String[] args) { - changeUserName("baeldung", "baeldung-new"); - changeUserName("user", "user-new"); - } - - public static void changeUserName(String oldFirstName, String newFirstName) { - Optional userOpt = findUserByName(oldFirstName); - if(userOpt.isPresent()){ - User user = userOpt.get(); - user.setFirstName(newFirstName); - - System.out.println("user with name "+oldFirstName+" is changed to "+ user.getFirstName()); - } else { - //user is missing - System.out.println("user with name "+oldFirstName+" is not found."); - } - } - - public static Optional findUserByName(String name){ - //look up the user in the database, the user object below could be null - User user=usersByName.get(name); - Optional opt = Optional.ofNullable(user); + static Map usersByName = new HashMap(); + static { + User user1 = new User(); + user1.setUserId(1l); + user1.setFirstName("baeldung"); + usersByName.put("baeldung", user1); + } - return opt; - } + public static void main(String[] args) { + changeUserName("baeldung", "baeldung-new"); + changeUserName("user", "user-new"); + } + + public static void changeUserName(String oldFirstName, String newFirstName) { + Optional userOpt = findUserByName(oldFirstName); + if (userOpt.isPresent()) { + User user = userOpt.get(); + user.setFirstName(newFirstName); + + System.out.println("user with name " + oldFirstName + " is changed to " + user.getFirstName()); + } else { + // user is missing + System.out.println("user with name " + oldFirstName + " is not found."); + } + } + + public static Optional findUserByName(String name) { + // look up the user in the database, the user object below could be null + User user = usersByName.get(name); + Optional opt = Optional.ofNullable(user); + + return opt; + } } diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/OptionalToJsonExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/OptionalToJsonExample.java index cec5ba5ce1..b44a35fae1 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/OptionalToJsonExample.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/OptionalToJsonExample.java @@ -4,17 +4,16 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public class OptionalToJsonExample { - public static void main(String[] args) { - UserOptional user = new UserOptional(); - user.setUserId(1l); - user.setFirstName("Bael Dung"); - - ObjectMapper om = new ObjectMapper(); - try { - System.out.print("user in json is:"+om.writeValueAsString(user)); - } catch (JsonProcessingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } + public static void main(String[] args) { + UserOptional user = new UserOptional(); + user.setUserId(1l); + user.setFirstName("Bael Dung"); + + ObjectMapper om = new ObjectMapper(); + try { + System.out.print("user in json is:" + om.writeValueAsString(user)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } } diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java index 681fae565b..85c96b9bc3 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample.java @@ -7,20 +7,20 @@ import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; public class PersistOptionalTypeExample { - static String persistenceUnit = "com.baeldung.optionalReturnType"; - static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); - - static EntityManager entityManager = emf.createEntityManager(); - - //to run this app, uncomment the follow line in META-INF/persistence.xml - //com.baeldung.optionalReturnType.UserOptionalField - public static void main(String[] args) { - UserOptionalField user1 = new UserOptionalField(); - user1.setUserId(1l); - user1.setFirstName(Optional.of("Bael Dung")); - entityManager.persist(user1); - - UserOptional user2 = entityManager.find(UserOptional.class, 1l); - System.out.print("User2.firstName:"+user2.getFirstName()); - } + static String persistenceUnit = "com.baeldung.optionalReturnType"; + static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); + + static EntityManager entityManager = emf.createEntityManager(); + + // to run this app, uncomment the follow line in META-INF/persistence.xml + // com.baeldung.optionalReturnType.UserOptionalField + public static void main(String[] args) { + UserOptionalField user1 = new UserOptionalField(); + user1.setUserId(1l); + user1.setFirstName(Optional.of("Bael Dung")); + entityManager.persist(user1); + + UserOptional user2 = entityManager.find(UserOptional.class, 1l); + System.out.print("User2.firstName:" + user2.getFirstName()); + } } diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample2.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample2.java index 0662b692a8..3114e7cefb 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample2.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistOptionalTypeExample2.java @@ -5,18 +5,18 @@ import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; public class PersistOptionalTypeExample2 { - static String persistenceUnit = "com.baeldung.optionalReturnType"; - static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); - - static EntityManager em = emf.createEntityManager(); - - public static void main(String[] args) { - UserOptional user1 = new UserOptional(); - user1.setUserId(1l); - user1.setFirstName("Bael Dung"); - em.persist(user1); - - UserOptional user2 = em.find(UserOptional.class, 1l); - System.out.print("User2.firstName:"+user2.getFirstName()); - } + static String persistenceUnit = "com.baeldung.optionalReturnType"; + static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); + + static EntityManager em = emf.createEntityManager(); + + public static void main(String[] args) { + UserOptional user1 = new UserOptional(); + user1.setUserId(1l); + user1.setFirstName("Bael Dung"); + em.persist(user1); + + UserOptional user2 = em.find(UserOptional.class, 1l); + System.out.print("User2.firstName:" + user2.getFirstName()); + } } diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserExample.java index af17f83c6e..f1284958e7 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserExample.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/PersistUserExample.java @@ -5,18 +5,18 @@ import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; public class PersistUserExample { - static String persistenceUnit = "com.baeldung.optionalReturnType"; - static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); - - static EntityManager em = emf.createEntityManager(); - - public static void main(String[] args) { - User user1 = new User(); - user1.setUserId(1l); - user1.setFirstName("Bael Dung"); - em.persist(user1); - - User user2 = em.find(User.class, 1l); - System.out.print("User2.firstName:"+user2.getFirstName()); - } + static String persistenceUnit = "com.baeldung.optionalReturnType"; + static EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit); + + static EntityManager em = emf.createEntityManager(); + + public static void main(String[] args) { + User user1 = new User(); + user1.setUserId(1l); + user1.setFirstName("Bael Dung"); + em.persist(user1); + + User user2 = em.find(User.class, 1l); + System.out.print("User2.firstName:" + user2.getFirstName()); + } } diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/SerializeOptionalTypeExample.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/SerializeOptionalTypeExample.java index 7ad4a5325e..d67337ad98 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/SerializeOptionalTypeExample.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/SerializeOptionalTypeExample.java @@ -6,37 +6,36 @@ import java.io.ObjectOutputStream; import java.util.Optional; public class SerializeOptionalTypeExample { - public static void main(String[] args) { - User user1 = new User(); - user1.setUserId(1l); - user1.setFirstName("baeldung"); - - serializeObject(user1, "user1.ser"); - + public static void main(String[] args) { + User user1 = new User(); + user1.setUserId(1l); + user1.setFirstName("baeldung"); - UserOptionalField user2 = new UserOptionalField(); - user2.setUserId(1l); - user2.setFirstName(Optional.of("baeldung")); - - serializeObject(user2, "user2.ser"); + serializeObject(user1, "user1.ser"); - } - - public static void serializeObject(Object object, String fileName) { - // Serialization - try { - FileOutputStream file = new FileOutputStream(fileName); - ObjectOutputStream out = new ObjectOutputStream(file); - - out.writeObject(object); - - out.close(); - file.close(); - - System.out.println("Object "+object.toString()+ " has been serialized to file "+fileName); - - } catch(IOException e) { - e.printStackTrace(); - } - } + UserOptionalField user2 = new UserOptionalField(); + user2.setUserId(1l); + user2.setFirstName(Optional.of("baeldung")); + + serializeObject(user2, "user2.ser"); + + } + + public static void serializeObject(Object object, String fileName) { + // Serialization + try { + FileOutputStream file = new FileOutputStream(fileName); + ObjectOutputStream out = new ObjectOutputStream(file); + + out.writeObject(object); + + out.close(); + file.close(); + + System.out.println("Object " + object.toString() + " has been serialized to file " + fileName); + + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/User.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/User.java index 42bedb4817..7aa11d78cb 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/User.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/User.java @@ -7,25 +7,25 @@ import javax.persistence.Id; @Entity public class User implements Serializable { - @Id - private long userId; - - private String firstName; - - public long getUserId() { - return userId; - } + @Id + private long userId; - public void setUserId(long userId) { - this.userId = userId; - } + private String firstName; - public String getFirstName() { - return firstName; - } + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } - public void setFirstName(String firstName) { - this.firstName = firstName; - } - } diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptional.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptional.java index c48781ea80..0138a84ab9 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptional.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptional.java @@ -9,27 +9,27 @@ import javax.persistence.Id; @Entity public class UserOptional implements Serializable { - @Id - private long userId; - - @Column(nullable = true) - private String firstName; - - public long getUserId() { - return userId; - } + @Id + private long userId; - public void setUserId(long userId) { - this.userId = userId; - } + @Column(nullable = true) + private String firstName; - public Optional getFirstName() { - return Optional.ofNullable(firstName); - } + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public Optional getFirstName() { + return Optional.ofNullable(firstName); + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + Optional.ofNullable(firstName); + } - public void setFirstName(String firstName) { - this.firstName = firstName; - Optional.ofNullable(firstName); - } - } diff --git a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptionalField.java b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptionalField.java index 0778a8bb99..c02430b1ba 100644 --- a/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptionalField.java +++ b/core-java-modules/core-java-8-2/src/main/java/com/baeldung/optionalReturnType/UserOptionalField.java @@ -8,24 +8,24 @@ import javax.persistence.Id; @Entity public class UserOptionalField implements Serializable { - @Id - private long userId; - - private Optional firstName; - - public long getUserId() { - return userId; - } + @Id + private long userId; - public void setUserId(long userId) { - this.userId = userId; - } + private Optional firstName; - public Optional getFirstName() { - return firstName; - } + public long getUserId() { + return userId; + } - public void setFirstName(Optional firstName) { - this.firstName = firstName; - } + public void setUserId(long userId) { + this.userId = userId; + } + + public Optional getFirstName() { + return firstName; + } + + public void setFirstName(Optional firstName) { + this.firstName = firstName; + } } From a8cdcc610083fd4a3d51fea91c2b8664f18c05ef Mon Sep 17 00:00:00 2001 From: Liesheng Long Date: Thu, 23 May 2019 20:18:30 -0400 Subject: [PATCH 14/31] formatting and use properties for versions --- core-java-modules/core-java-8-2/pom.xml | 103 ++++++++++++------------ 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/core-java-modules/core-java-8-2/pom.xml b/core-java-modules/core-java-8-2/pom.xml index 862b739530..150f36be59 100644 --- a/core-java-modules/core-java-8-2/pom.xml +++ b/core-java-modules/core-java-8-2/pom.xml @@ -1,64 +1,67 @@ - 4.0.0 - com.baeldung - core-java-8-2 - 0.1.0-SNAPSHOT - core-java-8-2 - jar + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + com.baeldung + core-java-8-2 + 0.1.0-SNAPSHOT + core-java-8-2 + jar - - com.baeldung - parent-java - 0.0.1-SNAPSHOT - ../../parent-java - + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../../parent-java + - - UTF-8 - 1.8 - 1.8 - 64.2 - + + UTF-8 + 1.8 + 1.8 + 64.2 + 5.4.0.Final + 1.4.197 + 2.9.8 + - - - com.ibm.icu - icu4j - ${icu.version} - + - org.hibernate - hibernate-core - 5.4.0.Final + com.ibm.icu + icu4j + ${icu.version} - com.h2database - h2 - 1.4.197 + org.hibernate + hibernate-core + ${hibernate.core.version} - com.fasterxml.jackson.core - jackson-databind - 2.9.8 - - + com.h2database + h2 + ${h2database.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.databind.version} + + - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + - + From 1050337dabfb4c84512bbe4a4bf7087a35f55ee3 Mon Sep 17 00:00:00 2001 From: Liesheng Long Date: Fri, 24 May 2019 11:28:49 -0400 Subject: [PATCH 15/31] replace tabs with 4-spaces --- core-java-modules/core-java-8-2/pom.xml | 116 ++++++++++++------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/core-java-modules/core-java-8-2/pom.xml b/core-java-modules/core-java-8-2/pom.xml index 150f36be59..ff2e290086 100644 --- a/core-java-modules/core-java-8-2/pom.xml +++ b/core-java-modules/core-java-8-2/pom.xml @@ -1,67 +1,67 @@ - 4.0.0 - com.baeldung - core-java-8-2 - 0.1.0-SNAPSHOT - core-java-8-2 - jar + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + com.baeldung + core-java-8-2 + 0.1.0-SNAPSHOT + core-java-8-2 + jar - - com.baeldung - parent-java - 0.0.1-SNAPSHOT - ../../parent-java - + + com.baeldung + parent-java + 0.0.1-SNAPSHOT + ../../parent-java + - - UTF-8 - 1.8 - 1.8 - 64.2 - 5.4.0.Final - 1.4.197 - 2.9.8 - + + UTF-8 + 1.8 + 1.8 + 64.2 + 5.4.0.Final + 1.4.197 + 2.9.8 + - - - com.ibm.icu - icu4j - ${icu.version} - - - org.hibernate - hibernate-core - ${hibernate.core.version} - - - com.h2database - h2 - ${h2database.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.databind.version} - - + + + com.ibm.icu + icu4j + ${icu.version} + + + org.hibernate + hibernate-core + ${hibernate.core.version} + + + com.h2database + h2 + ${h2database.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.databind.version} + + - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + - + From 066cf2d6f2d9122a648ce016aa31412cd22bd4c2 Mon Sep 17 00:00:00 2001 From: Matt Zhang Date: Sun, 26 May 2019 22:14:10 +1000 Subject: [PATCH 16/31] BAEL-2878 Guide to Spring's ApplicationContextRunner --- .../autoconfiguration/ConditionalOnBeanIntegrationTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanIntegrationTest.java b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanIntegrationTest.java index c94b432b9d..32f63edde4 100644 --- a/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanIntegrationTest.java +++ b/spring-boot-autoconfiguration/src/test/java/com/baeldung/autoconfiguration/ConditionalOnBeanIntegrationTest.java @@ -15,7 +15,7 @@ public class ConditionalOnBeanIntegrationTest { @Test public void whenDependentBeanIsPresent_thenConditionalBeanCreated() { - this.contextRunner.withUserConfiguration(basicConfiguration.class, ConditionalOnBeanConfiguration.class) + this.contextRunner.withUserConfiguration(BasicConfiguration.class, ConditionalOnBeanConfiguration.class) .run((context) -> { assertThat(context).hasBean("created"); assertThat(context).getBean("created") @@ -28,7 +28,7 @@ public class ConditionalOnBeanIntegrationTest { @Test public void whenDependentBeanIsPresent_thenConditionalMissingBeanIgnored() { - this.contextRunner.withUserConfiguration(basicConfiguration.class, ConditionalOnMissingBeanConfiguration.class) + this.contextRunner.withUserConfiguration(BasicConfiguration.class, ConditionalOnMissingBeanConfiguration.class) .run((context) -> { assertThat(context).hasBean("created"); assertThat(context).getBean("created") @@ -49,7 +49,7 @@ public class ConditionalOnBeanIntegrationTest { } @Configuration - protected static class basicConfiguration { + protected static class BasicConfiguration { @Bean public String created() { return "This is always created"; From 7ff1bc1aea5568146330db5f575edebc295e9be0 Mon Sep 17 00:00:00 2001 From: andrea-ligios Date: Sun, 26 May 2019 20:22:55 +0200 Subject: [PATCH 17/31] BAEL-2758 --- docker/docker-compose.yml | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 docker/docker-compose.yml diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000000..72d07d6392 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,61 @@ +version: '3' + +services: + +## VOLUME CONTAINER-TO-CONTAINER AND HOST-TO-CONTAINER TEST ## + + volumes-example-service: + image: alpine:latest + container_name: volumes-example-service + volumes: + - /tmp:/my-volumes/host-volume + - /home:/my-volumes/readonly-host-volume:ro + - my-named-global-volume:/my-volumes/named-global-volume + tty: true # Needed to keep the container running + + another-volumes-example-service: + image: alpine:latest + container_name: another-volumes-example-service + volumes: + - my-named-global-volume:/another-path/the-same-named-global-volume + tty: true # Needed to keep the container running + +## NETWORK CONTAINER-TO-CONTAINER TEST ## + + network-example-service: + image: karthequian/helloworld:latest + container_name: network-example-service + networks: + - my-shared-network + + another-service-in-the-same-network: + image: alpine:latest + container_name: another-service-in-the-same-network + networks: + - my-shared-network + + tty: true # Needed to keep the container running + + another-service-in-its-own-network: + image: alpine:latest + container_name: another-service-in-its-own-network + networks: + - my-private-network + tty: true # Needed to keep the container running + +## NETWORK HOST-TO-CONTAINER TEST ## + + network-example-service-available-to-host-on-port-1337: + image: karthequian/helloworld:latest + container_name: network-example-service-available-to-host-on-port-1337 + networks: + - my-shared-network + ports: + - "1337:80" + +volumes: + my-named-global-volume: + +networks: + my-shared-network: {} + my-private-network: {} From 879ac26e844628cd63f69c20b3e6a3deb028621e Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 1 Jun 2019 09:15:51 +0300 Subject: [PATCH 18/31] Update README.md --- spring-security-rest-custom/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-security-rest-custom/README.md b/spring-security-rest-custom/README.md index 85f2b7532c..d7cb31e784 100644 --- a/spring-security-rest-custom/README.md +++ b/spring-security-rest-custom/README.md @@ -8,3 +8,4 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com ### Relevant Articles: - [Spring Security Authentication Provider](http://www.baeldung.com/spring-security-authentication-provider) - [Retrieve User Information in Spring Security](http://www.baeldung.com/get-user-in-spring-security) +- [Spring Security – Run-As Authentication](https://www.baeldung.com/spring-security-run-as-auth) From dc73b7abff2f44e495546531b6cc7259efcdd855 Mon Sep 17 00:00:00 2001 From: pkoli Date: Sat, 1 Jun 2019 13:50:48 +0530 Subject: [PATCH 19/31] BAEL-2886- post incremented counter variable --- .../SpringSessionMongoDBIntegrationTest.java | 43 ------------------- spring-session/spring-session-mongodb/pom.xml | 2 + .../SpringSessionMongoDBController.java | 6 +-- .../SpringSessionMongoDBIntegrationTest.java | 8 ++-- .../SpringContextIntegrationTest.java | 3 +- 5 files changed, 10 insertions(+), 52 deletions(-) delete mode 100644 spring-session/mongodb-session/src/test/java/com/baeldung/springsessionmongodb/SpringSessionMongoDBIntegrationTest.java diff --git a/spring-session/mongodb-session/src/test/java/com/baeldung/springsessionmongodb/SpringSessionMongoDBIntegrationTest.java b/spring-session/mongodb-session/src/test/java/com/baeldung/springsessionmongodb/SpringSessionMongoDBIntegrationTest.java deleted file mode 100644 index c73335b49b..0000000000 --- a/spring-session/mongodb-session/src/test/java/com/baeldung/springsessionmongodb/SpringSessionMongoDBIntegrationTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.baeldung.springsessionmongodb; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.session.data.mongo.MongoOperationsSessionRepository; -import org.springframework.test.context.junit4.SpringRunner; -import springsessionmongodb.SpringSessionMongoDBApplication; - -import java.util.Base64; - - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = SpringSessionMongoDBApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) -public class SpringSessionMongoDBIntegrationTest { - - @Autowired - private MongoOperationsSessionRepository repository; - - private TestRestTemplate restTemplate = new TestRestTemplate(); - - @Test - public void givenEndpointIsCalledTwiceAndResponseIsReturned_whenMongoDBIsQueriedForCount_thenCountMustBeSame() { - HttpEntity response = restTemplate. - exchange("http://localhost:" + 8080, HttpMethod.GET, null, String.class); - HttpHeaders headers = response.getHeaders(); - String set_cookie = headers.getFirst(HttpHeaders.SET_COOKIE); - - Assert.assertEquals(response.getBody(), - repository.findById(getSessionId(set_cookie)).getAttribute("count").toString()); - } - - private String getSessionId(String set_cookie) { - return new String(Base64.getDecoder().decode(set_cookie.split(";")[0].split("=")[1])); - } - -} diff --git a/spring-session/spring-session-mongodb/pom.xml b/spring-session/spring-session-mongodb/pom.xml index 714833cf99..16fbaccc84 100644 --- a/spring-session/spring-session-mongodb/pom.xml +++ b/spring-session/spring-session-mongodb/pom.xml @@ -32,6 +32,7 @@ org.springframework.boot spring-boot-starter-data-mongodb + ${spring-boot-starter-data-mongodb.version} @@ -43,6 +44,7 @@ 2.1.3.RELEASE + 2.1.5.RELEASE diff --git a/spring-session/spring-session-mongodb/src/main/java/com/baeldung/springsessionmongodb/controller/SpringSessionMongoDBController.java b/spring-session/spring-session-mongodb/src/main/java/com/baeldung/springsessionmongodb/controller/SpringSessionMongoDBController.java index 1c38f419c3..b5cb4520a0 100644 --- a/spring-session/spring-session-mongodb/src/main/java/com/baeldung/springsessionmongodb/controller/SpringSessionMongoDBController.java +++ b/spring-session/spring-session-mongodb/src/main/java/com/baeldung/springsessionmongodb/controller/SpringSessionMongoDBController.java @@ -1,11 +1,11 @@ package com.baeldung.springsessionmongodb.controller; -import javax.servlet.http.HttpSession; - import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpSession; + @RestController public class SpringSessionMongoDBController { @@ -17,7 +17,7 @@ public class SpringSessionMongoDBController { if (counter == null) { counter = 1; } else { - counter += 1; + counter++; } session.setAttribute("count", counter); diff --git a/spring-session/spring-session-mongodb/src/test/java/com/baeldung/springsessionmongodb/SpringSessionMongoDBIntegrationTest.java b/spring-session/spring-session-mongodb/src/test/java/com/baeldung/springsessionmongodb/SpringSessionMongoDBIntegrationTest.java index eb9f4164a6..9dc45c5b32 100644 --- a/spring-session/spring-session-mongodb/src/test/java/com/baeldung/springsessionmongodb/SpringSessionMongoDBIntegrationTest.java +++ b/spring-session/spring-session-mongodb/src/test/java/com/baeldung/springsessionmongodb/SpringSessionMongoDBIntegrationTest.java @@ -1,7 +1,5 @@ package com.baeldung.springsessionmongodb; -import java.util.Base64; - import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -14,6 +12,8 @@ import org.springframework.http.HttpMethod; import org.springframework.session.data.mongo.MongoOperationsSessionRepository; import org.springframework.test.context.junit4.SpringRunner; +import java.util.Base64; + @RunWith(SpringRunner.class) @SpringBootTest(classes = SpringSessionMongoDBApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @@ -26,8 +26,8 @@ public class SpringSessionMongoDBIntegrationTest { @Test public void givenEndpointIsCalledTwiceAndResponseIsReturned_whenMongoDBIsQueriedForCount_thenCountMustBeSame() { - HttpEntity response = restTemplate. - exchange("http://localhost:" + 8080, HttpMethod.GET, null, String.class); + HttpEntity response = restTemplate + .exchange("http://localhost:" + 8080, HttpMethod.GET, null, String.class); HttpHeaders headers = response.getHeaders(); String set_cookie = headers.getFirst(HttpHeaders.SET_COOKIE); diff --git a/spring-session/spring-session-mongodb/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-session/spring-session-mongodb/src/test/java/org/baeldung/SpringContextIntegrationTest.java index 3c58b2673f..16b7404f57 100644 --- a/spring-session/spring-session-mongodb/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-session/spring-session-mongodb/src/test/java/org/baeldung/SpringContextIntegrationTest.java @@ -1,12 +1,11 @@ package org.baeldung; +import com.baeldung.springsessionmongodb.SpringSessionMongoDBApplication; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import com.baeldung.springsessionmongodb.SpringSessionMongoDBApplication; - @RunWith(SpringRunner.class) @SpringBootTest(classes = SpringSessionMongoDBApplication.class) public class SpringContextIntegrationTest { From 011bd19b09f26f2c62468dcc4240c4472ad427a1 Mon Sep 17 00:00:00 2001 From: Loredana Date: Sat, 1 Jun 2019 11:32:00 +0300 Subject: [PATCH 20/31] revert junit version --- pom.xml | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 39803fd9b0..0a8eebda71 100644 --- a/pom.xml +++ b/pom.xml @@ -123,17 +123,22 @@ - - org.junit.jupiter - junit-jupiter-engine - ${junit-jupiter.version} - - - org.junit.vintage - junit-vintage-engine - ${junit-jupiter.version} - - + + org.junit.platform + junit-platform-surefire-provider + ${junit-platform.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + + + org.junit.vintage + junit-vintage-engine + ${junit-jupiter.version} + + org.apache.maven.plugins @@ -1550,8 +1555,8 @@ 1.2 2.9.8 1.3 - 1.4.2 - 5.4.2 + 1.2.0 + 5.4.0 0.3.1 2.5.1 0.0.1 From 503331b3715b8538bd320159f2cfb4a1a83fd07b Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 1 Jun 2019 17:24:25 +0300 Subject: [PATCH 21/31] Update README.md --- persistence-modules/java-mongodb/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-modules/java-mongodb/README.md b/persistence-modules/java-mongodb/README.md index 6d31467db3..045b245030 100644 --- a/persistence-modules/java-mongodb/README.md +++ b/persistence-modules/java-mongodb/README.md @@ -3,3 +3,4 @@ - [A Guide to MongoDB with Java](http://www.baeldung.com/java-mongodb) - [A Simple Tagging Implementation with MongoDB](http://www.baeldung.com/mongodb-tagging) - [MongoDB BSON Guide](https://www.baeldung.com/mongodb-bson) +- [Geospatial Support in MongoDB](https://www.baeldung.com/mongodb-geospatial-support) From 0e56ee46fe49ad6d87173baa35d9e9f8c14b37cc Mon Sep 17 00:00:00 2001 From: Loredana Date: Sat, 1 Jun 2019 18:57:18 +0300 Subject: [PATCH 22/31] fix flowable test --- .../main/resources/processes/article-workflow.bpmn20.xml | 4 ++-- ...lowUnitTest.java => ArticleWorkflowIntegrationTest.java} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename spring-boot-flowable/src/test/java/com/baeldung/processes/{ArticleWorkflowUnitTest.java => ArticleWorkflowIntegrationTest.java} (90%) diff --git a/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml b/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml index 6bf210dcee..77c02f39a4 100644 --- a/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml +++ b/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml @@ -38,12 +38,12 @@ + flowable:class="com.baeldung.service.PublishArticleService" /> + flowable:class="com.baeldung.service.SendMailService" /> diff --git a/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java b/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowIntegrationTest.java similarity index 90% rename from spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java rename to spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowIntegrationTest.java index ef5453623a..7d4557a679 100644 --- a/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java +++ b/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowIntegrationTest.java @@ -13,11 +13,11 @@ import org.flowable.task.api.Task; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.boot.test.context.SpringBootTest; @ExtendWith(FlowableSpringExtension.class) -@ExtendWith(SpringExtension.class) -public class ArticleWorkflowUnitTest { +@SpringBootTest +public class ArticleWorkflowIntegrationTest { @Autowired private RuntimeService runtimeService; @Autowired From 4abfc5f863108106464cc0328294c4750734fafd Mon Sep 17 00:00:00 2001 From: Loredana Date: Sun, 2 Jun 2019 10:01:12 +0300 Subject: [PATCH 23/31] fix filter test --- .../baeldung/hibernate/DynamicMappingIntegrationTest.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/DynamicMappingIntegrationTest.java b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/DynamicMappingIntegrationTest.java index f31a61f121..fce670112b 100644 --- a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/DynamicMappingIntegrationTest.java +++ b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/DynamicMappingIntegrationTest.java @@ -122,14 +122,11 @@ public class DynamicMappingIntegrationTest { Employee employee = session.get(Employee.class, 1); assertThat(employee.getGrossIncome()).isEqualTo(10_000); - session.close(); - - session = HibernateUtil.getSessionFactory().openSession(); - transaction = session.beginTransaction(); + session.disableFilter("incomeLevelFilter"); employees = session.createQuery("from Employee").getResultList(); - assertThat(employees).hasSize(0); + assertThat(employees).hasSize(3); } From f64ef7590a87328bf9fa6e94c451b0a71a00b743 Mon Sep 17 00:00:00 2001 From: Loredana Date: Sun, 2 Jun 2019 10:02:17 +0300 Subject: [PATCH 24/31] fix formatting --- .../com/baeldung/hibernate/DynamicMappingIntegrationTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/DynamicMappingIntegrationTest.java b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/DynamicMappingIntegrationTest.java index fce670112b..7a112200b5 100644 --- a/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/DynamicMappingIntegrationTest.java +++ b/persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/DynamicMappingIntegrationTest.java @@ -122,8 +122,7 @@ public class DynamicMappingIntegrationTest { Employee employee = session.get(Employee.class, 1); assertThat(employee.getGrossIncome()).isEqualTo(10_000); - session.disableFilter("incomeLevelFilter"); - + session.disableFilter("incomeLevelFilter"); employees = session.createQuery("from Employee").getResultList(); assertThat(employees).hasSize(3); From ce68ce1c65b8d7d142c73276dc00caf26fa0bb31 Mon Sep 17 00:00:00 2001 From: binary-joe <48189951+binary-joe@users.noreply.github.com> Date: Mon, 3 Jun 2019 06:42:11 +0200 Subject: [PATCH 25/31] BAEL-2516 catching errors in catch blocks (#7075) * BAEL-2516 catching errors in catch block * BAEL-2516 catching errors in catch block; classes moved --- .../com/baeldung/error/ErrorGenerator.java | 15 ------ .../error/ErrorGeneratorUnitTest.java | 51 ------------------- .../error/ErrorGeneratorUnitTest.java | 26 ++++++++++ 3 files changed, 26 insertions(+), 66 deletions(-) delete mode 100644 core-java-lang/src/main/java/com/baeldung/error/ErrorGenerator.java delete mode 100644 core-java-lang/src/test/java/com/baeldung/error/ErrorGeneratorUnitTest.java create mode 100644 core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exception/error/ErrorGeneratorUnitTest.java diff --git a/core-java-lang/src/main/java/com/baeldung/error/ErrorGenerator.java b/core-java-lang/src/main/java/com/baeldung/error/ErrorGenerator.java deleted file mode 100644 index 58cbe22df5..0000000000 --- a/core-java-lang/src/main/java/com/baeldung/error/ErrorGenerator.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.baeldung.error; - -public class ErrorGenerator { - public void throwException() throws Exception { - throw new Exception("checked"); - } - - public void throwRuntimeException() { - throw new RuntimeException("unchecked"); - } - - public void throwError() { - throw new Error("unchecked"); - } -} diff --git a/core-java-lang/src/test/java/com/baeldung/error/ErrorGeneratorUnitTest.java b/core-java-lang/src/test/java/com/baeldung/error/ErrorGeneratorUnitTest.java deleted file mode 100644 index 2a7c24f5fa..0000000000 --- a/core-java-lang/src/test/java/com/baeldung/error/ErrorGeneratorUnitTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.baeldung.error; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class ErrorGeneratorUnitTest { - - private ErrorGenerator errorGenerator; - - @Before - public void setUp() { - errorGenerator = new ErrorGenerator(); - } - - @Test - public void whenCheckedException_thenIsCaughtByCatchException() { - try { - errorGenerator.throwException(); - } catch (Exception e) { - // caught! -> test pass - } - } - - @Test - public void whenUncheckedException_thenIsCaughtByCatchException() { - try { - errorGenerator.throwRuntimeException(); - } catch (Exception e) { - // caught! -> test pass - } - } - - @Test(expected = Error.class) - public void whenError_thenIsNotCaughtByCatchException() { - try { - errorGenerator.throwError(); - } catch (Exception e) { - Assert.fail(); // errors are not caught by catch exception - } - } - - @Test - public void whenError_thenIsCaughtByCatchError() { - try { - errorGenerator.throwError(); - } catch (Error e) { - // caught! -> test pass - } - } -} \ No newline at end of file diff --git a/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exception/error/ErrorGeneratorUnitTest.java b/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exception/error/ErrorGeneratorUnitTest.java new file mode 100644 index 0000000000..de56fb7113 --- /dev/null +++ b/core-java-modules/core-java-exceptions/src/test/java/com/baeldung/exception/error/ErrorGeneratorUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.error; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ErrorGeneratorUnitTest { + + @Test(expected = AssertionError.class) + public void whenError_thenIsNotCaughtByCatchException() { + try { + throw new AssertionError(); + } catch (Exception e) { + Assert.fail(); // errors are not caught by catch exception + } + } + + @Test + public void whenError_thenIsCaughtByCatchError() { + try { + throw new AssertionError(); + } catch (Error e) { + // caught! -> test pass + } + } +} \ No newline at end of file From fd3e1bf293ccda51716aaba1fe7759c95ee1ab8b Mon Sep 17 00:00:00 2001 From: Dhawal Kapil Date: Mon, 3 Jun 2019 23:40:23 +0530 Subject: [PATCH 26/31] BAEL-14787 Reverted junit jupiter version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0a8eebda71..185c0a4015 100644 --- a/pom.xml +++ b/pom.xml @@ -1556,7 +1556,7 @@ 2.9.8 1.3 1.2.0 - 5.4.0 + 5.2.0 0.3.1 2.5.1 0.0.1 From 3cea8b6df16f6fd743474cce95f96cc6225094eb Mon Sep 17 00:00:00 2001 From: Rodrigo Graciano Date: Mon, 3 Jun 2019 23:34:33 -0400 Subject: [PATCH 27/31] BAEL-2936 --- .../main/java/com/baeldung/convertToMap/ConvertToMap.java | 3 +-- .../com/baeldung/convertToMap/ConvertToMapUnitTest.java | 7 +++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/java-collections-conversions/src/main/java/com/baeldung/convertToMap/ConvertToMap.java b/java-collections-conversions/src/main/java/com/baeldung/convertToMap/ConvertToMap.java index 3c14dfdba6..e33d9ee212 100644 --- a/java-collections-conversions/src/main/java/com/baeldung/convertToMap/ConvertToMap.java +++ b/java-collections-conversions/src/main/java/com/baeldung/convertToMap/ConvertToMap.java @@ -15,8 +15,7 @@ public class ConvertToMap { } public Map listToMapWithDupKey(List books) { - return books.stream().collect(Collectors.toMap(Book::getReleaseYear, Function.identity(), - (o1, o2) -> o1)); + return books.stream().collect(Collectors.toMap(Book::getReleaseYear, Function.identity(), (existing, replacement) -> existing)); } public Map listToConcurrentMap(List books) { diff --git a/java-collections-conversions/src/test/java/com/baeldung/convertToMap/ConvertToMapUnitTest.java b/java-collections-conversions/src/test/java/com/baeldung/convertToMap/ConvertToMapUnitTest.java index d11221bbf7..d6eab461d7 100644 --- a/java-collections-conversions/src/test/java/com/baeldung/convertToMap/ConvertToMapUnitTest.java +++ b/java-collections-conversions/src/test/java/com/baeldung/convertToMap/ConvertToMapUnitTest.java @@ -2,6 +2,7 @@ package com.baeldung.convertToMap; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import static org.junit.Assert.*; @@ -34,8 +35,10 @@ public class ConvertToMapUnitTest { } @Test - public void whenMapHasDuplicateKey_with_merge_function() { - assertTrue(convertToMap.listToMapWithDupKey(bookList).size() == 2); + public void whenMapHasDuplicateKeyThenMergeFunctionHandlesCollision() { + Map booksByYear = convertToMap.listToMapWithDupKey(bookList); + assertEquals(2, booksByYear.size()); + assertEquals("0395489318", booksByYear.get(1954).getIsbn()); } @Test From f6a9d02b3733d488b7172ded16562660d1918400 Mon Sep 17 00:00:00 2001 From: FrancoCorleone Date: Wed, 5 Jun 2019 06:31:00 +0200 Subject: [PATCH 28/31] [BAEL-2898] Working with XML in Groovy (#7083) --- .../baeldung/xml/MarkupBuilderUnitTest.groovy | 40 +++++++ .../com/baeldung/xml/XmlParserUnitTest.groovy | 94 ++++++++++++++++ .../baeldung/xml/XmlSlurperUnitTest.groovy | 102 ++++++++++++++++++ .../resources/com/baeldung/xml/articles.xml | 34 ++++++ .../baeldung/xml/articles_short_formatted.xml | 18 ++++ 5 files changed, 288 insertions(+) create mode 100644 core-groovy-2/src/test/groovy/com/baeldung/xml/MarkupBuilderUnitTest.groovy create mode 100644 core-groovy-2/src/test/groovy/com/baeldung/xml/XmlParserUnitTest.groovy create mode 100644 core-groovy-2/src/test/groovy/com/baeldung/xml/XmlSlurperUnitTest.groovy create mode 100644 core-groovy-2/src/test/resources/com/baeldung/xml/articles.xml create mode 100644 core-groovy-2/src/test/resources/com/baeldung/xml/articles_short_formatted.xml diff --git a/core-groovy-2/src/test/groovy/com/baeldung/xml/MarkupBuilderUnitTest.groovy b/core-groovy-2/src/test/groovy/com/baeldung/xml/MarkupBuilderUnitTest.groovy new file mode 100644 index 0000000000..c0c8c98392 --- /dev/null +++ b/core-groovy-2/src/test/groovy/com/baeldung/xml/MarkupBuilderUnitTest.groovy @@ -0,0 +1,40 @@ +package com.baeldung.xml + +import groovy.xml.MarkupBuilder +import groovy.xml.XmlUtil +import spock.lang.Specification + +class MarkupBuilderUnitTest extends Specification { + + def xmlFile = getClass().getResource("articles_short_formatted.xml") + +def "Should create XML properly"() { + given: "Node structures" + + when: "Using MarkupBuilderUnitTest to create com.baeldung.xml structure" + def writer = new StringWriter() + new MarkupBuilder(writer).articles { + article { + title('First steps in Java') + author(id: '1') { + firstname('Siena') + lastname('Kerr') + } + 'release-date'('2018-12-01') + } + article { + title('Dockerize your SpringBoot application') + author(id: '2') { + firstname('Jonas') + lastname('Lugo') + } + 'release-date'('2018-12-01') + } + } + + then: "Xml is created properly" + XmlUtil.serialize(writer.toString()) == XmlUtil.serialize(xmlFile.text) +} + + +} diff --git a/core-groovy-2/src/test/groovy/com/baeldung/xml/XmlParserUnitTest.groovy b/core-groovy-2/src/test/groovy/com/baeldung/xml/XmlParserUnitTest.groovy new file mode 100644 index 0000000000..ada47406a1 --- /dev/null +++ b/core-groovy-2/src/test/groovy/com/baeldung/xml/XmlParserUnitTest.groovy @@ -0,0 +1,94 @@ +package com.baeldung.xml + + +import spock.lang.Shared +import spock.lang.Specification + +class XmlParserUnitTest extends Specification { + + def xmlFile = getClass().getResourceAsStream("articles.xml") + + @Shared + def parser = new XmlParser() + + def "Should read XML file properly"() { + given: "XML file" + + when: "Using XmlParser to read file" + def articles = parser.parse(xmlFile) + + then: "Xml is loaded properly" + articles.'*'.size() == 4 + articles.article[0].author.firstname.text() == "Siena" + articles.article[2].'release-date'.text() == "2018-06-12" + articles.article[3].title.text() == "Java 12 insights" + articles.article.find { it.author.'@id'.text() == "3" }.author.firstname.text() == "Daniele" + } + + + def "Should add node to existing com.baeldung.xml using NodeBuilder"() { + given: "XML object" + def articles = parser.parse(xmlFile) + + when: "Adding node to com.baeldung.xml" + def articleNode = new NodeBuilder().article(id: '5') { + title('Traversing XML in the nutshell') + author { + firstname('Martin') + lastname('Schmidt') + } + 'release-date'('2019-05-18') + } + articles.append(articleNode) + + then: "Node is added to com.baeldung.xml properly" + articles.'*'.size() == 5 + articles.article[4].title.text() == "Traversing XML in the nutshell" + } + + def "Should replace node"() { + given: "XML object" + def articles = parser.parse(xmlFile) + + when: "Adding node to com.baeldung.xml" + def articleNode = new NodeBuilder().article(id: '5') { + title('Traversing XML in the nutshell') + author { + firstname('Martin') + lastname('Schmidt') + } + 'release-date'('2019-05-18') + } + articles.article[0].replaceNode(articleNode) + + then: "Node is added to com.baeldung.xml properly" + articles.'*'.size() == 4 + articles.article[0].title.text() == "Traversing XML in the nutshell" + } + + def "Should modify node"() { + given: "XML object" + def articles = parser.parse(xmlFile) + + when: "Changing value of one of the nodes" + articles.article.each { it.'release-date'[0].value = "2019-05-18" } + + then: "XML is updated" + articles.article.findAll { it.'release-date'.text() != "2019-05-18" }.isEmpty() + } + + def "Should remove article from com.baeldung.xml"() { + given: "XML object" + def articles = parser.parse(xmlFile) + + when: "Removing all articles but with id==3" + articles.article + .findAll { it.author.'@id'.text() != "3" } + .each { articles.remove(it) } + + then: "There is only one article left" + articles.children().size() == 1 + articles.article[0].author.'@id'.text() == "3" + } + +} diff --git a/core-groovy-2/src/test/groovy/com/baeldung/xml/XmlSlurperUnitTest.groovy b/core-groovy-2/src/test/groovy/com/baeldung/xml/XmlSlurperUnitTest.groovy new file mode 100644 index 0000000000..ffeaa46fce --- /dev/null +++ b/core-groovy-2/src/test/groovy/com/baeldung/xml/XmlSlurperUnitTest.groovy @@ -0,0 +1,102 @@ +package com.baeldung.xml + + +import groovy.xml.XmlUtil +import spock.lang.Shared +import spock.lang.Specification + +class XmlSlurperUnitTest extends Specification { + + def xmlFile = getClass().getResourceAsStream("articles.xml") + + @Shared + def parser = new XmlSlurper() + + def "Should read XML file properly"() { + given: "XML file" + + when: "Using XmlSlurper to read file" + def articles = parser.parse(xmlFile) + + then: "Xml is loaded properly" + articles.'*'.size() == 4 + articles.article[0].author.firstname == "Siena" + articles.article[2].'release-date' == "2018-06-12" + articles.article[3].title == "Java 12 insights" + articles.article.find { it.author.'@id' == "3" }.author.firstname == "Daniele" + } + + def "Should add node to existing com.baeldung.xml"() { + given: "XML object" + def articles = parser.parse(xmlFile) + + when: "Adding node to com.baeldung.xml" + articles.appendNode { + article(id: '5') { + title('Traversing XML in the nutshell') + author { + firstname('Martin') + lastname('Schmidt') + } + 'release-date'('2019-05-18') + } + } + + articles = parser.parseText(XmlUtil.serialize(articles)) + + then: "Node is added to com.baeldung.xml properly" + articles.'*'.size() == 5 + articles.article[4].title == "Traversing XML in the nutshell" + } + + def "Should modify node"() { + given: "XML object" + def articles = parser.parse(xmlFile) + + when: "Changing value of one of the nodes" + articles.article.each { it.'release-date' = "2019-05-18" } + + then: "XML is updated" + articles.article.findAll { it.'release-date' != "2019-05-18" }.isEmpty() + } + + def "Should replace node"() { + given: "XML object" + def articles = parser.parse(xmlFile) + + when: "Replacing node" + articles.article[0].replaceNode { + article(id: '5') { + title('Traversing XML in the nutshell') + author { + firstname('Martin') + lastname('Schmidt') + } + 'release-date'('2019-05-18') + } + } + + articles = parser.parseText(XmlUtil.serialize(articles)) + + then: "Node is replaced properly" + articles.'*'.size() == 4 + articles.article[0].title == "Traversing XML in the nutshell" + } + + def "Should remove article from com.baeldung.xml"() { + given: "XML object" + def articles = parser.parse(xmlFile) + + when: "Removing all articles but with id==3" + articles.article + .findAll { it.author.'@id' != "3" } + .replaceNode {} + + articles = parser.parseText(XmlUtil.serialize(articles)) + + then: "There is only one article left" + articles.children().size() == 1 + articles.article[0].author.'@id' == "3" + } + +} diff --git a/core-groovy-2/src/test/resources/com/baeldung/xml/articles.xml b/core-groovy-2/src/test/resources/com/baeldung/xml/articles.xml new file mode 100644 index 0000000000..ef057405f5 --- /dev/null +++ b/core-groovy-2/src/test/resources/com/baeldung/xml/articles.xml @@ -0,0 +1,34 @@ + +
+ First steps in Java + + Siena + Kerr + + 2018-12-01 +
+
+ Dockerize your SpringBoot application + + Jonas + Lugo + + 2018-12-01 +
+
+ SpringBoot tutorial + + Daniele + Ferguson + + 2018-06-12 +
+
+ Java 12 insights + + Siena + Kerr + + 2018-07-22 +
+
diff --git a/core-groovy-2/src/test/resources/com/baeldung/xml/articles_short_formatted.xml b/core-groovy-2/src/test/resources/com/baeldung/xml/articles_short_formatted.xml new file mode 100644 index 0000000000..6492020e03 --- /dev/null +++ b/core-groovy-2/src/test/resources/com/baeldung/xml/articles_short_formatted.xml @@ -0,0 +1,18 @@ + +
+ First steps in Java + + Siena + Kerr + + 2018-12-01 +
+
+ Dockerize your SpringBoot application + + Jonas + Lugo + + 2018-12-01 +
+
From 244ebb1ad131e7cfa35553eba8e891732488b3b1 Mon Sep 17 00:00:00 2001 From: Alessio Stalla Date: Wed, 5 Jun 2019 22:16:47 +0200 Subject: [PATCH 29/31] Code for BAEL-2967 --- persistence-modules/hibernate-mapping/pom.xml | 11 + .../hibernate/persistmaps/mapkey/User.java | 24 +- .../UserAdditionalValidationUnitTest.java | 294 +++++++++++++++--- pom.xml | 1 + 4 files changed, 270 insertions(+), 60 deletions(-) diff --git a/persistence-modules/hibernate-mapping/pom.xml b/persistence-modules/hibernate-mapping/pom.xml index 67eda5bf72..bb8ebdab65 100644 --- a/persistence-modules/hibernate-mapping/pom.xml +++ b/persistence-modules/hibernate-mapping/pom.xml @@ -42,6 +42,17 @@ javax.el ${org.glassfish.javax.el.version}
+ + javax.money + money-api + 1.0.3 + + + org.javamoney + moneta + 1.3 + pom + diff --git a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java index 961fc944a4..b2ee7e85fe 100644 --- a/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java +++ b/persistence-modules/hibernate-mapping/src/main/java/com/baeldung/hibernate/persistmaps/mapkey/User.java @@ -4,9 +4,11 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.validation.constraints.Size; +import javax.money.MonetaryAmount; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.CreditCardNumber; +import org.hibernate.validator.constraints.Currency; @Entity public class User { @@ -24,12 +26,6 @@ public class User { @Size(min = 3, max = 5) private String city; - @CreditCardNumber - private String creditCardNumber; - - @CreditCardNumber(ignoreNonDigitCharacters = true) - private String lenientCreditCardNumber; - public User(String firstName, String middleName, String lastName, String city) { super(); this.firstName = firstName; @@ -69,20 +65,4 @@ public class User { public void setCity(String city) { this.city = city; } - - public String getCreditCardNumber() { - return creditCardNumber; - } - - public void setCreditCardNumber(String creditCardNumber) { - this.creditCardNumber = creditCardNumber; - } - - public String getLenientCreditCardNumber() { - return lenientCreditCardNumber; - } - - public void setLenientCreditCardNumber(String lenientCreditCardNumber) { - this.lenientCreditCardNumber = lenientCreditCardNumber; - } } diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserAdditionalValidationUnitTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserAdditionalValidationUnitTest.java index aaf52fe765..0f2a0403e9 100644 --- a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserAdditionalValidationUnitTest.java +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/validation/UserAdditionalValidationUnitTest.java @@ -1,72 +1,290 @@ package com.baeldung.hibernate.validation; -import com.baeldung.hibernate.HibernateUtil; -import com.baeldung.hibernate.Strategy; -import com.baeldung.hibernate.persistmaps.mapkey.User; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import javax.persistence.PersistenceException; -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; -import java.util.Set; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.math.BigDecimal; +import java.time.Duration; +import java.util.Set; + +import javax.money.CurrencyContextBuilder; +import javax.money.Monetary; +import javax.money.MonetaryAmount; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +import org.hibernate.validator.constraints.CodePointLength; +import org.hibernate.validator.constraints.CreditCardNumber; +import org.hibernate.validator.constraints.Currency; +import org.hibernate.validator.constraints.Length; +import org.hibernate.validator.constraints.LuhnCheck; +import org.hibernate.validator.constraints.Range; +import org.hibernate.validator.constraints.SafeHtml; +import org.hibernate.validator.constraints.ScriptAssert; +import org.hibernate.validator.constraints.URL; +import org.hibernate.validator.constraints.time.DurationMax; +import org.hibernate.validator.constraints.time.DurationMin; +import org.javamoney.moneta.CurrencyUnitBuilder; +import org.javamoney.moneta.Money; +import org.junit.BeforeClass; +import org.junit.Test; + public class UserAdditionalValidationUnitTest { private static Validator validator; - private static SessionFactory sessionFactory; - private Session session; - private Set> constraintViolations; + private Set> constraintViolations; @BeforeClass public static void before() { ValidatorFactory config = Validation.buildDefaultValidatorFactory(); validator = config.getValidator(); - sessionFactory = HibernateUtil.getSessionFactory(Strategy.MAP_KEY_BASED); - } - - @Before - public void setUp() { - session = sessionFactory.openSession(); - session.beginTransaction(); } @Test public void whenValidationWithCCNAndNullCCN_thenNoConstraintViolation() { - User user = new User("John", "Paul", "Butler", "York"); - constraintViolations = validator.validateProperty(user, "creditCardNumber"); + AdditionalValidations validations = new AdditionalValidations(); + constraintViolations = validator.validateProperty(validations, "creditCardNumber"); assertTrue(constraintViolations.isEmpty()); } @Test public void whenValidationWithCCNAndValidCCN_thenNoConstraintViolation() { - User user = new User("John", "Paul", "Butler", "York"); - user.setCreditCardNumber("79927398713"); - constraintViolations = validator.validateProperty(user, "creditCardNumber"); + AdditionalValidations validations = new AdditionalValidations(); + validations.setCreditCardNumber("79927398713"); + constraintViolations = validator.validateProperty(validations, "creditCardNumber"); assertTrue(constraintViolations.isEmpty()); } @Test public void whenValidationWithCCNAndInvalidCCN_thenConstraintViolation() { - User user = new User("John", "Paul", "Butler", "York"); - user.setCreditCardNumber("79927398714"); - constraintViolations = validator.validateProperty(user, "creditCardNumber"); - assertEquals(constraintViolations.size(), 1); + AdditionalValidations validations = new AdditionalValidations(); + validations.setCreditCardNumber("79927398714"); + constraintViolations = validator.validateProperty(validations, "creditCardNumber"); + assertEquals(constraintViolations.size(), 2); + } + + @Test + public void whenValidationWithCCNAndValidCCNWithDashes_thenConstraintViolation() { + AdditionalValidations validations = new AdditionalValidations(); + validations.setCreditCardNumber("7992-7398-713"); + constraintViolations = validator.validateProperty(validations, "creditCardNumber"); + assertEquals(1, constraintViolations.size()); } @Test public void whenValidationWithLenientCCNAndValidCCNWithDashes_thenNoConstraintViolation() { - User user = new User("John", "Paul", "Butler", "York"); - user.setLenientCreditCardNumber("7992-7398-713"); - constraintViolations = validator.validateProperty(user, "lenientCreditCardNumber"); + AdditionalValidations validations = new AdditionalValidations(); + validations.setLenientCreditCardNumber("7992-7398-713"); + constraintViolations = validator.validateProperty(validations, "lenientCreditCardNumber"); assertTrue(constraintViolations.isEmpty()); } + + @Test + public void whenMonetaryAmountWithRightCurrency_thenNoConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + bean.setBalance(Money.of(new BigDecimal(100.0), Monetary.getCurrency("EUR"))); + constraintViolations = validator.validateProperty(bean, "balance"); + assertEquals(0, constraintViolations.size()); + } + + @Test + public void whenMonetaryAmountWithWrongCurrency_thenConstraintViolation() { + AdditionalValidations validations = new AdditionalValidations(); + validations.setBalance(Money.of(new BigDecimal(100.0), Monetary.getCurrency("USD"))); + constraintViolations = validator.validateProperty(validations, "balance"); + assertEquals(1, constraintViolations.size()); + } + + @Test + public void whenDurationShorterThanMin_thenConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + bean.setDuration(Duration.ofDays(1).plusHours(1)); + constraintViolations = validator.validateProperty(bean, "duration"); + assertEquals(1, constraintViolations.size()); + } + + @Test + public void whenDurationLongerThanMax_thenConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + bean.setDuration(Duration.ofDays(2).plusHours(3)); + constraintViolations = validator.validateProperty(bean, "duration"); + assertEquals(1, constraintViolations.size()); + } + + @Test + public void whenDurationBetweenMinAndMax_thenNoConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + bean.setDuration(Duration.ofDays(2)); + constraintViolations = validator.validateProperty(bean, "duration"); + assertEquals(0, constraintViolations.size()); + } + + @Test + public void whenValueBelowRangeMin_thenConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + bean.setPercent(new BigDecimal("-1.4")); + constraintViolations = validator.validateProperty(bean, "percent"); + assertEquals(1, constraintViolations.size()); + } + + @Test + public void whenValueAboveRangeMax_thenConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + bean.setPercent(new BigDecimal("100.03")); + constraintViolations = validator.validateProperty(bean, "percent"); + assertEquals(1, constraintViolations.size()); + } + + @Test + public void whenValueInRange_thenNoConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + bean.setPercent(new BigDecimal("53.23")); + constraintViolations = validator.validateProperty(bean, "percent"); + assertEquals(0, constraintViolations.size()); + } + + @Test + public void whenLengthInRange_thenNoConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + bean.setSomeString("aaa"); + constraintViolations = validator.validateProperty(bean, "someString"); + assertEquals(0, constraintViolations.size()); + } + + @Test + public void whenCodePointLengthNotInRange_thenConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + bean.setSomeString("aa\uD835\uDD0A"); + constraintViolations = validator.validateProperty(bean, "someString"); + assertEquals(1, constraintViolations.size()); + } + + @Test + public void whenValidUrlWithWrongProtocol_thenConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + + bean.setUrl("https://www.google.com/"); + constraintViolations = validator.validateProperty(bean, "url"); + assertEquals(0, constraintViolations.size()); + + bean.setUrl("http://www.google.com/"); + constraintViolations = validator.validateProperty(bean, "url"); + assertEquals(1, constraintViolations.size()); + + bean.setUrl("https://foo:bar"); + constraintViolations = validator.validateProperty(bean, "url"); + assertEquals(1, constraintViolations.size()); + } + + @Test + public void whenScriptAssertFails_thenConstraintViolation() { + AdditionalValidations bean = new AdditionalValidations(); + + constraintViolations = validator.validate(bean); + assertEquals(0, constraintViolations.size()); + + bean.setValid(false); + + constraintViolations = validator.validate(bean); + assertEquals(1, constraintViolations.size()); + + constraintViolations = validator.validateProperty(bean, "valid"); + assertEquals(0, constraintViolations.size()); + } + + @ScriptAssert(lang = "nashorn", script = "_this.valid") + public class AdditionalValidations { + private boolean valid = true; + + @CreditCardNumber + @LuhnCheck(startIndex = 0, endIndex = Integer.MAX_VALUE, checkDigitIndex = -1) + private String creditCardNumber; + + @CreditCardNumber(ignoreNonDigitCharacters = true) + private String lenientCreditCardNumber; + + @Currency("EUR") + private MonetaryAmount balance; + + @DurationMin(days = 1, hours = 2) + @DurationMax(days = 2, hours = 1) + private Duration duration; + + @Range(min = 0, max = 100) + private BigDecimal percent; + + @Length(min = 1, max = 3) + @CodePointLength(min = 1, max = 3) + private String someString; + + @URL(protocol = "https") + private String url; + + public String getCreditCardNumber() { + return creditCardNumber; + } + + public void setCreditCardNumber(String creditCardNumber) { + this.creditCardNumber = creditCardNumber; + } + + public String getLenientCreditCardNumber() { + return lenientCreditCardNumber; + } + + public void setLenientCreditCardNumber(String lenientCreditCardNumber) { + this.lenientCreditCardNumber = lenientCreditCardNumber; + } + + public MonetaryAmount getBalance() { + return balance; + } + + public void setBalance(MonetaryAmount balance) { + this.balance = balance; + } + + public Duration getDuration() { + return duration; + } + + public void setDuration(Duration duration) { + this.duration = duration; + } + + public BigDecimal getPercent() { + return percent; + } + + public void setPercent(BigDecimal percent) { + this.percent = percent; + } + + public String getSomeString() { + return someString; + } + + public void setSomeString(String someString) { + this.someString = someString; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public boolean isValid() { + return valid; + } + + public void setValid(boolean valid) { + this.valid = valid; + } + + } } diff --git a/pom.xml b/pom.xml index 03d2e5d763..b9f9f636d3 100644 --- a/pom.xml +++ b/pom.xml @@ -921,6 +921,7 @@ spring-vault spring-vertx spring-zuul/spring-zuul-foos-resource + persistence-modules/hibernate-mapping persistence-modules/spring-data-dynamodb persistence-modules/spring-data-eclipselink persistence-modules/spring-data-solr From cf68c5c771fdc3a8d7ec057857ab83749e61f3ee Mon Sep 17 00:00:00 2001 From: DOHA Date: Thu, 6 Jun 2019 14:46:56 +0200 Subject: [PATCH 30/31] upgrade spring security cloud --- .../spring-cloud-security/auth-client/pom.xml | 16 ++++++++++------ .../src/main/resources/application.properties | 0 .../src/main/resources/application.yml | 4 +++- .../spring-cloud-security/auth-resource/pom.xml | 8 +++++--- .../com/baeldung/config/ResourceConfigurer.java | 11 +++++++---- .../src/main/resources/application.yml | 1 - .../spring-cloud-security/auth-server/pom.xml | 2 +- .../baeldung/config/AuthServerConfigurer.java | 12 +++++++----- .../{WebMvcConfigurer.java => WebMvcConfig.java} | 4 ++-- .../baeldung/config/WebSecurityConfigurer.java | 8 ++++++-- .../src/main/resources/application.yml | 12 +++--------- spring-cloud/spring-cloud-security/pom.xml | 4 ++-- 12 files changed, 46 insertions(+), 36 deletions(-) delete mode 100644 spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.properties rename spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/{WebMvcConfigurer.java => WebMvcConfig.java} (83%) diff --git a/spring-cloud/spring-cloud-security/auth-client/pom.xml b/spring-cloud/spring-cloud-security/auth-client/pom.xml index 4f64f470f0..4152552640 100644 --- a/spring-cloud/spring-cloud-security/auth-client/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-client/pom.xml @@ -24,7 +24,7 @@ org.springframework.cloud - spring-cloud-starter-zuul + spring-cloud-starter-netflix-zuul org.springframework.boot @@ -34,14 +34,16 @@ org.webjars jquery + ${jquery.version} org.webjars bootstrap + ${bootstrap.version} org.webjars - webjars-locator + webjars-locator-core org.springframework.boot @@ -62,8 +64,8 @@ spring-boot-starter-thymeleaf - org.springframework.security.oauth - spring-security-oauth2 + org.springframework.security.oauth.boot + spring-security-oauth2-autoconfigure @@ -89,8 +91,10 @@ - 2.1.0 - Dalston.SR4 + 2.2.0 + Greenwich.SR1 + 3.4.1 + 4.3.1 diff --git a/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.properties b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.properties deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml index 2a758faeae..69617555d9 100644 --- a/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml +++ b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml @@ -2,7 +2,8 @@ # These are default settings, but we add them for clarity. server: port: 8080 - contextPath: / + servlet: + context-path: / # Configure the Authorization Server and User Info Resource Server details security: @@ -21,6 +22,7 @@ person: # Proxies the calls to http://localhost:8080/api/* to our REST service at http://localhost:8081/* # and automatically includes our OAuth2 token in the request headers zuul: + sensitiveHeaders: Cookie,Set-Cookie routes: resource: path: /api/** diff --git a/spring-cloud/spring-cloud-security/auth-resource/pom.xml b/spring-cloud/spring-cloud-security/auth-resource/pom.xml index 22ee0528c3..a60eca740c 100644 --- a/spring-cloud/spring-cloud-security/auth-resource/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-resource/pom.xml @@ -19,8 +19,8 @@ spring-boot-starter-web - org.springframework.security.oauth - spring-security-oauth2 + org.springframework.security.oauth.boot + spring-security-oauth2-autoconfigure org.springframework.boot @@ -30,6 +30,7 @@ org.springframework.security spring-security-jwt + ${spring-jwt.version} @@ -55,7 +56,8 @@ - Edgware.RELEASE + Greenwich.SR1 + 1.0.10.RELEASE diff --git a/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java index 977d74093a..abe942325f 100644 --- a/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java +++ b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java @@ -3,7 +3,7 @@ package com.baeldung.config; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; @@ -11,15 +11,18 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.R * REST API Resource Server. */ @Configuration -@EnableWebSecurity @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true) // Allow method annotations like @PreAuthorize public class ResourceConfigurer extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { - http.httpBasic().disable(); - http.authorizeRequests().anyRequest().authenticated(); + http.sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.NEVER) + .and() + .authorizeRequests() + .anyRequest().authenticated(); + } } diff --git a/spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml index 52e02ba41b..35063a7879 100644 --- a/spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml +++ b/spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml @@ -5,7 +5,6 @@ server: # Configure the public key to use for verifying the incoming JWT tokens security: - sessions: NEVER oauth2: resource: jwt: diff --git a/spring-cloud/spring-cloud-security/auth-server/pom.xml b/spring-cloud/spring-cloud-security/auth-server/pom.xml index 4b3f94b825..afd8dbef44 100644 --- a/spring-cloud/spring-cloud-security/auth-server/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-server/pom.xml @@ -38,7 +38,7 @@ - 1.1.2.RELEASE + 2.1.2.RELEASE \ No newline at end of file diff --git a/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java index 32e445f998..7c9ee9ae18 100644 --- a/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java +++ b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java @@ -9,6 +9,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.core.io.Resource; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; @@ -19,9 +20,7 @@ import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFacto @Configuration @EnableAuthorizationServer @Order(6) -public class AuthServerConfigurer - extends - AuthorizationServerConfigurerAdapter { +public class AuthServerConfigurer extends AuthorizationServerConfigurerAdapter { @Value("${jwt.certificate.store.file}") private Resource keystore; @@ -37,6 +36,9 @@ public class AuthServerConfigurer @Autowired private UserDetailsService userDetailsService; + + @Autowired + private BCryptPasswordEncoder passwordEncoder; @Override public void configure( @@ -45,8 +47,8 @@ public class AuthServerConfigurer clients .inMemory() .withClient("authserver") - .secret("passwordforauthserver") - .redirectUris("http://localhost:8080/") + .secret(passwordEncoder.encode("passwordforauthserver")) + .redirectUris("http://localhost:8080/login") .authorizedGrantTypes("authorization_code", "refresh_token") .scopes("myscope") diff --git a/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfig.java similarity index 83% rename from spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfig.java index 23b56151e7..3cefd323b3 100644 --- a/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfigurer.java +++ b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfig.java @@ -2,10 +2,10 @@ package com.baeldung.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration -public class WebMvcConfigurer extends WebMvcConfigurerAdapter { +public class WebMvcConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { diff --git a/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java index 44406b8fa0..6a48c62097 100644 --- a/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java +++ b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java @@ -6,8 +6,8 @@ import org.springframework.security.config.annotation.authentication.builders.Au import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; @Configuration @@ -34,7 +34,7 @@ public class WebSecurityConfigurer AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() - .withUser("user").password("user") + .withUser("user").password(passwordEncoder().encode("user")) .roles("USER") .and() .withUser("admin").password("admin") @@ -48,5 +48,9 @@ public class WebSecurityConfigurer return super.userDetailsServiceBean(); } + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } } diff --git a/spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml index 1dc63d3f0e..b6e385e5c7 100644 --- a/spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml +++ b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml @@ -1,7 +1,8 @@ # Make the application available at http://localhost:7070/authserver server: port: 7070 - contextPath: /authserver + servlet: + context-path: /authserver # Our certificate settings for enabling JWT tokens jwt: @@ -11,11 +12,4 @@ jwt: password: abirkhan04 key: alias: myauthkey - password: abirkhan04 - - -security: - oauth2: - resource: - filter-order: 3 - \ No newline at end of file + password: abirkhan04 \ No newline at end of file diff --git a/spring-cloud/spring-cloud-security/pom.xml b/spring-cloud/spring-cloud-security/pom.xml index 2eecf579a5..d65fd6520b 100644 --- a/spring-cloud/spring-cloud-security/pom.xml +++ b/spring-cloud/spring-cloud-security/pom.xml @@ -8,10 +8,10 @@ pom - parent-boot-1 + parent-boot-2 com.baeldung 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../parent-boot-2 From 0ece18c76608bc841e5b9ad969d94f8c3e7c5bb6 Mon Sep 17 00:00:00 2001 From: Amy DeGregorio Date: Fri, 7 Jun 2019 07:54:00 -0400 Subject: [PATCH 31/31] Bael 2979 Guide to Crawler4j (#7071) * BAEL-2727 Example Code * BAEL-2979 Guide to Crawler4j * BAEL-2979 adjust based on feedback --- libraries-2/pom.xml | 6 +++ .../baeldung/crawler4j/CrawlerStatistics.java | 22 ++++++++ .../com/baeldung/crawler4j/HtmlCrawler.java | 48 +++++++++++++++++ .../crawler4j/HtmlCrawlerController.java | 36 +++++++++++++ .../com/baeldung/crawler4j/ImageCrawler.java | 49 +++++++++++++++++ .../crawler4j/ImageCrawlerController.java | 36 +++++++++++++ .../crawler4j/MultipleCrawlerController.java | 54 +++++++++++++++++++ 7 files changed, 251 insertions(+) create mode 100644 libraries-2/src/main/java/com/baeldung/crawler4j/CrawlerStatistics.java create mode 100644 libraries-2/src/main/java/com/baeldung/crawler4j/HtmlCrawler.java create mode 100644 libraries-2/src/main/java/com/baeldung/crawler4j/HtmlCrawlerController.java create mode 100644 libraries-2/src/main/java/com/baeldung/crawler4j/ImageCrawler.java create mode 100644 libraries-2/src/main/java/com/baeldung/crawler4j/ImageCrawlerController.java create mode 100644 libraries-2/src/main/java/com/baeldung/crawler4j/MultipleCrawlerController.java diff --git a/libraries-2/pom.xml b/libraries-2/pom.xml index 6303c0cab5..218bb437cb 100644 --- a/libraries-2/pom.xml +++ b/libraries-2/pom.xml @@ -55,6 +55,11 @@ spring-boot-starter ${spring-boot-starter.version} + + edu.uci.ics + crawler4j + ${crawler4j.version} + @@ -62,6 +67,7 @@ 4.8.28 6.0.0.Final 3.9.6 + 4.4.0 2.1.4.RELEASE diff --git a/libraries-2/src/main/java/com/baeldung/crawler4j/CrawlerStatistics.java b/libraries-2/src/main/java/com/baeldung/crawler4j/CrawlerStatistics.java new file mode 100644 index 0000000000..e3237a2755 --- /dev/null +++ b/libraries-2/src/main/java/com/baeldung/crawler4j/CrawlerStatistics.java @@ -0,0 +1,22 @@ +package com.baeldung.crawler4j; + +public class CrawlerStatistics { + private int processedPageCount = 0; + private int totalLinksCount = 0; + + public void incrementProcessedPageCount() { + processedPageCount++; + } + + public void incrementTotalLinksCount(int linksCount) { + totalLinksCount += linksCount; + } + + public int getProcessedPageCount() { + return processedPageCount; + } + + public int getTotalLinksCount() { + return totalLinksCount; + } +} diff --git a/libraries-2/src/main/java/com/baeldung/crawler4j/HtmlCrawler.java b/libraries-2/src/main/java/com/baeldung/crawler4j/HtmlCrawler.java new file mode 100644 index 0000000000..b77e1e075f --- /dev/null +++ b/libraries-2/src/main/java/com/baeldung/crawler4j/HtmlCrawler.java @@ -0,0 +1,48 @@ +package com.baeldung.crawler4j; + +import java.util.Set; +import java.util.regex.Pattern; + +import edu.uci.ics.crawler4j.crawler.Page; +import edu.uci.ics.crawler4j.crawler.WebCrawler; +import edu.uci.ics.crawler4j.parser.HtmlParseData; +import edu.uci.ics.crawler4j.url.WebURL; + +public class HtmlCrawler extends WebCrawler { + + private final static Pattern EXCLUSIONS = Pattern.compile(".*(\\.(css|js|xml|gif|jpg|png|mp3|mp4|zip|gz|pdf))$"); + + private CrawlerStatistics stats; + + public HtmlCrawler(CrawlerStatistics stats) { + this.stats = stats; + } + + @Override + public boolean shouldVisit(Page referringPage, WebURL url) { + String urlString = url.getURL().toLowerCase(); + return !EXCLUSIONS.matcher(urlString).matches() + && urlString.startsWith("https://www.baeldung.com/"); + } + + @Override + public void visit(Page page) { + String url = page.getWebURL().getURL(); + stats.incrementProcessedPageCount(); + + if (page.getParseData() instanceof HtmlParseData) { + HtmlParseData htmlParseData = (HtmlParseData) page.getParseData(); + String title = htmlParseData.getTitle(); + String text = htmlParseData.getText(); + String html = htmlParseData.getHtml(); + Set links = htmlParseData.getOutgoingUrls(); + stats.incrementTotalLinksCount(links.size()); + + System.out.printf("Page with title '%s' %n", title); + System.out.printf(" Text length: %d %n", text.length()); + System.out.printf(" HTML length: %d %n", html.length()); + System.out.printf(" %d outbound links %n", links.size()); + } + } + +} diff --git a/libraries-2/src/main/java/com/baeldung/crawler4j/HtmlCrawlerController.java b/libraries-2/src/main/java/com/baeldung/crawler4j/HtmlCrawlerController.java new file mode 100644 index 0000000000..82c1c6bdd7 --- /dev/null +++ b/libraries-2/src/main/java/com/baeldung/crawler4j/HtmlCrawlerController.java @@ -0,0 +1,36 @@ +package com.baeldung.crawler4j; + +import java.io.File; + +import edu.uci.ics.crawler4j.crawler.CrawlConfig; +import edu.uci.ics.crawler4j.crawler.CrawlController; +import edu.uci.ics.crawler4j.fetcher.PageFetcher; +import edu.uci.ics.crawler4j.robotstxt.RobotstxtConfig; +import edu.uci.ics.crawler4j.robotstxt.RobotstxtServer; + +public class HtmlCrawlerController { + + public static void main(String[] args) throws Exception { + File crawlStorage = new File("src/test/resources/crawler4j"); + CrawlConfig config = new CrawlConfig(); + config.setCrawlStorageFolder(crawlStorage.getAbsolutePath()); + config.setMaxDepthOfCrawling(2); + + int numCrawlers = 12; + + PageFetcher pageFetcher = new PageFetcher(config); + RobotstxtConfig robotstxtConfig = new RobotstxtConfig(); + RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcher); + CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer); + + controller.addSeed("https://www.baeldung.com/"); + + CrawlerStatistics stats = new CrawlerStatistics(); + CrawlController.WebCrawlerFactory factory = () -> new HtmlCrawler(stats); + + controller.start(factory, numCrawlers); + System.out.printf("Crawled %d pages %n", stats.getProcessedPageCount()); + System.out.printf("Total Number of outbound links = %d %n", stats.getTotalLinksCount()); + } + +} diff --git a/libraries-2/src/main/java/com/baeldung/crawler4j/ImageCrawler.java b/libraries-2/src/main/java/com/baeldung/crawler4j/ImageCrawler.java new file mode 100644 index 0000000000..ebb5d96f36 --- /dev/null +++ b/libraries-2/src/main/java/com/baeldung/crawler4j/ImageCrawler.java @@ -0,0 +1,49 @@ +package com.baeldung.crawler4j; + +import java.io.File; +import java.util.regex.Pattern; + +import edu.uci.ics.crawler4j.crawler.Page; +import edu.uci.ics.crawler4j.crawler.WebCrawler; +import edu.uci.ics.crawler4j.parser.BinaryParseData; +import edu.uci.ics.crawler4j.url.WebURL; + +public class ImageCrawler extends WebCrawler { + private final static Pattern EXCLUSIONS = Pattern.compile(".*(\\.(css|js|xml|gif|png|mp3|mp4|zip|gz|pdf))$"); + + private static final Pattern IMG_PATTERNS = Pattern.compile(".*(\\.(jpg|jpeg))$"); + + private File saveDir; + + public ImageCrawler(File saveDir) { + this.saveDir = saveDir; + } + + @Override + public boolean shouldVisit(Page referringPage, WebURL url) { + String urlString = url.getURL().toLowerCase(); + if (EXCLUSIONS.matcher(urlString).matches()) { + return false; + } + + if (IMG_PATTERNS.matcher(urlString).matches() + || urlString.startsWith("https://www.baeldung.com/")) { + return true; + } + + return false; + } + + @Override + public void visit(Page page) { + String url = page.getWebURL().getURL(); + if (IMG_PATTERNS.matcher(url).matches() + && page.getParseData() instanceof BinaryParseData) { + String extension = url.substring(url.lastIndexOf(".")); + int contentLength = page.getContentData().length; + + System.out.printf("Extension is '%s' with content length %d %n", extension, contentLength); + } + } + +} diff --git a/libraries-2/src/main/java/com/baeldung/crawler4j/ImageCrawlerController.java b/libraries-2/src/main/java/com/baeldung/crawler4j/ImageCrawlerController.java new file mode 100644 index 0000000000..9db32f1bfb --- /dev/null +++ b/libraries-2/src/main/java/com/baeldung/crawler4j/ImageCrawlerController.java @@ -0,0 +1,36 @@ +package com.baeldung.crawler4j; + +import java.io.File; + +import edu.uci.ics.crawler4j.crawler.CrawlConfig; +import edu.uci.ics.crawler4j.crawler.CrawlController; +import edu.uci.ics.crawler4j.fetcher.PageFetcher; +import edu.uci.ics.crawler4j.robotstxt.RobotstxtConfig; +import edu.uci.ics.crawler4j.robotstxt.RobotstxtServer; + +public class ImageCrawlerController { + + public static void main(String[] args) throws Exception { + File crawlStorage = new File("src/test/resources/crawler4j"); + CrawlConfig config = new CrawlConfig(); + config.setCrawlStorageFolder(crawlStorage.getAbsolutePath()); + config.setIncludeBinaryContentInCrawling(true); + config.setMaxPagesToFetch(500); + + File saveDir = new File("src/test/resources/crawler4j"); + + int numCrawlers = 12; + + PageFetcher pageFetcher = new PageFetcher(config); + RobotstxtConfig robotstxtConfig = new RobotstxtConfig(); + RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcher); + CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer); + + controller.addSeed("https://www.baeldung.com/"); + + CrawlController.WebCrawlerFactory factory = () -> new ImageCrawler(saveDir); + + controller.start(factory, numCrawlers); + } + +} diff --git a/libraries-2/src/main/java/com/baeldung/crawler4j/MultipleCrawlerController.java b/libraries-2/src/main/java/com/baeldung/crawler4j/MultipleCrawlerController.java new file mode 100644 index 0000000000..7662607f80 --- /dev/null +++ b/libraries-2/src/main/java/com/baeldung/crawler4j/MultipleCrawlerController.java @@ -0,0 +1,54 @@ +package com.baeldung.crawler4j; + +import java.io.File; + +import edu.uci.ics.crawler4j.crawler.CrawlConfig; +import edu.uci.ics.crawler4j.crawler.CrawlController; +import edu.uci.ics.crawler4j.fetcher.PageFetcher; +import edu.uci.ics.crawler4j.robotstxt.RobotstxtConfig; +import edu.uci.ics.crawler4j.robotstxt.RobotstxtServer; + +public class MultipleCrawlerController { + public static void main(String[] args) throws Exception { + File crawlStorageBase = new File("src/test/resources/crawler4j"); + CrawlConfig htmlConfig = new CrawlConfig(); + CrawlConfig imageConfig = new CrawlConfig(); + + htmlConfig.setCrawlStorageFolder(new File(crawlStorageBase, "html").getAbsolutePath()); + imageConfig.setCrawlStorageFolder(new File(crawlStorageBase, "image").getAbsolutePath()); + imageConfig.setIncludeBinaryContentInCrawling(true); + + htmlConfig.setMaxPagesToFetch(500); + imageConfig.setMaxPagesToFetch(1000); + + PageFetcher pageFetcherHtml = new PageFetcher(htmlConfig); + PageFetcher pageFetcherImage = new PageFetcher(imageConfig); + + RobotstxtConfig robotstxtConfig = new RobotstxtConfig(); + RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcherHtml); + + CrawlController htmlController = new CrawlController(htmlConfig, pageFetcherHtml, robotstxtServer); + CrawlController imageController = new CrawlController(imageConfig, pageFetcherImage, robotstxtServer); + + htmlController.addSeed("https://www.baeldung.com/"); + imageController.addSeed("https://www.baeldung.com/"); + + CrawlerStatistics stats = new CrawlerStatistics(); + CrawlController.WebCrawlerFactory htmlFactory = () -> new HtmlCrawler(stats); + + File saveDir = new File("src/test/resources/crawler4j"); + CrawlController.WebCrawlerFactory imageFactory = () -> new ImageCrawler(saveDir); + + imageController.startNonBlocking(imageFactory, 7); + htmlController.startNonBlocking(htmlFactory, 10); + + + htmlController.waitUntilFinish(); + System.out.printf("Crawled %d pages %n", stats.getProcessedPageCount()); + System.out.printf("Total Number of outbound links = %d %n", stats.getTotalLinksCount()); + + imageController.waitUntilFinish(); + System.out.printf("Image Crawler is finished."); + + } +}