diff --git a/pom.xml b/pom.xml
index 562aaf896b..4808e614f6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,7 +77,7 @@
spring-zuul
jsf
xml
-
+ spring-4.3
lombok
redis
diff --git a/spring-4.3/README.md b/spring-4.3/README.md
new file mode 100644
index 0000000000..df7a07959d
--- /dev/null
+++ b/spring-4.3/README.md
@@ -0,0 +1,9 @@
+In this tutorial we cover few of the new features of Spring 4.3:
+
+
+ Implicit Constructor Injection
+ Improved Resolution of Dependency
+ Cache Abstraction Refinements
+ Composed @RequestMapping Variants
+ @RequestScope, @SessionScope, @ApplicationScope annotations
+ Libraries/Application Servers Versions Support
\ No newline at end of file
diff --git a/spring-4.3/pom.xml b/spring-4.3/pom.xml
new file mode 100644
index 0000000000..940bd92f68
--- /dev/null
+++ b/spring-4.3/pom.xml
@@ -0,0 +1,122 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ spring-4.3
+ 0.0.1-SNAPSHOT
+
+ jar
+
+ Spring 4.3 Demo
+
+
+ UTF-8
+ 1.8
+
+
+
+
+
+ org.springframework
+ spring-core
+
+
+
+ org.springframework
+ spring-context
+
+
+
+ org.springframework
+ spring-webmvc
+
+
+
+ org.springframework
+ spring-tx
+
+
+
+ org.springframework
+ spring-jdbc
+
+
+
+ javax.validation
+ validation-api
+ 1.1.0.Final
+
+
+
+ ch.qos.logback
+ logback-classic
+ 1.1.3
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+
+
+
+ org.springframework
+ spring-test
+ test
+
+
+
+ org.easymock
+ easymock
+ 3.4
+ test
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+ com.h2database
+ h2
+ 1.4.190
+ test
+
+
+
+
+
+
+
+
+
+ org.springframework
+ spring-framework-bom
+ 4.3.1.RELEASE
+ pom
+ import
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+
+
+
+
+
+
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/attributeannotations/AttributeAnnotationsTestController.java b/spring-4.3/src/main/java/com/baeldung/spring43/attributeannotations/AttributeAnnotationsTestController.java
new file mode 100644
index 0000000000..d11ca10873
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/attributeannotations/AttributeAnnotationsTestController.java
@@ -0,0 +1,14 @@
+package com.baeldung.spring43.attributeannotations;
+
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/test")
+public class AttributeAnnotationsTestController {
+
+ @GetMapping
+ public String get(@SessionAttribute String login, @RequestAttribute String query) {
+ return String.format("login = %s, query = %s", login, query);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/attributeannotations/ParamInterceptor.java b/spring-4.3/src/main/java/com/baeldung/spring43/attributeannotations/ParamInterceptor.java
new file mode 100644
index 0000000000..3d6e0ad8b9
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/attributeannotations/ParamInterceptor.java
@@ -0,0 +1,17 @@
+package com.baeldung.spring43.attributeannotations;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+public class ParamInterceptor extends HandlerInterceptorAdapter {
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ request.getSession().setAttribute("login", "john");
+ request.setAttribute("query", "invoices");
+ return super.preHandle(request, response, handler);
+ }
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/cache/Foo.java b/spring-4.3/src/main/java/com/baeldung/spring43/cache/Foo.java
new file mode 100644
index 0000000000..8a26d2164c
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/cache/Foo.java
@@ -0,0 +1,29 @@
+package com.baeldung.spring43.cache;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Foo {
+
+ private static final Logger log = LoggerFactory.getLogger(Foo.class);
+
+ private static final AtomicInteger instanceCount = new AtomicInteger(0);
+
+
+ private final int instanceNum;
+
+ public Foo() {
+ instanceNum = instanceCount.incrementAndGet();
+ }
+
+ public static int getInstanceCount() {
+ return instanceCount.get();
+ }
+
+ public void printInstanceNumber() {
+ log.info("Foo instance number: {}", instanceNum);
+ }
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/cache/FooService.java b/spring-4.3/src/main/java/com/baeldung/spring43/cache/FooService.java
new file mode 100644
index 0000000000..9c0aa583c5
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/cache/FooService.java
@@ -0,0 +1,14 @@
+package com.baeldung.spring43.cache;
+
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+@Service
+public class FooService {
+
+ @Cacheable(cacheNames = "foos", sync = true)
+ public Foo getFoo(String id) {
+ return new Foo();
+ }
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/composedmapping/Appointment.java b/spring-4.3/src/main/java/com/baeldung/spring43/composedmapping/Appointment.java
new file mode 100644
index 0000000000..4d8ba86f4b
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/composedmapping/Appointment.java
@@ -0,0 +1,5 @@
+package com.baeldung.spring43.composedmapping;
+
+public class Appointment {
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/composedmapping/AppointmentService.java b/spring-4.3/src/main/java/com/baeldung/spring43/composedmapping/AppointmentService.java
new file mode 100644
index 0000000000..1ca389e16b
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/composedmapping/AppointmentService.java
@@ -0,0 +1,9 @@
+package com.baeldung.spring43.composedmapping;
+
+import java.util.Map;
+
+public interface AppointmentService {
+
+ Map getAppointmentsForToday();
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/composedmapping/AppointmentsController.java b/spring-4.3/src/main/java/com/baeldung/spring43/composedmapping/AppointmentsController.java
new file mode 100644
index 0000000000..756766e1a7
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/composedmapping/AppointmentsController.java
@@ -0,0 +1,26 @@
+package com.baeldung.spring43.composedmapping;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Controller
+@RequestMapping("/appointments")
+public class AppointmentsController {
+
+ private final AppointmentService appointmentService;
+
+ @Autowired
+ public AppointmentsController(AppointmentService appointmentService) {
+ this.appointmentService = appointmentService;
+ }
+
+ @GetMapping
+ public Map get() {
+ return appointmentService.getAppointmentsForToday();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/ctor/FooRepository.java b/spring-4.3/src/main/java/com/baeldung/spring43/ctor/FooRepository.java
new file mode 100644
index 0000000000..f1d8425682
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/ctor/FooRepository.java
@@ -0,0 +1,5 @@
+package com.baeldung.spring43.ctor;
+
+public class FooRepository {
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/ctor/FooService.java b/spring-4.3/src/main/java/com/baeldung/spring43/ctor/FooService.java
new file mode 100644
index 0000000000..cb481f99b2
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/ctor/FooService.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring43.ctor;
+
+public class FooService {
+
+ private final FooRepository repository;
+
+ public FooService(FooRepository repository) {
+ this.repository = repository;
+ }
+
+ public FooRepository getRepository() {
+ return repository;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/defaultmethods/DateHolder.java b/spring-4.3/src/main/java/com/baeldung/spring43/defaultmethods/DateHolder.java
new file mode 100644
index 0000000000..a5307ec37c
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/defaultmethods/DateHolder.java
@@ -0,0 +1,18 @@
+package com.baeldung.spring43.defaultmethods;
+
+import java.time.LocalDate;
+
+public class DateHolder implements IDateHolder {
+
+ private LocalDate localDate;
+
+ @Override
+ public LocalDate getLocalDate() {
+ return localDate;
+ }
+
+ @Override
+ public void setLocalDate(LocalDate localDate) {
+ this.localDate = localDate;
+ }
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/defaultmethods/IDateHolder.java b/spring-4.3/src/main/java/com/baeldung/spring43/defaultmethods/IDateHolder.java
new file mode 100644
index 0000000000..66eca031c0
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/defaultmethods/IDateHolder.java
@@ -0,0 +1,16 @@
+package com.baeldung.spring43.defaultmethods;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+public interface IDateHolder {
+
+ LocalDate getLocalDate();
+
+ void setLocalDate(LocalDate localDate);
+
+ default void setStringDate(String stringDate) {
+ setLocalDate(LocalDate.parse(stringDate, DateTimeFormatter.ofPattern("dd.MM.yyyy")));
+ }
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/depresolution/FooRepository.java b/spring-4.3/src/main/java/com/baeldung/spring43/depresolution/FooRepository.java
new file mode 100644
index 0000000000..281a4f29fd
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/depresolution/FooRepository.java
@@ -0,0 +1,8 @@
+package com.baeldung.spring43.depresolution;
+
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class FooRepository {
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/depresolution/FooService.java b/spring-4.3/src/main/java/com/baeldung/spring43/depresolution/FooService.java
new file mode 100644
index 0000000000..1a6b13dc23
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/depresolution/FooService.java
@@ -0,0 +1,18 @@
+package com.baeldung.spring43.depresolution;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.stereotype.Service;
+
+@Service
+public class FooService {
+
+ private final FooRepository repository;
+
+ public FooService(ObjectProvider repositoryProvider) {
+ this.repository = repositoryProvider.getIfUnique();
+ }
+
+ public FooRepository getRepository() {
+ return repository;
+ }
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/AppPreferences.java b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/AppPreferences.java
new file mode 100644
index 0000000000..ede2849a51
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/AppPreferences.java
@@ -0,0 +1,10 @@
+package com.baeldung.spring43.scopeannotations;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.annotation.ApplicationScope;
+
+@Component
+@ApplicationScope
+public class AppPreferences extends InstanceCountingService {
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/InstanceCountingService.java b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/InstanceCountingService.java
new file mode 100644
index 0000000000..e6879e0544
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/InstanceCountingService.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring43.scopeannotations;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class InstanceCountingService {
+
+ private static final AtomicInteger instanceCount = new AtomicInteger(0);
+
+ private final int instanceNumber = instanceCount.incrementAndGet();
+
+ public int getInstanceNumber() {
+ return instanceNumber;
+ }
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/LoginAction.java b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/LoginAction.java
new file mode 100644
index 0000000000..132e701b5a
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/LoginAction.java
@@ -0,0 +1,10 @@
+package com.baeldung.spring43.scopeannotations;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.annotation.RequestScope;
+
+@Component
+@RequestScope
+public class LoginAction extends InstanceCountingService {
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/ScopeTestController.java b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/ScopeTestController.java
new file mode 100644
index 0000000000..bd3e3e9b92
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/ScopeTestController.java
@@ -0,0 +1,36 @@
+package com.baeldung.spring43.scopeannotations;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/appointments")
+public class ScopeTestController {
+
+ @Autowired
+ private LoginAction loginAction;
+
+ @Autowired
+ private UserPreferences userPreferences;
+
+ @Autowired
+ private AppPreferences appPreferences;
+
+ @GetMapping("/request")
+ public String getRequestNumber() {
+ return Integer.toString(loginAction.getInstanceNumber());
+ }
+
+ @GetMapping("/session")
+ public String getSessionNumber() {
+ return Integer.toString(userPreferences.getInstanceNumber());
+ }
+
+ @GetMapping("/application")
+ public String getApplicationNumber() {
+ return Integer.toString(appPreferences.getInstanceNumber());
+ }
+
+}
diff --git a/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/UserPreferences.java b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/UserPreferences.java
new file mode 100644
index 0000000000..27f313b2cb
--- /dev/null
+++ b/spring-4.3/src/main/java/com/baeldung/spring43/scopeannotations/UserPreferences.java
@@ -0,0 +1,10 @@
+package com.baeldung.spring43.scopeannotations;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.annotation.SessionScope;
+
+@Component
+@SessionScope
+public class UserPreferences extends InstanceCountingService {
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/attributeannotations/AttributeAnnotationConfiguration.java b/spring-4.3/src/test/java/com/baeldung/spring43/attributeannotations/AttributeAnnotationConfiguration.java
new file mode 100644
index 0000000000..97b92a943c
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/attributeannotations/AttributeAnnotationConfiguration.java
@@ -0,0 +1,30 @@
+package com.baeldung.spring43.attributeannotations;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.ViewResolver;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+import org.springframework.web.servlet.view.InternalResourceViewResolver;
+
+@Configuration
+@ComponentScan
+@EnableWebMvc
+public class AttributeAnnotationConfiguration extends WebMvcConfigurerAdapter {
+
+ @Bean
+ public ViewResolver viewResolver() {
+ InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
+ viewResolver.setPrefix("/WEB-INF/jsp/view/");
+ viewResolver.setSuffix(".jsp");
+ return viewResolver;
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(new ParamInterceptor());
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/attributeannotations/AttributeAnnotationTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/attributeannotations/AttributeAnnotationTest.java
new file mode 100644
index 0000000000..f368fd4818
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/attributeannotations/AttributeAnnotationTest.java
@@ -0,0 +1,45 @@
+package com.baeldung.spring43.attributeannotations;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@ContextConfiguration(classes = AttributeAnnotationConfiguration.class)
+@WebAppConfiguration
+public class AttributeAnnotationTest extends AbstractJUnit4SpringContextTests {
+
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ @Before
+ public void setup() {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
+ .build();
+ }
+
+ @Test
+ public void whenInterceptorAddsRequestAndSessionParams_thenParamsInjectedWithAttributesAnnotations() throws Exception {
+ String result = this.mockMvc.perform(get("/test")
+ .accept(MediaType.ALL))
+ .andExpect(status().isOk())
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ Assert.assertEquals("login = john, query = invoices", result);
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/cache/CacheRefinementsConfiguration.java b/spring-4.3/src/test/java/com/baeldung/spring43/cache/CacheRefinementsConfiguration.java
new file mode 100644
index 0000000000..45acb11f72
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/cache/CacheRefinementsConfiguration.java
@@ -0,0 +1,25 @@
+package com.baeldung.spring43.cache;
+
+import java.util.Collections;
+
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.concurrent.ConcurrentMapCache;
+import org.springframework.cache.support.SimpleCacheManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ComponentScan
+@EnableCaching
+public class CacheRefinementsConfiguration {
+
+ @Bean
+ public CacheManager cacheManager() {
+ SimpleCacheManager manager = new SimpleCacheManager();
+ manager.setCaches(Collections.singletonList(new ConcurrentMapCache("foos")));
+ return manager;
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/cache/CacheRefinementsTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/cache/CacheRefinementsTest.java
new file mode 100644
index 0000000000..3f06465c34
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/cache/CacheRefinementsTest.java
@@ -0,0 +1,31 @@
+package com.baeldung.spring43.cache;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+
+import static org.junit.Assert.assertEquals;
+
+@ContextConfiguration(classes = CacheRefinementsConfiguration.class)
+public class CacheRefinementsTest extends AbstractJUnit4SpringContextTests {
+
+ private ExecutorService executorService = Executors.newFixedThreadPool(10);
+
+ @Autowired
+ private FooService service;
+
+ @Test
+ public void whenMultipleThreadsExecuteCacheableMethodWithSyncTrue_thenMethodIsExecutedOnlyOnce() throws InterruptedException {
+ for (int i = 0; i < 10; i++) {
+ executorService.execute(() -> service.getFoo("test").printInstanceNumber());
+ }
+ executorService.awaitTermination(1, TimeUnit.SECONDS);
+ assertEquals(Foo.getInstanceCount(), 1);
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/composedmapping/ComposedMappingConfiguration.java b/spring-4.3/src/test/java/com/baeldung/spring43/composedmapping/ComposedMappingConfiguration.java
new file mode 100644
index 0000000000..7d92d4cecf
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/composedmapping/ComposedMappingConfiguration.java
@@ -0,0 +1,35 @@
+package com.baeldung.spring43.composedmapping;
+
+import java.util.Collections;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.ViewResolver;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.view.InternalResourceViewResolver;
+
+import static org.easymock.EasyMock.*;
+
+@Configuration
+@ComponentScan
+@EnableWebMvc
+public class ComposedMappingConfiguration {
+
+ @Bean
+ public ViewResolver viewResolver() {
+ InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
+ viewResolver.setPrefix("/WEB-INF/jsp/view/");
+ viewResolver.setSuffix(".jsp");
+ return viewResolver;
+ }
+
+ @Bean
+ public AppointmentService appointmentBook() {
+ AppointmentService book = mock(AppointmentService.class);
+ expect(book.getAppointmentsForToday()).andReturn(Collections.emptyMap());
+ replay(book);
+ return book;
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/composedmapping/ComposedMappingTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/composedmapping/ComposedMappingTest.java
new file mode 100644
index 0000000000..a3c4f818a5
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/composedmapping/ComposedMappingTest.java
@@ -0,0 +1,44 @@
+package com.baeldung.spring43.composedmapping;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.easymock.EasyMock.verify;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@ContextConfiguration(classes = ComposedMappingConfiguration.class)
+@WebAppConfiguration
+public class ComposedMappingTest extends AbstractJUnit4SpringContextTests {
+
+ @Autowired
+ private AppointmentService appointmentService;
+
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ @Before
+ public void setup() {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
+ .build();
+ }
+
+ @Test
+ public void whenRequestingMethodWithGetMapping_thenReceiving200Answer() throws Exception {
+ this.mockMvc.perform(get("/appointments")
+ .accept(MediaType.ALL))
+ .andExpect(status().isOk());
+ verify(appointmentService);
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/ctor/ConfigurationConstructorInjectionTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/ctor/ConfigurationConstructorInjectionTest.java
new file mode 100644
index 0000000000..3d001cdb78
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/ctor/ConfigurationConstructorInjectionTest.java
@@ -0,0 +1,21 @@
+package com.baeldung.spring43.ctor;
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+
+import static org.junit.Assert.assertNotNull;
+
+@ContextConfiguration(classes = {FooRepositoryConfiguration.class, FooServiceConfiguration.class})
+public class ConfigurationConstructorInjectionTest extends AbstractJUnit4SpringContextTests {
+
+ @Autowired
+ public FooService fooService;
+
+ @Test
+ public void whenSingleCtorInConfiguration_thenContextLoadsNormally() {
+ assertNotNull(fooService.getRepository());
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/ctor/FooRepositoryConfiguration.java b/spring-4.3/src/test/java/com/baeldung/spring43/ctor/FooRepositoryConfiguration.java
new file mode 100644
index 0000000000..fb33942844
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/ctor/FooRepositoryConfiguration.java
@@ -0,0 +1,14 @@
+package com.baeldung.spring43.ctor;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class FooRepositoryConfiguration {
+
+ @Bean
+ public FooRepository fooRepository() {
+ return new FooRepository();
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/ctor/FooServiceConfiguration.java b/spring-4.3/src/test/java/com/baeldung/spring43/ctor/FooServiceConfiguration.java
new file mode 100644
index 0000000000..5ab09e37ec
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/ctor/FooServiceConfiguration.java
@@ -0,0 +1,19 @@
+package com.baeldung.spring43.ctor;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class FooServiceConfiguration {
+
+ private final FooRepository repository;
+
+ public FooServiceConfiguration(FooRepository repository) {
+ this.repository = repository;
+ }
+
+ @Bean
+ public FooService fooService() {
+ return new FooService(this.repository);
+ }
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/ctor/ImplicitConstructorTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/ctor/ImplicitConstructorTest.java
new file mode 100644
index 0000000000..62c3eed091
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/ctor/ImplicitConstructorTest.java
@@ -0,0 +1,21 @@
+package com.baeldung.spring43.ctor;
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+
+import static org.junit.Assert.assertNotNull;
+
+@ContextConfiguration("classpath:implicit-ctor-context.xml")
+public class ImplicitConstructorTest extends AbstractJUnit4SpringContextTests {
+
+ @Autowired
+ private FooService fooService;
+
+ @Test
+ public void whenBeanWithoutAutowiredCtor_thenInjectIntoSingleCtor() {
+ assertNotNull(fooService.getRepository());
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/DefaultMethodsInjectionTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/DefaultMethodsInjectionTest.java
new file mode 100644
index 0000000000..8c4fa580d7
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/DefaultMethodsInjectionTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.spring43.defaultmethods;
+
+import java.time.LocalDate;
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+
+import static org.junit.Assert.assertEquals;
+
+@ContextConfiguration("classpath:defaultmethods-context.xml")
+public class DefaultMethodsInjectionTest extends AbstractJUnit4SpringContextTests {
+
+ @Autowired
+ private IDateHolder dateHolder;
+
+ @Test
+ public void whenInjectingToDefaultInterfaceMethod_thenInjectionShouldHappen() {
+ assertEquals(LocalDate.of(1982, 10, 15), dateHolder.getLocalDate());
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/ITransactionalTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/ITransactionalTest.java
new file mode 100644
index 0000000000..b3cca5f21f
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/ITransactionalTest.java
@@ -0,0 +1,22 @@
+package com.baeldung.spring43.defaultmethods;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.test.context.transaction.AfterTransaction;
+import org.springframework.test.context.transaction.BeforeTransaction;
+
+public interface ITransactionalTest {
+
+ Logger log = LoggerFactory.getLogger(ITransactionalTest.class);
+
+ @BeforeTransaction
+ default void beforeTransaction() {
+ log.info("Opening transaction");
+ }
+
+ @AfterTransaction
+ default void afterTransaction() {
+ log.info("Closing transaction");
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/TransactionalTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/TransactionalTest.java
new file mode 100644
index 0000000000..a7a693102c
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/TransactionalTest.java
@@ -0,0 +1,14 @@
+package com.baeldung.spring43.defaultmethods;
+
+import org.junit.Test;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
+
+@ContextConfiguration(classes = TransactionalTestConfiguration.class)
+public class TransactionalTest extends AbstractTransactionalJUnit4SpringContextTests implements ITransactionalTest {
+
+ @Test
+ public void whenDefaultMethodAnnotatedWithBeforeTransaction_thenDefaultMethodIsExecuted() {
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/TransactionalTestConfiguration.java b/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/TransactionalTestConfiguration.java
new file mode 100644
index 0000000000..c5b5a6574f
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/defaultmethods/TransactionalTestConfiguration.java
@@ -0,0 +1,30 @@
+package com.baeldung.spring43.defaultmethods;
+
+
+import javax.sql.DataSource;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.jdbc.datasource.SimpleDriverDataSource;
+import org.springframework.transaction.PlatformTransactionManager;
+
+@Configuration
+public class TransactionalTestConfiguration {
+
+ @Bean
+ public DataSource getDataSource() {
+ SimpleDriverDataSource simpleDriverDataSource = new SimpleDriverDataSource();
+ simpleDriverDataSource.setDriverClass(org.h2.Driver.class);
+ simpleDriverDataSource.setUrl("jdbc:h2:mem:~test");
+ simpleDriverDataSource.setUsername("sa");
+ simpleDriverDataSource.setPassword("");
+ return simpleDriverDataSource;
+ }
+
+ @Bean
+ public PlatformTransactionManager transactionManager() {
+ return new DataSourceTransactionManager(getDataSource());
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/depresolution/ObjectProviderConfiguration.java b/spring-4.3/src/test/java/com/baeldung/spring43/depresolution/ObjectProviderConfiguration.java
new file mode 100644
index 0000000000..020b50ceb2
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/depresolution/ObjectProviderConfiguration.java
@@ -0,0 +1,9 @@
+package com.baeldung.spring43.depresolution;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ComponentScan
+public class ObjectProviderConfiguration {
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/depresolution/ObjectProviderTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/depresolution/ObjectProviderTest.java
new file mode 100644
index 0000000000..6ae6b1eda3
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/depresolution/ObjectProviderTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.spring43.depresolution;
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+
+import static org.junit.Assert.assertNotNull;
+
+@ContextConfiguration(classes = ObjectProviderConfiguration.class)
+public class ObjectProviderTest extends AbstractJUnit4SpringContextTests {
+
+ @Autowired
+ private FooService fooService;
+
+ @Test
+ public void whenArgumentIsObjectProvider_thenObjectProviderInjected() {
+
+ assertNotNull(fooService.getRepository());
+
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/scopeannotations/ScopeAnnotationsConfiguration.java b/spring-4.3/src/test/java/com/baeldung/spring43/scopeannotations/ScopeAnnotationsConfiguration.java
new file mode 100644
index 0000000000..a7d9c16721
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/scopeannotations/ScopeAnnotationsConfiguration.java
@@ -0,0 +1,23 @@
+package com.baeldung.spring43.scopeannotations;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.ViewResolver;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.view.InternalResourceViewResolver;
+
+@Configuration
+@ComponentScan
+@EnableWebMvc
+public class ScopeAnnotationsConfiguration {
+
+ @Bean
+ public ViewResolver viewResolver() {
+ InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
+ viewResolver.setPrefix("/WEB-INF/jsp/view/");
+ viewResolver.setSuffix(".jsp");
+ return viewResolver;
+ }
+
+}
diff --git a/spring-4.3/src/test/java/com/baeldung/spring43/scopeannotations/ScopeAnnotationsTest.java b/spring-4.3/src/test/java/com/baeldung/spring43/scopeannotations/ScopeAnnotationsTest.java
new file mode 100644
index 0000000000..5bd07437c1
--- /dev/null
+++ b/spring-4.3/src/test/java/com/baeldung/spring43/scopeannotations/ScopeAnnotationsTest.java
@@ -0,0 +1,110 @@
+package com.baeldung.spring43.scopeannotations;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.mock.web.MockHttpSession;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@ContextConfiguration(classes = ScopeAnnotationsConfiguration.class)
+@WebAppConfiguration
+public class ScopeAnnotationsTest extends AbstractJUnit4SpringContextTests {
+
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ @Before
+ public void setup() {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
+ .build();
+ }
+
+ @Test
+ public void whenDifferentRequests_thenDifferentInstancesOfRequestScopedBeans() throws Exception {
+ MockHttpSession session = new MockHttpSession();
+
+ String requestScopedServiceInstanceNumber1 = this.mockMvc.perform(get("/appointments/request")
+ .session(session)
+ .accept(MediaType.ALL)).andExpect(status().isOk())
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ String requestScopedServiceInstanceNumber2 = this.mockMvc.perform(get("/appointments/request")
+ .session(session)
+ .accept(MediaType.ALL)).andExpect(status().isOk())
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ assertNotEquals(requestScopedServiceInstanceNumber1, requestScopedServiceInstanceNumber2);
+ }
+
+ @Test
+ public void whenDifferentSessions_thenDifferentInstancesOfSessionScopedBeans() throws Exception {
+
+ MockHttpSession session1 = new MockHttpSession();
+ MockHttpSession session2 = new MockHttpSession();
+
+ String sessionScopedServiceInstanceNumber1 = this.mockMvc.perform(get("/appointments/session")
+ .session(session1)
+ .accept(MediaType.ALL)).andExpect(status().isOk())
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+ String sessionScopedServiceInstanceNumber2 = this.mockMvc.perform(get("/appointments/session")
+ .session(session1)
+ .accept(MediaType.ALL)).andExpect(status().isOk())
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+ String sessionScopedServiceInstanceNumber3 = this.mockMvc.perform(get("/appointments/session")
+ .session(session2)
+ .accept(MediaType.ALL)).andExpect(status().isOk())
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ assertEquals(sessionScopedServiceInstanceNumber1, sessionScopedServiceInstanceNumber2);
+
+ assertNotEquals(sessionScopedServiceInstanceNumber1, sessionScopedServiceInstanceNumber3);
+
+ }
+
+ @Test
+ public void whenDifferentSessionsAndRequests_thenAlwaysSingleApplicationScopedBean() throws Exception {
+
+ MockHttpSession session1 = new MockHttpSession();
+ MockHttpSession session2 = new MockHttpSession();
+
+ String applicationScopedServiceInstanceNumber1 = this.mockMvc.perform(get("/appointments/application")
+ .session(session1)
+ .accept(MediaType.ALL)).andExpect(status().isOk())
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+ String applicationScopedServiceInstanceNumber2 = this.mockMvc.perform(get("/appointments/application")
+ .session(session2)
+ .accept(MediaType.ALL)).andExpect(status().isOk())
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ assertEquals(applicationScopedServiceInstanceNumber1, applicationScopedServiceInstanceNumber2);
+
+ }
+
+}
diff --git a/spring-4.3/src/test/resources/defaultmethods-context.xml b/spring-4.3/src/test/resources/defaultmethods-context.xml
new file mode 100644
index 0000000000..5725d0cabf
--- /dev/null
+++ b/spring-4.3/src/test/resources/defaultmethods-context.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-4.3/src/test/resources/implicit-ctor-context.xml b/spring-4.3/src/test/resources/implicit-ctor-context.xml
new file mode 100644
index 0000000000..3dc0058f94
--- /dev/null
+++ b/spring-4.3/src/test/resources/implicit-ctor-context.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/spring-4.3/src/test/resources/logback.xml b/spring-4.3/src/test/resources/logback.xml
new file mode 100644
index 0000000000..68ea00fb54
--- /dev/null
+++ b/spring-4.3/src/test/resources/logback.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss} [%t] %-5p: %c - %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file