diff --git a/core-java-modules/core-java-io-3/src/test/java/com/baeldung/createfile/CreateFileUnitTest.java b/core-java-modules/core-java-io-3/src/test/java/com/baeldung/createfile/CreateFileUnitTest.java
index f3cdb22f4d..f26a1ab3ad 100644
--- a/core-java-modules/core-java-io-3/src/test/java/com/baeldung/createfile/CreateFileUnitTest.java
+++ b/core-java-modules/core-java-io-3/src/test/java/com/baeldung/createfile/CreateFileUnitTest.java
@@ -6,6 +6,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -37,6 +38,12 @@ public class CreateFileUnitTest {
assertTrue(success);
}
+ @Test
+ void givenUsingFileOutputStream_whenCreatingFile_thenCorrect() throws IOException {
+ try(FileOutputStream fileOutputStream = new FileOutputStream(FILE_NAME)){
+ }
+ }
+
@Test
public void givenUsingGuava_whenCreatingFile_thenCorrect() throws IOException {
com.google.common.io.Files.touch(new File(FILE_NAME));
diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/arguments/DefaultArguments.kt b/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/arguments/DefaultArguments.kt
new file mode 100644
index 0000000000..691b3475b4
--- /dev/null
+++ b/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/arguments/DefaultArguments.kt
@@ -0,0 +1,37 @@
+package com.baeldung.arguments
+
+fun main() {
+
+ // Skip both the connectTimeout and enableRetry arguments
+ connect("http://www.baeldung.com")
+
+ // Skip only the enableRetry argument:
+ connect("http://www.baeldung.com", 5000)
+
+ // Skip only the middle argument connectTimeout
+ // connect("http://www.baeldung.com", false) // This results in a compiler error
+
+ // Because we skipped the connectTimeout argument, we must pass the enableRetry as a named argument
+ connect("http://www.baeldung.com", enableRetry = false)
+
+ // Overriding Functions and Default Arguments
+ val realConnector = RealConnector()
+ realConnector.connect("www.baeldung.com")
+ realConnector.connect()
+}
+
+fun connect(url: String, connectTimeout: Int = 1000, enableRetry: Boolean = true) {
+ println("The parameters are url = $url, connectTimeout = $connectTimeout, enableRetry = $enableRetry")
+}
+
+open class AbstractConnector {
+ open fun connect(url: String = "localhost") {
+ // function implementation
+ }
+}
+
+class RealConnector : AbstractConnector() {
+ override fun connect(url: String) {
+ println("The parameter is url = $url")
+ }
+}
\ No newline at end of file
diff --git a/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/arguments/NamedArguments.kt b/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/arguments/NamedArguments.kt
new file mode 100644
index 0000000000..0cbf6f158a
--- /dev/null
+++ b/core-kotlin-modules/core-kotlin/src/main/kotlin/com/baeldung/arguments/NamedArguments.kt
@@ -0,0 +1,28 @@
+package com.baeldung.arguments
+
+fun main() {
+ resizePane(newSize = 10, forceResize = true, noAnimation = false)
+
+ // Swap the order of last two named arguments
+ resizePane(newSize = 11, noAnimation = false, forceResize = true)
+
+ // Named arguments can be passed in any order
+ resizePane(forceResize = true, newSize = 12, noAnimation = false)
+
+ // Mixing Named and Positional Arguments
+ // Kotlin 1.3 would allow us to name only the arguments after the positional ones
+ resizePane(20, true, noAnimation = false)
+
+ // Using a positional argument in the middle of named arguments (supported from Kotlin 1.4.0)
+ // resizePane(newSize = 20, true, noAnimation = false)
+
+ // Only the last argument as a positional argument (supported from Kotlin 1.4.0)
+ // resizePane(newSize = 30, forceResize = true, false)
+
+ // Use a named argument in the middle of positional arguments (supported from Kotlin 1.4.0)
+ // resizePane(40, forceResize = true, false)
+}
+
+fun resizePane(newSize: Int, forceResize: Boolean, noAnimation: Boolean) {
+ println("The parameters are newSize = $newSize, forceResize = $forceResize, noAnimation = $noAnimation")
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index ac1a16a728..cba7e33b03 100644
--- a/pom.xml
+++ b/pom.xml
@@ -977,7 +977,7 @@
jjwt
jmeter
jmh
- jni
+ java-native
jooby
jsf
json
diff --git a/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/EmployeeApplication.java b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/EmployeeApplication.java
new file mode 100644
index 0000000000..17c7af858b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/EmployeeApplication.java
@@ -0,0 +1,19 @@
+package com.baeldung.annotations;
+
+import com.baeldung.annotations.componentscanautoconfigure.teacher.Teacher;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+
+@ComponentScan(basePackages = {"com.baeldung.annotations.componentscanautoconfigure.healthcare",
+ "com.baeldung.annotations.componentscanautoconfigure.employee"},
+ basePackageClasses = Teacher.class)
+@EnableAutoConfiguration(exclude = {JdbcTemplateAutoConfiguration.class})
+//@EnableAutoConfiguration(excludeName = {"org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration"})
+public class EmployeeApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(EmployeeApplication.class, args);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/employee/Employee.java b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/employee/Employee.java
new file mode 100644
index 0000000000..9be3388046
--- /dev/null
+++ b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/employee/Employee.java
@@ -0,0 +1,12 @@
+package com.baeldung.annotations.componentscanautoconfigure.employee;
+
+import org.springframework.stereotype.Component;
+
+@Component("employee")
+public class Employee {
+
+ @Override
+ public String toString() {
+ return "Employee" + this.hashCode();
+ }
+}
diff --git a/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/employee/SeniorEmployee.java b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/employee/SeniorEmployee.java
new file mode 100644
index 0000000000..242e84f887
--- /dev/null
+++ b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/employee/SeniorEmployee.java
@@ -0,0 +1,12 @@
+package com.baeldung.annotations.componentscanautoconfigure.employee;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class SeniorEmployee {
+
+ @Override
+ public String toString() {
+ return "Senior Employee" + this.hashCode();
+ }
+}
diff --git a/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/healthcare/Doctor.java b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/healthcare/Doctor.java
new file mode 100644
index 0000000000..7e7e6cb03b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/healthcare/Doctor.java
@@ -0,0 +1,9 @@
+package com.baeldung.annotations.componentscanautoconfigure.healthcare;
+
+public class Doctor {
+
+ @Override
+ public String toString() {
+ return "Doctor" + this.hashCode();
+ }
+}
diff --git a/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/healthcare/Hospital.java b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/healthcare/Hospital.java
new file mode 100644
index 0000000000..0711544060
--- /dev/null
+++ b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/healthcare/Hospital.java
@@ -0,0 +1,13 @@
+package com.baeldung.annotations.componentscanautoconfigure.healthcare;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class Hospital {
+
+ @Bean("doctor")
+ public Doctor getDoctor() {
+ return new Doctor();
+ }
+}
diff --git a/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/student/Student.java b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/student/Student.java
new file mode 100644
index 0000000000..56f2ac9830
--- /dev/null
+++ b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/student/Student.java
@@ -0,0 +1,12 @@
+package com.baeldung.annotations.componentscanautoconfigure.student;
+
+import org.springframework.stereotype.Component;
+
+@Component("student")
+public class Student {
+
+ @Override
+ public String toString() {
+ return "Student" + this.hashCode();
+ }
+}
diff --git a/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/teacher/Teacher.java b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/teacher/Teacher.java
new file mode 100644
index 0000000000..e2c653204d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-annotations/src/main/java/com/baeldung/annotations/componentscanautoconfigure/teacher/Teacher.java
@@ -0,0 +1,12 @@
+package com.baeldung.annotations.componentscanautoconfigure.teacher;
+
+import org.springframework.stereotype.Component;
+
+@Component("teacher")
+public class Teacher {
+
+ @Override
+ public String toString() {
+ return "Teacher" + this.hashCode();
+ }
+}
diff --git a/spring-boot-modules/spring-boot-annotations/src/main/test/com.baeldung.annotations/EmployeeApplicationTest.java b/spring-boot-modules/spring-boot-annotations/src/main/test/com.baeldung.annotations/EmployeeApplicationTest.java
new file mode 100644
index 0000000000..66700cf781
--- /dev/null
+++ b/spring-boot-modules/spring-boot-annotations/src/main/test/com.baeldung.annotations/EmployeeApplicationTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.annotations;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+public class EmployeeApplicationTest {
+ private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withUserConfiguration(EmployeeApplication.class);
+
+ @Test
+ void whenApplicationContextRuns_thenContainAllDefinedBeans() {
+ contextRunner.run(context -> assertAll(
+ () -> assertTrue(context.containsBeanDefinition("employee")),
+ () -> assertTrue(context.containsBeanDefinition("seniorEmployee")),
+ () -> assertTrue(context.containsBeanDefinition("doctor")),
+ () -> assertTrue(context.containsBeanDefinition("hospital")),
+ () -> assertFalse(context.containsBeanDefinition("student")),
+ () -> assertTrue(context.containsBeanDefinition("teacher"))));
+ }
+}
diff --git a/spring-boot-modules/spring-boot-keycloak/pom.xml b/spring-boot-modules/spring-boot-keycloak/pom.xml
index 5049cc3651..cfcdcf2c37 100644
--- a/spring-boot-modules/spring-boot-keycloak/pom.xml
+++ b/spring-boot-modules/spring-boot-keycloak/pom.xml
@@ -76,7 +76,7 @@
- 10.0.2
+ 11.0.2
diff --git a/spring-mvc-basics-2/src/main/java/com/baeldung/spring/configuration/EmailConfiguration.java b/spring-mvc-basics-2/src/main/java/com/baeldung/spring/configuration/EmailConfiguration.java
index 4bd692f609..86a7f1162c 100644
--- a/spring-mvc-basics-2/src/main/java/com/baeldung/spring/configuration/EmailConfiguration.java
+++ b/spring-mvc-basics-2/src/main/java/com/baeldung/spring/configuration/EmailConfiguration.java
@@ -1,37 +1,61 @@
package com.baeldung.spring.configuration;
+import freemarker.cache.ClassTemplateLoader;
+import freemarker.cache.TemplateLoader;
+import freemarker.template.Configuration;
import java.util.Properties;
-
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
-import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.thymeleaf.spring5.SpringTemplateEngine;
-import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
+import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
+import org.thymeleaf.templateresolver.ITemplateResolver;
-@Configuration
@ComponentScan(basePackages = { "com.baeldung.spring.mail" })
+@PropertySource(value={"classpath:application.properties"})
public class EmailConfiguration {
+
+ @Value("${spring.mail.host}")
+ private String mailServerHost;
+
+ @Value("${spring.mail.port}")
+ private Integer mailServerPort;
+
+ @Value("${spring.mail.username}")
+ private String mailServerUsername;
+
+ @Value("${spring.mail.password}")
+ private String mailServerPassword;
+
+ @Value("${spring.mail.properties.mail.smtp.auth}")
+ private String mailServerAuth;
+
+ @Value("${spring.mail.properties.mail.smtp.starttls.enable}")
+ private String mailServerStartTls;
+
+ @Value("${spring.mail.templates.path}")
+ private String mailTemplatesPath;
@Bean
public JavaMailSender getJavaMailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
- mailSender.setHost("smtp.gmail.com");
- mailSender.setPort(587);
+ mailSender.setHost(mailServerHost);
+ mailSender.setPort(mailServerPort);
- mailSender.setUsername("my.gmail@gmail.com");
- mailSender.setPassword("password");
+ mailSender.setUsername(mailServerUsername);
+ mailSender.setPassword(mailServerPassword);
Properties props = mailSender.getJavaMailProperties();
props.put("mail.transport.protocol", "smtp");
- props.put("mail.smtp.auth", "true");
- props.put("mail.smtp.starttls.enable", "false");
+ props.put("mail.smtp.auth", mailServerAuth);
+ props.put("mail.smtp.starttls.enable", mailServerStartTls);
props.put("mail.debug", "true");
return mailSender;
@@ -45,39 +69,52 @@ public class EmailConfiguration {
}
@Bean
- public SpringTemplateEngine thymeleafTemplateEngine() {
+ public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
- templateEngine.setTemplateResolver(thymeleafTemplateResolver());
+ templateEngine.setTemplateResolver(templateResolver);
templateEngine.setTemplateEngineMessageSource(emailMessageSource());
return templateEngine;
}
@Bean
- public SpringResourceTemplateResolver thymeleafTemplateResolver() {
- SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
- templateResolver.setPrefix("/WEB-INF/views/mail/");
+ public ITemplateResolver thymeleafClassLoaderTemplateResolver() {
+ ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
+ templateResolver.setPrefix(mailTemplatesPath + "/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
+
+// @Bean
+// public ITemplateResolver thymeleafFilesystemTemplateResolver() {
+// FileTemplateResolver templateResolver = new FileTemplateResolver();
+// templateResolver.setPrefix(mailTemplatesPath + "/");
+// templateResolver.setSuffix(".html");
+// templateResolver.setTemplateMode("HTML");
+// templateResolver.setCharacterEncoding("UTF-8");
+// return templateResolver;
+// }
@Bean
- public FreeMarkerConfigurer freemarkerConfig() {
- FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
- freeMarkerConfigurer.setTemplateLoaderPath("/WEB-INF/views/mail");
+ public FreeMarkerConfigurer freemarkerClassLoaderConfig() {
+ Configuration configuration = new Configuration(Configuration.VERSION_2_3_27);
+ TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), "/" + mailTemplatesPath);
+ configuration.setTemplateLoader(templateLoader);
+ FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
+ freeMarkerConfigurer.setConfiguration(configuration);
return freeMarkerConfigurer;
}
- @Bean
- public FreeMarkerViewResolver freemarkerViewResolver() {
- FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
- resolver.setCache(true);
- resolver.setPrefix("");
- resolver.setSuffix(".ftl");
- return resolver;
- }
-
+// @Bean
+// public FreeMarkerConfigurer freemarkerFilesystemConfig() throws IOException {
+// Configuration configuration = new Configuration(Configuration.VERSION_2_3_27);
+// TemplateLoader templateLoader = new FileTemplateLoader(new File(mailTemplatesPath));
+// configuration.setTemplateLoader(templateLoader);
+// FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
+// freeMarkerConfigurer.setConfiguration(configuration);
+// return freeMarkerConfigurer;
+// }
@Bean
public ResourceBundleMessageSource emailMessageSource() {
diff --git a/spring-mvc-basics-2/src/main/java/com/baeldung/spring/mail/EmailServiceImpl.java b/spring-mvc-basics-2/src/main/java/com/baeldung/spring/mail/EmailServiceImpl.java
index 1eb7a5f8b4..a0c8907a87 100644
--- a/spring-mvc-basics-2/src/main/java/com/baeldung/spring/mail/EmailServiceImpl.java
+++ b/spring-mvc-basics-2/src/main/java/com/baeldung/spring/mail/EmailServiceImpl.java
@@ -112,7 +112,7 @@ public class EmailServiceImpl implements EmailService {
String to, String subject, Map templateModel)
throws IOException, TemplateException, MessagingException {
- Template freemarkerTemplate = freemarkerConfigurer.createConfiguration().getTemplate("template-freemarker.ftl");
+ Template freemarkerTemplate = freemarkerConfigurer.getConfiguration().getTemplate("template-freemarker.ftl");
String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel);
sendHtmlMessage(to, subject, htmlBody);
diff --git a/spring-mvc-basics-2/src/main/resources/application.properties b/spring-mvc-basics-2/src/main/resources/application.properties
index 9a804c07d8..7ca8d33d5c 100644
--- a/spring-mvc-basics-2/src/main/resources/application.properties
+++ b/spring-mvc-basics-2/src/main/resources/application.properties
@@ -6,7 +6,7 @@ spring.mail.port=587
spring.mail.username=username
spring.mail.password=password
spring.mail.properties.mail.smtp.auth=true
-spring.mail.properties.mail.smtp.starttls.enable=true
+spring.mail.properties.mail.smtp.starttls.enable=false
# Amazon SES SMTP
#spring.mail.host=email-smtp.us-west-2.amazonaws.com
@@ -19,4 +19,14 @@ spring.mail.properties.mail.smtp.starttls.enable=true
#spring.mail.properties.mail.smtp.starttls.required=true
# path to attachment file
-attachment.invoice=path_to_file
\ No newline at end of file
+attachment.invoice=path_to_file
+
+
+#
+# Mail templates
+#
+
+# Templates directory inside main/resources or absolute filesystem path
+spring.mail.templates.path=mail-templates
+#spring.mail.templates.path=/path/to/templates
+
diff --git a/spring-mvc-basics-2/src/main/webapp/WEB-INF/views/mail/template-freemarker.ftl b/spring-mvc-basics-2/src/main/resources/mail-templates/template-freemarker.ftl
similarity index 100%
rename from spring-mvc-basics-2/src/main/webapp/WEB-INF/views/mail/template-freemarker.ftl
rename to spring-mvc-basics-2/src/main/resources/mail-templates/template-freemarker.ftl
diff --git a/spring-mvc-basics-2/src/main/webapp/WEB-INF/views/mail/template-thymeleaf.html b/spring-mvc-basics-2/src/main/resources/mail-templates/template-thymeleaf.html
similarity index 100%
rename from spring-mvc-basics-2/src/main/webapp/WEB-INF/views/mail/template-thymeleaf.html
rename to spring-mvc-basics-2/src/main/resources/mail-templates/template-thymeleaf.html