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