- Logged in user:
|
- domain:
Some Domain
+
+
+
Logged in: | Some Domain
+
-
Hello Spring Security
+
+
Hello Spring Security
This is an unsecured page, but you can access the secured pages after authenticating.
+
diff --git a/spring-5-security/src/main/resources/templatesextrafields/login.html b/spring-5-security/src/main/resources/templatesextrafields/login.html
index cafec89c15..5c51ea3b2c 100644
--- a/spring-5-security/src/main/resources/templatesextrafields/login.html
+++ b/spring-5-security/src/main/resources/templatesextrafields/login.html
@@ -1,23 +1,36 @@
-
-
-
Login page
-
-
-
-
-
Login page
+
+
+
Login page
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-5-security/src/main/resources/templatesextrafields/user/index.html b/spring-5-security/src/main/resources/templatesextrafields/user/index.html
index a4c1535100..9c41f0e78c 100644
--- a/spring-5-security/src/main/resources/templatesextrafields/user/index.html
+++ b/spring-5-security/src/main/resources/templatesextrafields/user/index.html
@@ -1,13 +1,20 @@
-
-
-
Spring Security - Login With Extra Fields
-
-
-
-
-
-
This is a secured page!
-
Back to home page
-
+
+
+
Secured Page
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-5-security/src/test/java/com/baeldung/loginextrafields/AbstractExtraLoginFieldsTest.java b/spring-5-security/src/test/java/com/baeldung/loginextrafields/AbstractExtraLoginFieldsTest.java
new file mode 100644
index 0000000000..30b869714f
--- /dev/null
+++ b/spring-5-security/src/test/java/com/baeldung/loginextrafields/AbstractExtraLoginFieldsTest.java
@@ -0,0 +1,46 @@
+package com.baeldung.loginextrafields;
+
+import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.web.FilterChainProxy;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+public abstract class AbstractExtraLoginFieldsTest {
+
+ @Autowired
+ private FilterChainProxy springSecurityFilterChain;
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ protected MockMvc mockMvc;
+
+ @Before
+ public void setup() {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
+ .apply(springSecurity(springSecurityFilterChain))
+ .build();
+ }
+
+ @Test
+ public void givenRootPathAccess_thenRedirectToIndex() throws Exception {
+ this.mockMvc.perform(get("/"))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(redirectedUrlPattern("/index*"));
+ }
+
+ @Test
+ public void givenSecuredResource_whenAccessUnauthenticated_thenRequiresAuthentication() throws Exception {
+ this.mockMvc.perform(get("/user/index"))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(redirectedUrlPattern("**/login"));
+ }
+}
diff --git a/spring-5-security/src/test/java/com/baeldung/securityextrafields/SecurityExtraFieldsTest.java b/spring-5-security/src/test/java/com/baeldung/loginextrafields/LoginFieldsFullTest.java
similarity index 65%
rename from spring-5-security/src/test/java/com/baeldung/securityextrafields/SecurityExtraFieldsTest.java
rename to spring-5-security/src/test/java/com/baeldung/loginextrafields/LoginFieldsFullTest.java
index cf0701708d..38c219cb5e 100644
--- a/spring-5-security/src/test/java/com/baeldung/securityextrafields/SecurityExtraFieldsTest.java
+++ b/spring-5-security/src/test/java/com/baeldung/loginextrafields/LoginFieldsFullTest.java
@@ -1,8 +1,7 @@
-package com.baeldung.securityextrafields;
+package com.baeldung.loginextrafields;
import static org.junit.Assert.assertEquals;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
-import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
@@ -11,57 +10,26 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import java.util.ArrayList;
import java.util.Collection;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
-import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.loginextrafieldscustom.ExtraLoginFieldsApplication;
+import com.baeldung.loginextrafieldscustom.User;
@RunWith(SpringRunner.class)
@SpringJUnitWebConfig
-@SpringBootTest(classes = SpringExtraLoginFieldsApplication.class)
-public class SecurityExtraFieldsTest {
-
- @Autowired
- private FilterChainProxy springSecurityFilterChain;
-
- @Autowired
- private WebApplicationContext wac;
-
- private MockMvc mockMvc;
-
- @Before
- public void setup() {
- this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
- .apply(springSecurity(springSecurityFilterChain)).build();
- }
-
- @Test
- public void givenRootPathAccess_thenRedirectToIndex() throws Exception {
- this.mockMvc.perform(get("/"))
- .andExpect(status().is3xxRedirection())
- .andExpect(redirectedUrlPattern("/index*"));
- }
-
- @Test
- public void givenSecuredResource_whenAccessUnauthenticated_thenRequiresAuthentication() throws Exception {
- this.mockMvc.perform(get("/user/index"))
- .andExpect(status().is3xxRedirection())
- .andExpect(redirectedUrlPattern("**/login"));
- }
+@SpringBootTest(classes = ExtraLoginFieldsApplication.class)
+public class LoginFieldsFullTest extends AbstractExtraLoginFieldsTest {
@Test
public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception {
@@ -100,4 +68,5 @@ public class SecurityExtraFieldsTest {
Collection extends GrantedAuthority> authorities = new ArrayList<>();
return new User("myusername", "mydomain", "password", true, true, true, true, authorities);
}
+
}
diff --git a/spring-5-security/src/test/java/com/baeldung/loginextrafields/LoginFieldsSimpleTest.java b/spring-5-security/src/test/java/com/baeldung/loginextrafields/LoginFieldsSimpleTest.java
new file mode 100644
index 0000000000..5c0d462772
--- /dev/null
+++ b/spring-5-security/src/test/java/com/baeldung/loginextrafields/LoginFieldsSimpleTest.java
@@ -0,0 +1,72 @@
+package com.baeldung.loginextrafields;
+
+import static org.junit.Assert.assertEquals;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.mock.web.MockHttpSession;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
+import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
+
+import com.baeldung.loginextrafieldssimple.ExtraLoginFieldsApplication;
+import com.baeldung.loginextrafieldssimple.User;
+
+@RunWith(SpringRunner.class)
+@SpringJUnitWebConfig
+@SpringBootTest(classes = ExtraLoginFieldsApplication.class)
+public class LoginFieldsSimpleTest extends AbstractExtraLoginFieldsTest {
+
+ @Test
+ public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception {
+ MockHttpServletRequestBuilder securedResourceAccess = get("/user/index");
+ MvcResult unauthenticatedResult = mockMvc.perform(securedResourceAccess)
+ .andExpect(status().is3xxRedirection())
+ .andReturn();
+
+ MockHttpSession session = (MockHttpSession) unauthenticatedResult.getRequest()
+ .getSession();
+ String loginUrl = unauthenticatedResult.getResponse()
+ .getRedirectedUrl();
+
+ User user = getUser();
+
+ mockMvc.perform(post(loginUrl)
+ .param("username", user.getUsername())
+ .param("password", user.getPassword())
+ .param("domain", user.getDomain())
+ .session(session)
+ .with(csrf()))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(redirectedUrlPattern("**/user/index"))
+ .andReturn();
+
+ mockMvc.perform(securedResourceAccess.session(session))
+ .andExpect(status().isOk());
+
+ SecurityContext securityContext
+ = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
+ Authentication auth = securityContext.getAuthentication();
+ assertEquals(((User)auth.getPrincipal()).getDomain(), user.getDomain());
+ }
+
+ private User getUser() {
+ Collection extends GrantedAuthority> authorities = new ArrayList<>();
+ return new User("myusername", "mydomain", "password", true, true, true, true, authorities);
+ }
+
+}
diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java
index 4e4244abb7..32c3fbdef4 100644
--- a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java
+++ b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/basic_auth/BasicAuthConfigurationIntegrationTest.java
@@ -37,6 +37,7 @@ public class BasicAuthConfigurationIntegrationTest {
@Test
public void whenLoggedUserRequestsHomePage_ThenSuccess() throws IllegalStateException, IOException {
ResponseEntity
response = restTemplate.getForEntity(base.toString(), String.class);
+
assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue(response
.getBody()
@@ -47,6 +48,7 @@ public class BasicAuthConfigurationIntegrationTest {
public void whenUserWithWrongCredentialsRequestsHomePage_ThenUnauthorizedPage() throws IllegalStateException, IOException {
restTemplate = new TestRestTemplate("user", "wrongpassword");
ResponseEntity response = restTemplate.getForEntity(base.toString(), String.class);
+
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
assertTrue(response
.getBody()
diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/CustomConfigAuthorizationServerIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/CustomConfigAuthorizationServerIntegrationTest.java
index 09df9ce645..cc953eef5a 100644
--- a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/CustomConfigAuthorizationServerIntegrationTest.java
+++ b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/CustomConfigAuthorizationServerIntegrationTest.java
@@ -2,10 +2,7 @@ package com.baeldung.springbootsecurity.oauth2server;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
-import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
@@ -13,7 +10,6 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
-import static java.lang.String.format;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
@@ -21,54 +17,35 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = SpringBootAuthorizationServerApplication.class)
@ActiveProfiles("authz")
-public class CustomConfigAuthorizationServerIntegrationTest {
-
- @Value("${local.server.port}") protected int port;
+public class CustomConfigAuthorizationServerIntegrationTest extends OAuth2IntegrationTestSupport {
@Test
- public void whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
- ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails();
- resourceDetails.setClientId("baeldung");
- resourceDetails.setClientSecret("baeldung");
- resourceDetails.setScope(singletonList("read"));
- DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
- OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
- restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
+ public void givenOAuth2Context_whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
+ ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails("baeldung", singletonList("read"));
+ OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
+
OAuth2AccessToken accessToken = restTemplate.getAccessToken();
+
assertNotNull(accessToken);
}
@Test(expected = OAuth2AccessDeniedException.class)
- public void whenAccessTokenIsRequestedWithInvalidException_ThenExceptionIsThrown() {
- ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails();
- resourceDetails.setClientId("baeldung");
- resourceDetails.setClientSecret("baeldung");
- resourceDetails.setScope(singletonList("write"));
- DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
- OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
- restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
+ public void givenOAuth2Context_whenAccessTokenIsRequestedWithInvalidException_ThenExceptionIsThrown() {
+ ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails("baeldung", singletonList("write"));
+ OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
+
restTemplate.getAccessToken();
}
@Test
- public void whenAccessTokenIsRequestedByClientWithWriteScope_ThenAccessTokenIsNotNull() {
- ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails();
- resourceDetails.setClientId("baeldung-admin");
- resourceDetails.setClientSecret("baeldung");
- resourceDetails.setScope(singletonList("write"));
- DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
- OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
- restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
- OAuth2AccessToken accessToken = restTemplate.getAccessToken();
- assertNotNull(accessToken);
- }
+ public void givenOAuth2Context_whenAccessTokenIsRequestedByClientWithWriteScope_ThenAccessTokenIsNotNull() {
+ ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails("baeldung-admin", singletonList("write"));
+ OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
- private ClientCredentialsResourceDetails getClientCredentialsResourceDetails() {
- ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
- resourceDetails.setAccessTokenUri(format("http://localhost:%d/oauth/token", port));
- resourceDetails.setGrantType("client_credentials");
- return resourceDetails;
+ OAuth2AccessToken accessToken = restTemplate.getAccessToken();
+
+ assertNotNull(accessToken);
}
}
diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/DefaultConfigAuthorizationServerIntegrationTest.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/DefaultConfigAuthorizationServerIntegrationTest.java
index c7b1b4ef6c..4d7b449380 100644
--- a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/DefaultConfigAuthorizationServerIntegrationTest.java
+++ b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/DefaultConfigAuthorizationServerIntegrationTest.java
@@ -2,40 +2,28 @@ package com.baeldung.springbootsecurity.oauth2server;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
-import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.test.context.junit4.SpringRunner;
-import static java.lang.String.format;
import static java.util.Arrays.asList;
-import static java.util.Collections.singletonList;
import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = SpringBootAuthorizationServerApplication.class,
- properties = { "security.oauth2.client.client-id=client", "security.oauth2.client.client-secret=secret" })
-public class DefaultConfigAuthorizationServerIntegrationTest {
-
- @Value("${local.server.port}") protected int port;
+ properties = { "security.oauth2.client.client-id=client", "security.oauth2.client.client-secret=baeldung" })
+public class DefaultConfigAuthorizationServerIntegrationTest extends OAuth2IntegrationTestSupport {
@Test
- public void whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
- ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
- resourceDetails.setAccessTokenUri(format("http://localhost:%d/oauth/token", port));
- resourceDetails.setClientId("client");
- resourceDetails.setClientSecret("secret");
- resourceDetails.setGrantType("client_credentials");
- resourceDetails.setScope(asList("read", "write"));
- DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
- OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
- restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
+ public void givenOAuth2Context_whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
+ ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails("client", asList("read", "write"));
+ OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
+
OAuth2AccessToken accessToken = restTemplate.getAccessToken();
+
assertNotNull(accessToken);
}
diff --git a/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/OAuth2IntegrationTestSupport.java b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/OAuth2IntegrationTestSupport.java
new file mode 100644
index 0000000000..3eef206c7d
--- /dev/null
+++ b/spring-boot-security/src/test/java/com/baeldung/springbootsecurity/oauth2server/OAuth2IntegrationTestSupport.java
@@ -0,0 +1,34 @@
+package com.baeldung.springbootsecurity.oauth2server;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
+import org.springframework.security.oauth2.client.OAuth2RestTemplate;
+import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
+
+import java.util.List;
+
+import static java.lang.String.format;
+import static java.util.Collections.singletonList;
+
+public class OAuth2IntegrationTestSupport {
+
+ @Value("${local.server.port}") protected int port;
+
+ protected ClientCredentialsResourceDetails getClientCredentialsResourceDetails(final String clientId, final List scopes) {
+ ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
+ resourceDetails.setAccessTokenUri(format("http://localhost:%d/oauth/token", port));
+ resourceDetails.setClientId(clientId);
+ resourceDetails.setClientSecret("baeldung");
+ resourceDetails.setScope(scopes);
+ resourceDetails.setGrantType("client_credentials");
+ return resourceDetails;
+ }
+
+ protected OAuth2RestTemplate getOAuth2RestTemplate(final ClientCredentialsResourceDetails resourceDetails) {
+ DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
+ OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
+ restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
+ return restTemplate;
+ }
+}
diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml
index d6ee022522..a557604bf3 100644
--- a/spring-boot/pom.xml
+++ b/spring-boot/pom.xml
@@ -167,6 +167,12 @@
org.apache.activemq
artemis-server
+
+
+ com.rometools
+ rome
+ ${rome.version}
+
@@ -276,6 +282,7 @@
8.5.11
1.4.194
2.4.1.Final
+ 1.9.0
\ No newline at end of file
diff --git a/spring-boot/src/main/java/com/baeldung/internationalization/config/MvcConfig.java b/spring-boot/src/main/java/com/baeldung/internationalization/config/MvcConfig.java
index 59f7fd3ba5..478e8d393a 100644
--- a/spring-boot/src/main/java/com/baeldung/internationalization/config/MvcConfig.java
+++ b/spring-boot/src/main/java/com/baeldung/internationalization/config/MvcConfig.java
@@ -6,14 +6,12 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
-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.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
@Configuration
-@EnableWebMvc
@ComponentScan(basePackages = "com.baeldung.internationalization.config")
public class MvcConfig extends WebMvcConfigurerAdapter {
@@ -33,6 +31,6 @@ public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
- registry.addInterceptor(localeChangeInterceptor());
+ registry.addInterceptor(localeChangeInterceptor());
}
}
diff --git a/spring-boot/src/main/java/com/baeldung/kong/QueryController.java b/spring-boot/src/main/java/com/baeldung/kong/QueryController.java
new file mode 100644
index 0000000000..af63a7e8a1
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/kong/QueryController.java
@@ -0,0 +1,32 @@
+package com.baeldung.kong;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author aiet
+ */
+@RestController
+@RequestMapping("/stock")
+public class QueryController {
+
+ private static int REQUEST_COUNTER = 0;
+
+ @GetMapping("/reqcount")
+ public int getReqCount(){
+ return REQUEST_COUNTER;
+ }
+
+ @GetMapping("/{code}")
+ public String getStockPrice(@PathVariable String code){
+ REQUEST_COUNTER++;
+ if("BTC".equalsIgnoreCase(code))
+ return "10000";
+ else return "N/A";
+ }
+
+
+
+}
diff --git a/spring-boot/src/main/java/com/baeldung/kong/StockApp.java b/spring-boot/src/main/java/com/baeldung/kong/StockApp.java
new file mode 100644
index 0000000000..f901592938
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/kong/StockApp.java
@@ -0,0 +1,13 @@
+package com.baeldung.kong;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class StockApp {
+
+ public static void main(String[] args) {
+ SpringApplication.run(StockApp.class, args);
+ }
+
+}
diff --git a/spring-boot/src/main/java/com/baeldung/rss/ArticleFeedView.java b/spring-boot/src/main/java/com/baeldung/rss/ArticleFeedView.java
new file mode 100644
index 0000000000..3efa619409
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/rss/ArticleFeedView.java
@@ -0,0 +1,54 @@
+package com.baeldung.rss;
+
+import com.rometools.rome.feed.rss.Channel;
+import com.rometools.rome.feed.rss.Description;
+import com.rometools.rome.feed.rss.Item;
+import org.springframework.stereotype.Service;
+import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@Service("articleFeedView")
+public class ArticleFeedView extends AbstractRssFeedView {
+
+ protected Channel newFeed() {
+ Channel channel = new Channel("rss_2.0");
+ channel.setLink("http://localhost:8080/rss");
+ channel.setTitle("Article Feed");
+ channel.setDescription("Article Feed Description");
+ channel.setPubDate(new Date());
+ return channel;
+ }
+
+ @Override
+ protected List- buildFeedItems(Map map, HttpServletRequest httpStRequest, HttpServletResponse httpStResponse) throws Exception {
+ List list = new ArrayList
- ();
+
+ Item item1 = new Item();
+ item1.setLink("http://www.baeldung.com/netty-exception-handling");
+ item1.setTitle("Exceptions in Netty");
+ Description description1 = new Description();
+ description1.setValue("In this quick article, we’ll be looking at exception handling in Netty.");
+ item1.setDescription(description1);
+ item1.setPubDate(new Date());
+ item1.setAuthor("Carlos");
+
+ Item item2 = new Item();
+ item2.setLink("http://www.baeldung.com/cockroachdb-java");
+ item2.setTitle("Guide to CockroachDB in Java");
+ Description description2 = new Description();
+ description2.setValue("This tutorial is an introductory guide to using CockroachDB with Java.");
+ item2.setDescription(description2);
+ item2.setPubDate(new Date());
+ item2.setAuthor("Baeldung");
+
+ list.add(item1);
+ list.add(item2);
+ return list;
+ }
+}
diff --git a/spring-boot/src/main/java/com/baeldung/rss/ArticleRssController.java b/spring-boot/src/main/java/com/baeldung/rss/ArticleRssController.java
new file mode 100644
index 0000000000..a3fbc4a37e
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/rss/ArticleRssController.java
@@ -0,0 +1,16 @@
+package com.baeldung.rss;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+@Controller
+@RequestMapping(value = "/rss", produces = "application/*")
+public class ArticleRssController {
+
+ @RequestMapping(method = RequestMethod.GET)
+ public String articleFeed() {
+ return "articleFeedView";
+ }
+
+}
diff --git a/spring-boot/src/main/java/com/baeldung/rss/CustomContainer.java b/spring-boot/src/main/java/com/baeldung/rss/CustomContainer.java
new file mode 100644
index 0000000000..ee36ecdc51
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/rss/CustomContainer.java
@@ -0,0 +1,16 @@
+package com.baeldung.rss;
+
+import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
+import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CustomContainer implements EmbeddedServletContainerCustomizer {
+
+ @Override
+ public void customize(ConfigurableEmbeddedServletContainer container) {
+ container.setPort(8080);
+ container.setContextPath("");
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot/src/main/java/com/baeldung/rss/RssApp.java b/spring-boot/src/main/java/com/baeldung/rss/RssApp.java
new file mode 100644
index 0000000000..2add7ed421
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/rss/RssApp.java
@@ -0,0 +1,20 @@
+package com.baeldung.rss;
+
+import com.baeldung.autoconfiguration.MySQLAutoconfiguration;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+import javax.annotation.security.RolesAllowed;
+
+@SpringBootApplication(exclude = MySQLAutoconfiguration.class)
+@ComponentScan(basePackages = "com.baeldung.rss")
+public class RssApp {
+
+ @RolesAllowed("*")
+ public static void main(String[] args) {
+ System.setProperty("security.basic.enabled", "false");
+ SpringApplication.run(RssApp.class, args);
+ }
+
+}
diff --git a/spring-boot/src/main/java/com/baeldung/utils/controller/UtilsController.java b/spring-boot/src/main/java/com/baeldung/utils/controller/UtilsController.java
index 7c66391bd2..8c7f2f932a 100644
--- a/spring-boot/src/main/java/com/baeldung/utils/controller/UtilsController.java
+++ b/spring-boot/src/main/java/com/baeldung/utils/controller/UtilsController.java
@@ -4,7 +4,6 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
-import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
diff --git a/spring-boot/src/main/java/com/baeldung/webjar/WebjarsdemoApplication.java b/spring-boot/src/main/java/com/baeldung/webjar/WebjarsdemoApplication.java
index 8704b42166..5038c7e5f7 100644
--- a/spring-boot/src/main/java/com/baeldung/webjar/WebjarsdemoApplication.java
+++ b/spring-boot/src/main/java/com/baeldung/webjar/WebjarsdemoApplication.java
@@ -2,7 +2,6 @@ package com.baeldung.webjar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.ComponentScan;
import com.baeldung.autoconfiguration.MySQLAutoconfiguration;
diff --git a/spring-boot/src/main/java/org/baeldung/boot/converter/GenericBigDecimalConverter.java b/spring-boot/src/main/java/org/baeldung/boot/converter/GenericBigDecimalConverter.java
index decd8ac5db..7bcbfee45b 100644
--- a/spring-boot/src/main/java/org/baeldung/boot/converter/GenericBigDecimalConverter.java
+++ b/spring-boot/src/main/java/org/baeldung/boot/converter/GenericBigDecimalConverter.java
@@ -5,7 +5,6 @@ import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;
import java.math.BigDecimal;
-import java.math.MathContext;
import java.util.Set;
public class GenericBigDecimalConverter implements GenericConverter {
diff --git a/spring-boot/src/main/java/org/baeldung/boot/converter/controller/StringToEmployeeConverterController.java b/spring-boot/src/main/java/org/baeldung/boot/converter/controller/StringToEmployeeConverterController.java
index ad921c2c43..a6e0400845 100644
--- a/spring-boot/src/main/java/org/baeldung/boot/converter/controller/StringToEmployeeConverterController.java
+++ b/spring-boot/src/main/java/org/baeldung/boot/converter/controller/StringToEmployeeConverterController.java
@@ -1,7 +1,6 @@
package org.baeldung.boot.converter.controller;
import com.baeldung.toggle.Employee;
-import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
diff --git a/spring-boot/src/main/java/org/baeldung/main/SpringBootApplication.java b/spring-boot/src/main/java/org/baeldung/main/SpringBootApplication.java
index 0ab4ecb128..f9bdb67a10 100644
--- a/spring-boot/src/main/java/org/baeldung/main/SpringBootApplication.java
+++ b/spring-boot/src/main/java/org/baeldung/main/SpringBootApplication.java
@@ -11,7 +11,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
-import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
diff --git a/spring-boot/src/main/resources/application.properties b/spring-boot/src/main/resources/application.properties
index 458b4e0d46..059a6c96be 100644
--- a/spring-boot/src/main/resources/application.properties
+++ b/spring-boot/src/main/resources/application.properties
@@ -1,4 +1,4 @@
-server.port=8080
+server.port=9090
server.contextPath=/springbootapp
management.port=8081
management.address=127.0.0.1
diff --git a/spring-boot/src/main/resources/static/internationalization.js b/spring-boot/src/main/resources/static/internationalization.js
new file mode 100644
index 0000000000..ae416f083d
--- /dev/null
+++ b/spring-boot/src/main/resources/static/internationalization.js
@@ -0,0 +1,8 @@
+$(document).ready(function() {
+ $("#locales").change(function () {
+ var selectedOption = $('#locales').val();
+ if (selectedOption != ''){
+ window.location.replace('international?lang=' + selectedOption);
+ }
+ });
+});
\ No newline at end of file
diff --git a/spring-boot/src/main/resources/templates/international.html b/spring-boot/src/main/resources/templates/international.html
index a2a5fbb591..e0cfb5143b 100644
--- a/spring-boot/src/main/resources/templates/international.html
+++ b/spring-boot/src/main/resources/templates/international.html
@@ -4,16 +4,7 @@
Home
-
+
diff --git a/spring-boot/src/test/java/com/baeldung/kong/KongAdminAPILiveTest.java b/spring-boot/src/test/java/com/baeldung/kong/KongAdminAPILiveTest.java
new file mode 100644
index 0000000000..f399806a65
--- /dev/null
+++ b/spring-boot/src/test/java/com/baeldung/kong/KongAdminAPILiveTest.java
@@ -0,0 +1,165 @@
+package com.baeldung.kong;
+
+import com.baeldung.kong.domain.APIObject;
+import com.baeldung.kong.domain.ConsumerObject;
+import com.baeldung.kong.domain.KeyAuthObject;
+import com.baeldung.kong.domain.PluginObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.http.*;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.net.URI;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT;
+
+/**
+ * @author aiet
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = DEFINED_PORT, classes = StockApp.class)
+public class KongAdminAPILiveTest {
+
+ private String getStockPrice(String code) {
+ try {
+ return restTemplate.getForObject(new URI("http://localhost:8080/stock/" + code), String.class);
+ } catch (Exception ignored) {
+ }
+ return null;
+ }
+
+ @Before
+ public void init() {
+ System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
+ }
+
+ @Autowired TestRestTemplate restTemplate;
+
+ @Test
+ public void givenEndpoint_whenQueryStockPrice_thenPriceCorrect() {
+ String response = getStockPrice("btc");
+ assertEquals("10000", response);
+
+ response = getStockPrice("eth");
+ assertEquals("N/A", response);
+ }
+
+ @Test
+ public void givenKongAdminAPI_whenAddAPI_thenAPIAccessibleViaKong() throws Exception {
+ restTemplate.delete("http://localhost:8001/apis/stock-api");
+
+ APIObject stockAPI = new APIObject("stock-api", "stock.api", "http://localhost:8080", "/");
+ HttpEntity apiEntity = new HttpEntity<>(stockAPI);
+ ResponseEntity addAPIResp = restTemplate.postForEntity("http://localhost:8001/apis", apiEntity, String.class);
+
+ assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode());
+
+ addAPIResp = restTemplate.postForEntity("http://localhost:8001/apis", apiEntity, String.class);
+ assertEquals(HttpStatus.CONFLICT, addAPIResp.getStatusCode());
+ String apiListResp = restTemplate.getForObject("http://localhost:8001/apis/", String.class);
+
+ assertTrue(apiListResp.contains("stock-api"));
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Host", "stock.api");
+ RequestEntity requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
+ ResponseEntity stockPriceResp = restTemplate.exchange(requestEntity, String.class);
+
+ assertEquals("10000", stockPriceResp.getBody());
+ }
+
+ @Test
+ public void givenKongAdminAPI_whenAddAPIConsumer_thenAdded() {
+ restTemplate.delete("http://localhost:8001/consumers/eugenp");
+
+ ConsumerObject consumer = new ConsumerObject("eugenp");
+ HttpEntity addConsumerEntity = new HttpEntity<>(consumer);
+ ResponseEntity addConsumerResp = restTemplate.postForEntity("http://localhost:8001/consumers/", addConsumerEntity, String.class);
+
+ assertEquals(HttpStatus.CREATED, addConsumerResp.getStatusCode());
+
+ addConsumerResp = restTemplate.postForEntity("http://localhost:8001/consumers", addConsumerEntity, String.class);
+ assertEquals(HttpStatus.CONFLICT, addConsumerResp.getStatusCode());
+
+ String consumerListResp = restTemplate.getForObject("http://localhost:8001/consumers/", String.class);
+ assertTrue(consumerListResp.contains("eugenp"));
+ }
+
+ @Test
+ public void givenAPI_whenEnableAuth_thenAnonymousDenied() throws Exception {
+ String apiListResp = restTemplate.getForObject("http://localhost:8001/apis/", String.class);
+ if (!apiListResp.contains("stock-api")) {
+ givenKongAdminAPI_whenAddAPI_thenAPIAccessibleViaKong();
+ }
+
+ PluginObject authPlugin = new PluginObject("key-auth");
+ ResponseEntity enableAuthResp = restTemplate.postForEntity("http://localhost:8001/apis/stock-api/plugins", new HttpEntity<>(authPlugin), String.class);
+
+ assertTrue(HttpStatus.CREATED == enableAuthResp.getStatusCode() || HttpStatus.CONFLICT == enableAuthResp.getStatusCode());
+
+ String pluginsResp = restTemplate.getForObject("http://localhost:8001/apis/stock-api/plugins", String.class);
+ assertTrue(pluginsResp.contains("key-auth"));
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Host", "stock.api");
+ RequestEntity requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
+ ResponseEntity stockPriceResp = restTemplate.exchange(requestEntity, String.class);
+ assertEquals(HttpStatus.UNAUTHORIZED, stockPriceResp.getStatusCode());
+ }
+
+ @Test
+ public void givenAPIAuthEnabled_whenAddKey_thenAccessAllowed() throws Exception {
+ String apiListResp = restTemplate.getForObject("http://localhost:8001/apis/", String.class);
+ if (!apiListResp.contains("stock-api")) {
+ givenKongAdminAPI_whenAddAPI_thenAPIAccessibleViaKong();
+ }
+
+ String consumerListResp = restTemplate.getForObject("http://localhost:8001/consumers/", String.class);
+ if (!consumerListResp.contains("eugenp")) {
+ givenKongAdminAPI_whenAddAPIConsumer_thenAdded();
+ }
+
+ final String consumerKey = "eugenp.pass";
+ KeyAuthObject keyAuth = new KeyAuthObject(consumerKey);
+ ResponseEntity keyAuthResp = restTemplate.postForEntity("http://localhost:8001/consumers/eugenp/key-auth", new HttpEntity<>(keyAuth), String.class);
+
+ assertTrue(HttpStatus.CREATED == keyAuthResp.getStatusCode() || HttpStatus.CONFLICT == keyAuthResp.getStatusCode());
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Host", "stock.api");
+ headers.set("apikey", consumerKey);
+ RequestEntity requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
+ ResponseEntity stockPriceResp = restTemplate.exchange(requestEntity, String.class);
+
+ assertEquals("10000", stockPriceResp.getBody());
+
+ headers.set("apikey", "wrongpass");
+ requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
+ stockPriceResp = restTemplate.exchange(requestEntity, String.class);
+ assertEquals(HttpStatus.FORBIDDEN, stockPriceResp.getStatusCode());
+ }
+
+ @Test
+ public void givenAdminAPIProxy_whenAddAPIViaProxy_thenAPIAdded() throws Exception {
+ APIObject adminAPI = new APIObject("admin-api", "admin.api", "http://localhost:8001", "/admin-api");
+ HttpEntity apiEntity = new HttpEntity<>(adminAPI);
+ ResponseEntity addAPIResp = restTemplate.postForEntity("http://localhost:8001/apis", apiEntity, String.class);
+
+ assertTrue(HttpStatus.CREATED == addAPIResp.getStatusCode() || HttpStatus.CONFLICT == addAPIResp.getStatusCode());
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Host", "admin.api");
+ APIObject baeldungAPI = new APIObject("baeldung-api", "baeldung.com", "http://ww.baeldung.com", "/");
+ RequestEntity requestEntity = new RequestEntity<>(baeldungAPI, headers, HttpMethod.POST, new URI("http://localhost:8000/admin-api/apis"));
+ addAPIResp = restTemplate.exchange(requestEntity, String.class);
+
+ assertTrue(HttpStatus.CREATED == addAPIResp.getStatusCode() || HttpStatus.CONFLICT == addAPIResp.getStatusCode());
+ }
+
+}
diff --git a/spring-boot/src/test/java/com/baeldung/kong/KongLoadBalanceLiveTest.java b/spring-boot/src/test/java/com/baeldung/kong/KongLoadBalanceLiveTest.java
new file mode 100644
index 0000000000..f8090e4c86
--- /dev/null
+++ b/spring-boot/src/test/java/com/baeldung/kong/KongLoadBalanceLiveTest.java
@@ -0,0 +1,68 @@
+package com.baeldung.kong;
+
+import com.baeldung.kong.domain.APIObject;
+import com.baeldung.kong.domain.TargetObject;
+import com.baeldung.kong.domain.UpstreamObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.http.*;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.net.URI;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT;
+
+/**
+ * @author aiet
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = DEFINED_PORT, classes = StockApp.class)
+public class KongLoadBalanceLiveTest {
+
+ @Before
+ public void init() {
+ System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
+ }
+
+ @Autowired TestRestTemplate restTemplate;
+
+ @Test
+ public void givenKongAdminAPI_whenAddAPI_thenAPIAccessibleViaKong() throws Exception {
+ UpstreamObject upstream = new UpstreamObject("stock.api.service");
+ ResponseEntity addUpstreamResp = restTemplate.postForEntity("http://localhost:8001/upstreams", new HttpEntity<>(upstream), String.class);
+ assertTrue(HttpStatus.CREATED == addUpstreamResp.getStatusCode() || HttpStatus.CONFLICT == addUpstreamResp.getStatusCode());
+
+ TargetObject testTarget = new TargetObject("localhost:8080", 10);
+ ResponseEntity addTargetResp = restTemplate.postForEntity("http://localhost:8001/upstreams/stock.api.service/targets", new HttpEntity<>(testTarget), String.class);
+ assertTrue(HttpStatus.CREATED == addTargetResp.getStatusCode() || HttpStatus.CONFLICT == addTargetResp.getStatusCode());
+
+ TargetObject releaseTarget = new TargetObject("localhost:9090", 40);
+ addTargetResp = restTemplate.postForEntity("http://localhost:8001/upstreams/stock.api.service/targets", new HttpEntity<>(releaseTarget), String.class);
+ assertTrue(HttpStatus.CREATED == addTargetResp.getStatusCode() || HttpStatus.CONFLICT == addTargetResp.getStatusCode());
+
+ APIObject stockAPI = new APIObject("balanced-stock-api", "balanced.stock.api", "http://stock.api.service", "/");
+ HttpEntity apiEntity = new HttpEntity<>(stockAPI);
+ ResponseEntity addAPIResp = restTemplate.postForEntity("http://localhost:8001/apis", apiEntity, String.class);
+ assertTrue(HttpStatus.CREATED == addAPIResp.getStatusCode() || HttpStatus.CONFLICT == addAPIResp.getStatusCode());
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Host", "balanced.stock.api");
+ for (int i = 0; i < 1000; i++) {
+ RequestEntity requestEntity = new RequestEntity<>(headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
+ ResponseEntity stockPriceResp = restTemplate.exchange(requestEntity, String.class);
+ assertEquals("10000", stockPriceResp.getBody());
+ }
+
+ int releaseCount = restTemplate.getForObject("http://localhost:9090/stock/reqcount", Integer.class);
+ int testCount = restTemplate.getForObject("http://localhost:8080/stock/reqcount", Integer.class);
+
+ assertTrue(Math.round(releaseCount * 1.0 / testCount) == 4);
+ }
+
+}
diff --git a/spring-boot/src/test/java/com/baeldung/kong/domain/APIObject.java b/spring-boot/src/test/java/com/baeldung/kong/domain/APIObject.java
new file mode 100644
index 0000000000..f386712444
--- /dev/null
+++ b/spring-boot/src/test/java/com/baeldung/kong/domain/APIObject.java
@@ -0,0 +1,54 @@
+package com.baeldung.kong.domain;
+
+/**
+ * @author aiet
+ */
+public class APIObject {
+
+ public APIObject() {
+ }
+
+ public APIObject(String name, String hosts, String upstream_url, String uris) {
+ this.name = name;
+ this.hosts = hosts;
+ this.upstream_url = upstream_url;
+ this.uris = uris;
+ }
+
+ private String name;
+ private String hosts;
+ private String upstream_url;
+ private String uris;
+
+ public String getUris() {
+ return uris;
+ }
+
+ public void setUris(String uris) {
+ this.uris = uris;
+ }
+
+ public String getUpstream_url() {
+ return upstream_url;
+ }
+
+ public void setUpstream_url(String upstream_url) {
+ this.upstream_url = upstream_url;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getHosts() {
+ return hosts;
+ }
+
+ public void setHosts(String hosts) {
+ this.hosts = hosts;
+ }
+}
diff --git a/spring-boot/src/test/java/com/baeldung/kong/domain/ConsumerObject.java b/spring-boot/src/test/java/com/baeldung/kong/domain/ConsumerObject.java
new file mode 100644
index 0000000000..74bef8f2d1
--- /dev/null
+++ b/spring-boot/src/test/java/com/baeldung/kong/domain/ConsumerObject.java
@@ -0,0 +1,35 @@
+package com.baeldung.kong.domain;
+
+/**
+ * @author aiet
+ */
+public class ConsumerObject {
+
+ private String username;
+ private String custom_id;
+
+ public ConsumerObject(String username) {
+ this.username = username;
+ }
+
+ public ConsumerObject(String username, String custom_id) {
+ this.username = username;
+ this.custom_id = custom_id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getCustom_id() {
+ return custom_id;
+ }
+
+ public void setCustom_id(String custom_id) {
+ this.custom_id = custom_id;
+ }
+}
diff --git a/spring-boot/src/test/java/com/baeldung/kong/domain/KeyAuthObject.java b/spring-boot/src/test/java/com/baeldung/kong/domain/KeyAuthObject.java
new file mode 100644
index 0000000000..80de6bfcd9
--- /dev/null
+++ b/spring-boot/src/test/java/com/baeldung/kong/domain/KeyAuthObject.java
@@ -0,0 +1,21 @@
+package com.baeldung.kong.domain;
+
+/**
+ * @author aiet
+ */
+public class KeyAuthObject {
+
+ public KeyAuthObject(String key) {
+ this.key = key;
+ }
+
+ private String key;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+}
diff --git a/spring-boot/src/test/java/com/baeldung/kong/domain/PluginObject.java b/spring-boot/src/test/java/com/baeldung/kong/domain/PluginObject.java
new file mode 100644
index 0000000000..c161fc9b54
--- /dev/null
+++ b/spring-boot/src/test/java/com/baeldung/kong/domain/PluginObject.java
@@ -0,0 +1,30 @@
+package com.baeldung.kong.domain;
+
+/**
+ * @author aiet
+ */
+public class PluginObject {
+
+ private String name;
+ private String consumer_id;
+
+ public PluginObject(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getConsumer_id() {
+ return consumer_id;
+ }
+
+ public void setConsumer_id(String consumer_id) {
+ this.consumer_id = consumer_id;
+ }
+}
diff --git a/spring-boot/src/test/java/com/baeldung/kong/domain/TargetObject.java b/spring-boot/src/test/java/com/baeldung/kong/domain/TargetObject.java
new file mode 100644
index 0000000000..79653e2846
--- /dev/null
+++ b/spring-boot/src/test/java/com/baeldung/kong/domain/TargetObject.java
@@ -0,0 +1,31 @@
+package com.baeldung.kong.domain;
+
+/**
+ * @author aiet
+ */
+public class TargetObject {
+
+ public TargetObject(String target, int weight) {
+ this.target = target;
+ this.weight = weight;
+ }
+
+ private String target;
+ private int weight;
+
+ public String getTarget() {
+ return target;
+ }
+
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ public int getWeight() {
+ return weight;
+ }
+
+ public void setWeight(int weight) {
+ this.weight = weight;
+ }
+}
diff --git a/spring-boot/src/test/java/com/baeldung/kong/domain/UpstreamObject.java b/spring-boot/src/test/java/com/baeldung/kong/domain/UpstreamObject.java
new file mode 100644
index 0000000000..6461381ac5
--- /dev/null
+++ b/spring-boot/src/test/java/com/baeldung/kong/domain/UpstreamObject.java
@@ -0,0 +1,21 @@
+package com.baeldung.kong.domain;
+
+/**
+ * @author aiet
+ */
+public class UpstreamObject {
+
+ public UpstreamObject(String name) {
+ this.name = name;
+ }
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/spring-boot/src/test/java/org/baeldung/SpringBootMailIntegrationTest.java b/spring-boot/src/test/java/org/baeldung/SpringBootMailIntegrationTest.java
index 17e7d2d9e0..5dd6ab8e17 100644
--- a/spring-boot/src/test/java/org/baeldung/SpringBootMailIntegrationTest.java
+++ b/spring-boot/src/test/java/org/baeldung/SpringBootMailIntegrationTest.java
@@ -10,8 +10,6 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import org.springframework.test.context.web.WebAppConfiguration;
-import org.springframework.web.context.WebApplicationContext;
import org.subethamail.wiser.Wiser;
import org.subethamail.wiser.WiserMessage;
diff --git a/spring-cloud/README.md b/spring-cloud/README.md
index 53b7606563..adaf3052e6 100644
--- a/spring-cloud/README.md
+++ b/spring-cloud/README.md
@@ -12,13 +12,11 @@
Client-side service discovery allows services to find and communicate with each other without hardcoding hostname and port. The only ‘fixed point’ in such an architecture consists of a service registry with which each service has to register.
+### Relevant Articles:
- [Intro to Spring Cloud Netflix - Hystrix](http://www.baeldung.com/spring-cloud-netflix-hystrix)
- [Dockerizing a Spring Boot Application](http://www.baeldung.com/dockerizing-spring-boot-application)
- [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon)
- [A Quick Guide to Spring Cloud Consul](http://www.baeldung.com/spring-cloud-consul)
-
-### Relevant Articles:
-- [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon)
- [An Introduction to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper)
+- [Using a Spring Cloud App Starter](http://www.baeldung.com/using-a-spring-cloud-app-starter)
- [Spring Cloud Connectors and Heroku](http://www.baeldung.com/spring-cloud-heroku)
-
diff --git a/spring-cloud/spring-cloud-aws/README.md b/spring-cloud/spring-cloud-aws/README.md
index c5f58159c8..1340712c7a 100644
--- a/spring-cloud/spring-cloud-aws/README.md
+++ b/spring-cloud/spring-cloud-aws/README.md
@@ -19,3 +19,8 @@ to write the following in `application.properties`:
cloud.aws.rds.spring-cloud-test-db
cloud.aws.rds.spring-cloud-test-db.password=se3retpass
```
+Multiple application classes are available under this project. To launch InstanceProfileAwsApplication application, replace `start-class` under `pom.xml`:
+
+```
+com.baeldung.spring.cloud.aws.InstanceProfileAwsApplication
+```
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-aws/pom.xml b/spring-cloud/spring-cloud-aws/pom.xml
index 632e050d92..b27b6c0d18 100644
--- a/spring-cloud/spring-cloud-aws/pom.xml
+++ b/spring-cloud/spring-cloud-aws/pom.xml
@@ -19,6 +19,7 @@
+ com.baeldung.spring.cloud.aws.SpringCloudAwsApplication
UTF-8
UTF-8
1.8
diff --git a/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/InstanceProfileAwsApplication.java b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/InstanceProfileAwsApplication.java
new file mode 100644
index 0000000000..80c0851a6f
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/InstanceProfileAwsApplication.java
@@ -0,0 +1,60 @@
+package com.baeldung.spring.cloud.aws;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+import com.baeldung.spring.cloud.aws.s3.SpringCloudS3Service;
+
+@Configuration
+@EnableAutoConfiguration
+@ComponentScan("com.baeldung.spring.cloud.aws.s3")
+public class InstanceProfileAwsApplication {
+
+ private static final Logger logger = LoggerFactory.getLogger(InstanceProfileAwsApplication.class);
+ private static final String applicationConfig = "spring.config.name:application-instance-profile";
+
+ private static String bucketName;
+ private static String fileName = "sample-file.txt";
+
+ private static void setupResources() {
+ bucketName = "baeldung-test-" + UUID.randomUUID()
+ .toString();
+ try {
+ Files.write(Paths.get(fileName), "Hello World!".getBytes());
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ public static void main(String[] args) {
+ setupResources();
+ if (!new File(fileName).exists()) {
+ logger.warn("Not able to create {} file. Check your folder permissions.", fileName);
+ System.exit(1);
+ }
+
+ SpringApplication application = new SpringApplicationBuilder(InstanceProfileAwsApplication.class).properties(applicationConfig)
+ .build();
+ ConfigurableApplicationContext context = application.run(args);
+ SpringCloudS3Service service = context.getBean(SpringCloudS3Service.class);
+
+ // S3 bucket operations
+ service.createBucket(bucketName);
+ service.uploadObject(bucketName, fileName);
+ service.downloadObject(bucketName, fileName);
+ service.deleteBucket(bucketName);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3Service.java b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3Service.java
new file mode 100644
index 0000000000..a0fdce2143
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3Service.java
@@ -0,0 +1,64 @@
+package com.baeldung.spring.cloud.aws.s3;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.model.ListObjectsV2Result;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+
+@Component
+public class SpringCloudS3Service {
+
+ private static final Logger logger = LoggerFactory.getLogger(SpringCloudS3Service.class);
+
+ @Autowired
+ AmazonS3 amazonS3;
+
+ @Autowired
+ SpringCloudS3 springCloudS3;
+
+ public void createBucket(String bucketName) {
+ logger.debug("Creating S3 bucket: {}", bucketName);
+ amazonS3.createBucket(bucketName);
+ logger.info("{} bucket created successfully", bucketName);
+ }
+
+ public void downloadObject(String bucketName, String objectName) {
+ String s3Url = "s3://" + bucketName + "/" + objectName;
+ try {
+ springCloudS3.downloadS3Object(s3Url);
+ logger.info("{} file download result: {}", objectName, new File(objectName).exists());
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ public void uploadObject(String bucketName, String objectName) {
+ String s3Url = "s3://" + bucketName + "/" + objectName;
+ File file = new File(objectName);
+ try {
+ springCloudS3.uploadFileToS3(file, s3Url);
+ logger.info("{} file uploaded to S3", objectName);
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ public void deleteBucket(String bucketName) {
+ logger.trace("Deleting S3 objects under {} bucket...", bucketName);
+ ListObjectsV2Result listObjectsV2Result = amazonS3.listObjectsV2(bucketName);
+ for (S3ObjectSummary objectSummary : listObjectsV2Result.getObjectSummaries()) {
+ logger.info("Deleting S3 object: {}", objectSummary.getKey());
+ amazonS3.deleteObject(bucketName, objectSummary.getKey());
+ }
+ logger.info("Deleting S3 bucket: {}", bucketName);
+ amazonS3.deleteBucket(bucketName);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-aws/src/main/resources/InstanceProfileFormation.yaml b/spring-cloud/spring-cloud-aws/src/main/resources/InstanceProfileFormation.yaml
new file mode 100644
index 0000000000..f8c3d3c915
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/resources/InstanceProfileFormation.yaml
@@ -0,0 +1,78 @@
+AWSTemplateFormatVersion: 2010-09-09
+Metadata:
+ 'AWS::CloudFormation::Designer':
+ 157e7d5f-5cb3-4a23-a50c-97e7f6c57173:
+ size:
+ width: 60
+ height: 60
+ position:
+ x: 450
+ 'y': 90
+ z: 0
+ embeds: []
+ 9bbaaa55-9cba-4555-a7c6-fb6ac248fd3a:
+ size:
+ width: 60
+ height: 60
+ position:
+ x: 260
+ 'y': 90
+ z: 0
+ embeds: []
+ isassociatedwith:
+ - 157e7d5f-5cb3-4a23-a50c-97e7f6c57173
+ a7348729-a594-4dca-9b0a-e1c8d777dc3b:
+ size:
+ width: 60
+ height: 60
+ position:
+ x: 70
+ 'y': 90
+ z: 0
+ embeds: []
+Resources:
+ IAMRoleBaeldung:
+ Type: 'AWS::IAM::Role'
+ Properties:
+ AssumeRolePolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Effect: Allow
+ Principal:
+ Service:
+ - ec2.amazonaws.com
+ Action:
+ - 'sts:AssumeRole'
+ ManagedPolicyArns:
+ - 'arn:aws:iam::aws:policy/AmazonS3FullAccess'
+ Metadata:
+ 'AWS::CloudFormation::Designer':
+ id: 157e7d5f-5cb3-4a23-a50c-97e7f6c57173
+ InstanceProfileBaeldung:
+ Type: 'AWS::IAM::InstanceProfile'
+ Properties:
+ Roles:
+ - !Ref IAMRoleBaeldung
+ Metadata:
+ 'AWS::CloudFormation::Designer':
+ id: 9bbaaa55-9cba-4555-a7c6-fb6ac248fd3a
+ EC2Instance:
+ Type: 'AWS::EC2::Instance'
+ Properties:
+ ImageId: ami-2581aa40
+ InstanceType: t2.micro
+ IamInstanceProfile: !Ref InstanceProfileBaeldung
+ KeyName: Satish-Ohio
+ UserData: !Base64
+ 'Fn::Join':
+ - ''
+ - - |
+ #!/bin/bash
+ - |
+ apt -y install openjdk-8-jre-headless
+ Metadata:
+ 'AWS::CloudFormation::Designer':
+ id: a7348729-a594-4dca-9b0a-e1c8d777dc3b
+ DependsOn:
+ - InstanceProfileBaeldung
+
diff --git a/spring-cloud/spring-cloud-aws/src/main/resources/application-instance-profile.properties b/spring-cloud/spring-cloud-aws/src/main/resources/application-instance-profile.properties
new file mode 100644
index 0000000000..23ca09c85c
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/resources/application-instance-profile.properties
@@ -0,0 +1,14 @@
+# Don't try to create DataSouce when running tests which don't need a DataSource
+spring.autoconfigure.exclude=\
+ org.springframework.cloud.aws.autoconfigure.jdbc.AmazonRdsDatabaseAutoConfiguration,\
+ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
+cloud.aws.region.auto=true
+
+# Load instance profile credentials
+cloud.aws.credentials.instanceProfile=true
+
+# Disable auto cloud formation
+cloud.aws.stack.auto=false
+
+# Disable web environment
+spring.main.web-environment=false
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-security/personresource/pom.xml b/spring-cloud/spring-cloud-security/personresource/pom.xml
index 783fd41e66..ca1ff82515 100644
--- a/spring-cloud/spring-cloud-security/personresource/pom.xml
+++ b/spring-cloud/spring-cloud-security/personresource/pom.xml
@@ -43,10 +43,6 @@
org.springframework.security
spring-security-jwt
-
- com.google.code.gson
- gson
-
diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java b/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java
index 15ffc557fc..9e5420da5a 100644
--- a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java
+++ b/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java
@@ -6,16 +6,13 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.baeldung.model.Person;
-import com.google.gson.Gson;
@RestController
public class PersonInfoController {
@GetMapping("/personResource")
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
- public @ResponseBody String personInfo() {
- Gson gson = new Gson();
- String person = gson.toJson(new Person("abir", "Dhaka", "Bangladesh", 29, "Male"));
- return person;
+ public @ResponseBody Person personInfo() {
+ return new Person("abir", "Dhaka", "Bangladesh", 29, "Male");
}
}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/bash/hadoop.sh b/spring-cloud/spring-cloud-stream-starters/bash/hadoop.sh
new file mode 100644
index 0000000000..ca8298430b
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/bash/hadoop.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+# For Ubuntu 14.04
+# Inspired from: https://github.com/curran/setupHadoop/blob/master/setupHadoop.sh
+# Use from the user directory
+
+# Install Java
+sudo apt-get update
+sudo add-apt-repository -y ppa:webupd8team/java
+sudo apt-get install -y oracle-java8-installer
+
+# Install Hadoop
+curl -O http://mirror.cogentco.com/pub/apache/hadoop/common/hadoop-2.8.2/hadoop-2.8.2.tar.gz
+tar xfz hadoop-2.8.2.tar.gz
+sudo mv hadoop-2.8.2 /usr/local/hadoop
+rm hadoop-2.8.2.tar.gz
+
+# Environmental Variables
+echo export JAVA_HOME=/usr/lib/jvm/java-8-oracle >> ~/.bashrc
+echo export HADOOP_PREFIX=/usr/local/hadoop >> ~/.bashrc
+echo export PATH=\$PATH:/usr/local/hadoop/bin >> ~/.bashrc
+echo export PATH=\$PATH:/usr/local/hadoop/sbin >> ~/.bashrc
+source ~/.bashrc
+
+# Copy configuration files
+cp master/* /usr/local/hadoop/etc/hadoop/
+
+# Format HDFS
+hdfs namenode -format
+
+# SSH keys for Hadoop to use.
+ssh-keygen -t rsa -P 'password' -f ~/.ssh/id_rsa.pub
+sudo mv ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys
+
+# SSH
+ssh localhost
+# authenticate with osboxes.org
+
+# Start NameNode daemon and DataNode daemon
+start-dfs.sh
+# stop-dfs.sh
+
+# Install Maven
+sudo apt-get install maven
+
+# Access Hadoop - http://localhost:50070
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/boot/.gitignore b/spring-cloud/spring-cloud-stream-starters/boot/.gitignore
new file mode 100644
index 0000000000..e4b82e1c0f
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/boot/.gitignore
@@ -0,0 +1,3 @@
+.idea
+*/target/*
+*.iml
diff --git a/spring-cloud/spring-cloud-stream-starters/boot/pom.xml b/spring-cloud/spring-cloud-stream-starters/boot/pom.xml
new file mode 100644
index 0000000000..3e6bc134e3
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/boot/pom.xml
@@ -0,0 +1,55 @@
+
+
+ 4.0.0
+ com.baeldung.twitterhdfs
+ twitterhdfs
+ jar
+ 1.0.0
+
+ twitterhdfs
+
+
+ UTF-8
+ UTF-8
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.5.8.RELEASE
+
+
+
+
+
+ org.springframework.cloud.stream.app
+ spring-cloud-starter-stream-source-twitterstream
+ 1.3.1.RELEASE
+
+
+ org.springframework.cloud.stream.app
+ spring-cloud-starter-stream-sink-hdfs
+ 1.3.1.RELEASE
+
+
+
+
+ javax.servlet
+ jstl
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ twitterhdfs
+
+
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/aggregate/AggregateApp.java b/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/aggregate/AggregateApp.java
new file mode 100644
index 0000000000..8b9ca6dc62
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/aggregate/AggregateApp.java
@@ -0,0 +1,18 @@
+package com.baeldung.twitterhdfs.aggregate;
+
+import com.baeldung.twitterhdfs.processor.ProcessorApp;
+import com.baeldung.twitterhdfs.source.SourceApp;
+import com.baeldung.twitterhdfs.sink.SinkApp;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.stream.aggregate.AggregateApplicationBuilder;
+
+@SpringBootApplication
+public class AggregateApp {
+ public static void main(String[] args) {
+ new AggregateApplicationBuilder()
+ .from(SourceApp.class).args("--fixedDelay=5000")
+ .via(ProcessorApp.class)
+ .to(SinkApp.class).args("--debug=true")
+ .run(args);
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/processor/ProcessorApp.java b/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/processor/ProcessorApp.java
new file mode 100644
index 0000000000..e3bd1197f6
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/processor/ProcessorApp.java
@@ -0,0 +1,20 @@
+package com.baeldung.twitterhdfs.processor;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.stream.annotation.EnableBinding;
+import org.springframework.cloud.stream.messaging.Processor;
+import org.springframework.integration.annotation.Transformer;
+
+@SpringBootApplication
+@EnableBinding(Processor.class)
+public class ProcessorApp {
+ Logger log = LoggerFactory.getLogger(ProcessorApp.class);
+
+ @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
+ public String processMessage(String payload) {
+ log.info("Payload received!");
+ return payload;
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/sink/SinkApp.java b/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/sink/SinkApp.java
new file mode 100644
index 0000000000..c0c1e287d3
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/sink/SinkApp.java
@@ -0,0 +1,22 @@
+package com.baeldung.twitterhdfs.sink;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.stream.annotation.EnableBinding;
+import org.springframework.cloud.stream.app.hdfs.sink.HdfsSinkConfiguration;
+import org.springframework.cloud.stream.messaging.Sink;
+import org.springframework.context.annotation.Import;
+import org.springframework.integration.annotation.ServiceActivator;
+
+@SpringBootApplication
+@EnableBinding(Sink.class)
+@Import(HdfsSinkConfiguration.class)
+public class SinkApp {
+ Logger log = LoggerFactory.getLogger(SinkApp.class);
+
+ @ServiceActivator(inputChannel= Sink.INPUT)
+ public void loggerSink(Object payload) {
+ log.info("Received: " + payload);
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/source/SourceApp.java b/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/source/SourceApp.java
new file mode 100644
index 0000000000..f9b220561b
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/boot/src/main/java/com/baeldung/twitterhdfs/source/SourceApp.java
@@ -0,0 +1,26 @@
+package com.baeldung.twitterhdfs.source;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.stream.annotation.EnableBinding;
+import org.springframework.cloud.stream.app.twitterstream.source.TwitterstreamSourceConfiguration;
+import org.springframework.cloud.stream.messaging.Source;
+import org.springframework.context.annotation.Import;
+import org.springframework.integration.annotation.InboundChannelAdapter;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@SpringBootApplication
+@EnableBinding(Source.class)
+@Import(TwitterstreamSourceConfiguration.class)
+public class SourceApp {
+ Logger log = LoggerFactory.getLogger(SourceApp.class);
+
+ @InboundChannelAdapter(value = Source.OUTPUT)
+ public String timerMessageSource() {
+ return new SimpleDateFormat().format(new Date());
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-stream-starters/boot/src/main/resources/application.properties b/spring-cloud/spring-cloud-stream-starters/boot/src/main/resources/application.properties
new file mode 100644
index 0000000000..298a8ebf4d
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/boot/src/main/resources/application.properties
@@ -0,0 +1,6 @@
+hdfs.fs-uri=hdfs://127.0.0.1:50010/
+
+twitter.credentials.access-token=
+twitter.credentials.access-token-secret=
+twitter.credentials.consumer-key=
+twitter.credentials.consumer-secret=
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/hdfs/application.properties b/spring-cloud/spring-cloud-stream-starters/hdfs/application.properties
new file mode 100644
index 0000000000..1f4aaf88dd
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/hdfs/application.properties
@@ -0,0 +1 @@
+hdfs.fs-uri=hdfs://127.0.0.1:50010/
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/hdfs/hdfs.sh b/spring-cloud/spring-cloud-stream-starters/hdfs/hdfs.sh
new file mode 100644
index 0000000000..f1c6bfcf3f
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/hdfs/hdfs.sh
@@ -0,0 +1,11 @@
+# Git spring-cloud-stream-app-starters
+# https://github.com/spring-cloud-stream-app-starters/hdfs/blob/master/spring-cloud-starter-stream-sink-hdfs/README.adoc
+git clone https://github.com/spring-cloud-stream-app-starters/hdfs.git
+
+# Build it
+./mvnw clean install -PgenerateApps
+
+# Run it
+cd target
+# Optionally inject application.properties prior to build
+java -jar hdfs-sink.jar --fsUri=hdfs://127.0.0.1:50010/
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/twitter/application.properties b/spring-cloud/spring-cloud-stream-starters/twitter/application.properties
new file mode 100644
index 0000000000..e38612d25e
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/twitter/application.properties
@@ -0,0 +1,4 @@
+twitter.credentials.access-token=
+twitter.credentials.access-token-secret=
+twitter.credentials.consumer-key=
+twitter.credentials.consumer-secret=
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-stream-starters/twitter/twitter.sh b/spring-cloud/spring-cloud-stream-starters/twitter/twitter.sh
new file mode 100644
index 0000000000..967cb54dfe
--- /dev/null
+++ b/spring-cloud/spring-cloud-stream-starters/twitter/twitter.sh
@@ -0,0 +1,12 @@
+# Git spring-cloud-stream-app-starters
+# https://github.com/spring-cloud-stream-app-starters/hdfs/blob/master/spring-cloud-starter-stream-sink-hdfs/README.adoc
+git clone https://github.com/spring-cloud-stream-app-starters/twitter.git
+
+# Build it
+./mvnw clean install -PgenerateApps
+
+# Run it
+cd target
+# Optionally inject application.properties prior to build
+java -jar twitter_stream_source.jar --consumerKey= --consumerSecret= \
+ --accessToken= --accessTokenSecret=
\ No newline at end of file
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Person.java b/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Person.java
index b8ad59e2e2..09b971fdc2 100644
--- a/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Person.java
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/elasticsearch/Person.java
@@ -11,10 +11,9 @@ public class Person {
private Date dateOfBirth;
public Person() {
-
}
- public Person(int age, String fullName, Date dateOfBirth) {
+ Person(int age, String fullName, Date dateOfBirth) {
super();
this.age = age;
this.fullName = fullName;
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/repository/ArticleRepository.java b/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/repository/ArticleRepository.java
index 8aef865401..93812a3cea 100644
--- a/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/repository/ArticleRepository.java
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/repository/ArticleRepository.java
@@ -1,12 +1,13 @@
package com.baeldung.spring.data.es.repository;
-import com.baeldung.spring.data.es.model.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
+import com.baeldung.spring.data.es.model.Article;
+
@Repository
public interface ArticleRepository extends ElasticsearchRepository {
@@ -14,4 +15,10 @@ public interface ArticleRepository extends ElasticsearchRepository findByAuthorsNameUsingCustomQuery(String name, Pageable pageable);
+
+ @Query("{\"bool\": {\"must\": {\"match_all\": {}}, \"filter\": {\"term\": {\"tags\": \"?0\" }}}}")
+ Page findByFilteredTagQuery(String tag, Pageable pageable);
+
+ @Query("{\"bool\": {\"must\": {\"match\": {\"authors.name\": \"?0\"}}, \"filter\": {\"term\": {\"tags\": \"?1\" }}}}")
+ Page findByAuthorsNameAndFilteredTagQuery(String name, String tag, Pageable pageable);
}
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/service/ArticleService.java b/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/service/ArticleService.java
index b5a8fde633..63e2d91fa7 100644
--- a/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/service/ArticleService.java
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/service/ArticleService.java
@@ -1,9 +1,10 @@
package com.baeldung.spring.data.es.service;
-import com.baeldung.spring.data.es.model.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
+import com.baeldung.spring.data.es.model.Article;
+
public interface ArticleService {
Article save(Article article);
@@ -15,6 +16,10 @@ public interface ArticleService {
Page findByAuthorNameUsingCustomQuery(String name, Pageable pageable);
+ Page findByFilteredTagQuery(String tag, Pageable pageable);
+
+ Page findByAuthorsNameAndFilteredTagQuery(String name, String tag, Pageable pageable);
+
long count();
void delete(Article article);
diff --git a/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/service/ArticleServiceImpl.java b/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/service/ArticleServiceImpl.java
index 2a31b52602..0908ffa70e 100644
--- a/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/service/ArticleServiceImpl.java
+++ b/spring-data-elasticsearch/src/main/java/com/baeldung/spring/data/es/service/ArticleServiceImpl.java
@@ -1,12 +1,13 @@
package com.baeldung.spring.data.es.service;
-import com.baeldung.spring.data.es.repository.ArticleRepository;
-import com.baeldung.spring.data.es.model.Article;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
+import com.baeldung.spring.data.es.model.Article;
+import com.baeldung.spring.data.es.repository.ArticleRepository;
+
@Service
public class ArticleServiceImpl implements ArticleService {
@@ -42,6 +43,16 @@ public class ArticleServiceImpl implements ArticleService {
return articleRepository.findByAuthorsNameUsingCustomQuery(name, pageable);
}
+ @Override
+ public Page findByFilteredTagQuery(String tag, Pageable pageable) {
+ return articleRepository.findByFilteredTagQuery(tag, pageable);
+ }
+
+ @Override
+ public Page findByAuthorsNameAndFilteredTagQuery(String name, String tag, Pageable pageable) {
+ return articleRepository.findByAuthorsNameAndFilteredTagQuery(name, tag, pageable);
+ }
+
@Override
public long count() {
return articleRepository.count();
diff --git a/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java b/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java
index 1fb1ae76f7..285c164869 100644
--- a/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java
+++ b/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/ElasticSearchManualTest.java
@@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
+import java.util.stream.Collectors;
import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
import static org.junit.Assert.assertEquals;
@@ -78,12 +79,9 @@ public class ElasticSearchManualTest {
SearchHit[] searchHits = response
.getHits()
.getHits();
- List results = new ArrayList<>();
- for (SearchHit hit : searchHits) {
- String sourceAsString = hit.getSourceAsString();
- Person person = JSON.parseObject(sourceAsString, Person.class);
- results.add(person);
- }
+ List results = Arrays.stream(searchHits)
+ .map(hit -> JSON.parseObject(hit.getSourceAsString(), Person.class))
+ .collect(Collectors.toList());
}
@Test
@@ -125,11 +123,10 @@ public class ElasticSearchManualTest {
.actionGet();
response2.getHits();
response3.getHits();
- List searchHits = Arrays.asList(response
- .getHits()
- .getHits());
- final List results = new ArrayList<>();
- searchHits.forEach(hit -> results.add(JSON.parseObject(hit.getSourceAsString(), Person.class)));
+
+ final List results = Arrays.stream(response.getHits().getHits())
+ .map(hit -> JSON.parseObject(hit.getSourceAsString(), Person.class))
+ .collect(Collectors.toList());
}
@Test
diff --git a/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesTest.java b/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesTest.java
index 19514ce4c2..aa20913637 100644
--- a/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesTest.java
+++ b/spring-data-elasticsearch/src/test/java/com/baeldung/elasticsearch/GeoQueriesTest.java
@@ -1,11 +1,6 @@
package com.baeldung.elasticsearch;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
+import com.baeldung.spring.data.es.config.Config;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
@@ -15,6 +10,7 @@ import org.elasticsearch.common.geo.builders.ShapeBuilder;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -24,14 +20,19 @@ import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import com.baeldung.spring.data.es.config.Config;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
public class GeoQueriesTest {
- public static final String WONDERS_OF_WORLD = "wonders-of-world";
- public static final String WONDERS = "Wonders";
+ private static final String WONDERS_OF_WORLD = "wonders-of-world";
+ private static final String WONDERS = "Wonders";
+
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@@ -44,39 +45,37 @@ public class GeoQueriesTest {
CreateIndexRequest req = new CreateIndexRequest(WONDERS_OF_WORLD);
req.mapping(WONDERS, jsonObject);
client.admin()
- .indices()
- .create(req)
- .actionGet();
+ .indices()
+ .create(req)
+ .actionGet();
}
@Test
public void givenGeoShapeData_whenExecutedGeoShapeQuery_thenResultNonEmpty() {
String jsonObject = "{\"name\":\"Agra\",\"region\":{\"type\":\"envelope\",\"coordinates\":[[75,25],[80.1,30.2]]}}";
IndexResponse response = client.prepareIndex(WONDERS_OF_WORLD, WONDERS)
- .setSource(jsonObject)
- .get();
+ .setSource(jsonObject)
+ .get();
String tajMahalId = response.getId();
client.admin()
- .indices()
- .prepareRefresh(WONDERS_OF_WORLD)
- .get();
+ .indices()
+ .prepareRefresh(WONDERS_OF_WORLD)
+ .get();
QueryBuilder qb = QueryBuilders.geoShapeQuery("region", ShapeBuilder.newEnvelope()
- .topLeft(74.00, 24.0)
- .bottomRight(81.1, 31.2))
- .relation(ShapeRelation.WITHIN);
+ .topLeft(74.00, 24.0)
+ .bottomRight(81.1, 31.2))
+ .relation(ShapeRelation.WITHIN);
SearchResponse searchResponse = client.prepareSearch(WONDERS_OF_WORLD)
- .setTypes(WONDERS)
- .setQuery(qb)
- .execute()
- .actionGet();
+ .setTypes(WONDERS)
+ .setQuery(qb)
+ .execute()
+ .actionGet();
List ids = Arrays.stream(searchResponse.getHits()
- .getHits())
- .map(hit -> {
- return hit.getId();
- })
- .collect(Collectors.toList());
+ .getHits())
+ .map(SearchHit::getId)
+ .collect(Collectors.toList());
assertTrue(ids.contains(tajMahalId));
}
@@ -84,29 +83,27 @@ public class GeoQueriesTest {
public void givenGeoPointData_whenExecutedGeoBoundingBoxQuery_thenResultNonEmpty() {
String jsonObject = "{\"name\":\"Pyramids of Giza\",\"location\":[31.131302,29.976480]}";
IndexResponse response = client.prepareIndex(WONDERS_OF_WORLD, WONDERS)
- .setSource(jsonObject)
- .get();
+ .setSource(jsonObject)
+ .get();
String pyramidsOfGizaId = response.getId();
client.admin()
- .indices()
- .prepareRefresh(WONDERS_OF_WORLD)
- .get();
+ .indices()
+ .prepareRefresh(WONDERS_OF_WORLD)
+ .get();
QueryBuilder qb = QueryBuilders.geoBoundingBoxQuery("location")
- .bottomLeft(28, 30)
- .topRight(31, 32);
+ .bottomLeft(28, 30)
+ .topRight(31, 32);
SearchResponse searchResponse = client.prepareSearch(WONDERS_OF_WORLD)
- .setTypes(WONDERS)
- .setQuery(qb)
- .execute()
- .actionGet();
+ .setTypes(WONDERS)
+ .setQuery(qb)
+ .execute()
+ .actionGet();
List ids = Arrays.stream(searchResponse.getHits()
- .getHits())
- .map(hit -> {
- return hit.getId();
- })
- .collect(Collectors.toList());
+ .getHits())
+ .map(SearchHit::getId)
+ .collect(Collectors.toList());
assertTrue(ids.contains(pyramidsOfGizaId));
}
@@ -114,29 +111,27 @@ public class GeoQueriesTest {
public void givenGeoPointData_whenExecutedGeoDistanceQuery_thenResultNonEmpty() {
String jsonObject = "{\"name\":\"Lighthouse of alexandria\",\"location\":[31.131302,29.976480]}";
IndexResponse response = client.prepareIndex(WONDERS_OF_WORLD, WONDERS)
- .setSource(jsonObject)
- .get();
+ .setSource(jsonObject)
+ .get();
String lighthouseOfAlexandriaId = response.getId();
client.admin()
- .indices()
- .prepareRefresh(WONDERS_OF_WORLD)
- .get();
+ .indices()
+ .prepareRefresh(WONDERS_OF_WORLD)
+ .get();
QueryBuilder qb = QueryBuilders.geoDistanceQuery("location")
- .point(29.976, 31.131)
- .distance(10, DistanceUnit.MILES);
+ .point(29.976, 31.131)
+ .distance(10, DistanceUnit.MILES);
SearchResponse searchResponse = client.prepareSearch(WONDERS_OF_WORLD)
- .setTypes(WONDERS)
- .setQuery(qb)
- .execute()
- .actionGet();
+ .setTypes(WONDERS)
+ .setQuery(qb)
+ .execute()
+ .actionGet();
List ids = Arrays.stream(searchResponse.getHits()
- .getHits())
- .map(hit -> {
- return hit.getId();
- })
- .collect(Collectors.toList());
+ .getHits())
+ .map(SearchHit::getId)
+ .collect(Collectors.toList());
assertTrue(ids.contains(lighthouseOfAlexandriaId));
}
@@ -144,30 +139,28 @@ public class GeoQueriesTest {
public void givenGeoPointData_whenExecutedGeoPolygonQuery_thenResultNonEmpty() {
String jsonObject = "{\"name\":\"The Great Rann of Kutch\",\"location\":[69.859741,23.733732]}";
IndexResponse response = client.prepareIndex(WONDERS_OF_WORLD, WONDERS)
- .setSource(jsonObject)
- .get();
+ .setSource(jsonObject)
+ .get();
String greatRannOfKutchid = response.getId();
client.admin()
- .indices()
- .prepareRefresh(WONDERS_OF_WORLD)
- .get();
+ .indices()
+ .prepareRefresh(WONDERS_OF_WORLD)
+ .get();
QueryBuilder qb = QueryBuilders.geoPolygonQuery("location")
- .addPoint(22.733, 68.859)
- .addPoint(24.733, 68.859)
- .addPoint(23, 70.859);
+ .addPoint(22.733, 68.859)
+ .addPoint(24.733, 68.859)
+ .addPoint(23, 70.859);
SearchResponse searchResponse = client.prepareSearch(WONDERS_OF_WORLD)
- .setTypes(WONDERS)
- .setQuery(qb)
- .execute()
- .actionGet();
+ .setTypes(WONDERS)
+ .setQuery(qb)
+ .execute()
+ .actionGet();
List ids = Arrays.stream(searchResponse.getHits()
- .getHits())
- .map(hit -> {
- return hit.getId();
- })
- .collect(Collectors.toList());
+ .getHits())
+ .map(SearchHit::getId)
+ .collect(Collectors.toList());
assertTrue(ids.contains(greatRannOfKutchid));
}
@@ -175,5 +168,4 @@ public class GeoQueriesTest {
public void destroy() {
elasticsearchTemplate.deleteIndex(WONDERS_OF_WORLD);
}
-
}
diff --git a/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchIntegrationTest.java b/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchIntegrationTest.java
index 1280c8e1de..41965fbb83 100644
--- a/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchIntegrationTest.java
+++ b/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchIntegrationTest.java
@@ -1,15 +1,9 @@
package com.baeldung.spring.data.es;
-import static java.util.Arrays.asList;
-import static org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND;
-import static org.elasticsearch.index.query.QueryBuilders.fuzzyQuery;
-import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
-import static org.elasticsearch.index.query.QueryBuilders.regexpQuery;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.util.List;
-
+import com.baeldung.spring.data.es.config.Config;
+import com.baeldung.spring.data.es.model.Article;
+import com.baeldung.spring.data.es.model.Author;
+import com.baeldung.spring.data.es.service.ArticleService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -22,10 +16,15 @@ import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import com.baeldung.spring.data.es.config.Config;
-import com.baeldung.spring.data.es.model.Article;
-import com.baeldung.spring.data.es.model.Author;
-import com.baeldung.spring.data.es.service.ArticleService;
+import java.util.List;
+
+import static java.util.Arrays.asList;
+import static org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND;
+import static org.elasticsearch.index.query.QueryBuilders.fuzzyQuery;
+import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
+import static org.elasticsearch.index.query.QueryBuilders.regexpQuery;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
@@ -47,14 +46,22 @@ public class ElasticSearchIntegrationTest {
Article article = new Article("Spring Data Elasticsearch");
article.setAuthors(asList(johnSmith, johnDoe));
+ article.setTags("elasticsearch", "spring data");
articleService.save(article);
article = new Article("Search engines");
article.setAuthors(asList(johnDoe));
+ article.setTags("search engines", "tutorial");
articleService.save(article);
article = new Article("Second Article About Elasticsearch");
article.setAuthors(asList(johnSmith));
+ article.setTags("elasticsearch", "spring data");
+ articleService.save(article);
+
+ article = new Article("Elasticsearch Tutorial");
+ article.setAuthors(asList(johnDoe));
+ article.setTags("elasticsearch");
articleService.save(article);
}
@@ -72,21 +79,34 @@ public class ElasticSearchIntegrationTest {
@Test
public void givenPersistedArticles_whenSearchByAuthorsName_thenRightFound() {
- final Page articleByAuthorName = articleService.findByAuthorName(johnSmith.getName(), new PageRequest(0, 10));
+ final Page articleByAuthorName = articleService
+ .findByAuthorName(johnSmith.getName(), new PageRequest(0, 10));
assertEquals(2L, articleByAuthorName.getTotalElements());
}
@Test
public void givenCustomQuery_whenSearchByAuthorsName_thenArticleIsFound() {
+ final Page articleByAuthorName = articleService.findByAuthorNameUsingCustomQuery("Smith", new PageRequest(0, 10));
+ assertEquals(2L, articleByAuthorName.getTotalElements());
+ }
- final Page articleByAuthorName = articleService.findByAuthorNameUsingCustomQuery("John Smith", new PageRequest(0, 10));
+ @Test
+ public void givenTagFilterQuery_whenSearchByTag_thenArticleIsFound() {
+ final Page articleByAuthorName = articleService.findByFilteredTagQuery("elasticsearch", new PageRequest(0, 10));
assertEquals(3L, articleByAuthorName.getTotalElements());
}
+ @Test
+ public void givenTagFilterQuery_whenSearchByAuthorsName_thenArticleIsFound() {
+ final Page articleByAuthorName = articleService.findByAuthorsNameAndFilteredTagQuery("Doe", "elasticsearch", new PageRequest(0, 10));
+ assertEquals(2L, articleByAuthorName.getTotalElements());
+ }
+
@Test
public void givenPersistedArticles_whenUseRegexQuery_thenRightArticlesFound() {
- final SearchQuery searchQuery = new NativeSearchQueryBuilder().withFilter(regexpQuery("title", ".*data.*")).build();
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder().withFilter(regexpQuery("title", ".*data.*"))
+ .build();
final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
@@ -112,7 +132,8 @@ public class ElasticSearchIntegrationTest {
final String articleTitle = "Spring Data Elasticsearch";
- final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%")).build();
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%")).build();
final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
final long count = articleService.count();
@@ -124,7 +145,8 @@ public class ElasticSearchIntegrationTest {
@Test
public void givenSavedDoc_whenOneTermMatches_thenFindByTitle() {
- final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(AND)).build();
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(matchQuery("title", "Search engines").operator(AND)).build();
final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
}
diff --git a/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryIntegrationTest.java b/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryIntegrationTest.java
index cc4bce0c75..c6af93bb62 100644
--- a/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryIntegrationTest.java
+++ b/spring-data-elasticsearch/src/test/java/com/baeldung/spring/data/es/ElasticSearchQueryIntegrationTest.java
@@ -1,20 +1,9 @@
package com.baeldung.spring.data.es;
-import static java.util.Arrays.asList;
-import static java.util.stream.Collectors.toList;
-import static org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND;
-import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
-import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;
-import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
-import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery;
-import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
-import static org.elasticsearch.index.query.QueryBuilders.termQuery;
-import static org.junit.Assert.assertEquals;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
+import com.baeldung.spring.data.es.config.Config;
+import com.baeldung.spring.data.es.model.Article;
+import com.baeldung.spring.data.es.model.Author;
+import com.baeldung.spring.data.es.service.ArticleService;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.unit.Fuzziness;
@@ -22,6 +11,7 @@ import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
@@ -35,10 +25,20 @@ import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import com.baeldung.spring.data.es.config.Config;
-import com.baeldung.spring.data.es.model.Article;
-import com.baeldung.spring.data.es.model.Author;
-import com.baeldung.spring.data.es.service.ArticleService;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toList;
+import static org.elasticsearch.index.query.MatchQueryBuilder.Operator.AND;
+import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
+import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;
+import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
+import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery;
+import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
+import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+import static org.junit.Assert.assertEquals;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
@@ -86,14 +86,16 @@ public class ElasticSearchQueryIntegrationTest {
@Test
public void givenFullTitle_whenRunMatchQuery_thenDocIsFound() {
- final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Search engines").operator(AND)).build();
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(matchQuery("title", "Search engines").operator(AND)).build();
final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
}
@Test
public void givenOneTermFromTitle_whenRunMatchQuery_thenDocIsFound() {
- final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "Engines Solutions")).build();
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(matchQuery("title", "Engines Solutions")).build();
final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
assertEquals("Search engines", articles.get(0).getTitle());
@@ -101,18 +103,21 @@ public class ElasticSearchQueryIntegrationTest {
@Test
public void givenPartTitle_whenRunMatchQuery_thenDocIsFound() {
- final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "elasticsearch data")).build();
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(matchQuery("title", "elasticsearch data")).build();
final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(3, articles.size());
}
@Test
public void givenFullTitle_whenRunMatchQueryOnVerbatimField_thenDocIsFound() {
- SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About Elasticsearch")).build();
+ SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(matchQuery("title.verbatim", "Second Article About Elasticsearch")).build();
List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
- searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About")).build();
+ searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title.verbatim", "Second Article About"))
+ .build();
articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(0, articles.size());
}
@@ -130,38 +135,48 @@ public class ElasticSearchQueryIntegrationTest {
@Test
public void givenAnalyzedQuery_whenMakeAggregationOnTermCount_thenEachTokenCountsSeparately() {
final TermsBuilder aggregation = AggregationBuilders.terms("top_tags").field("title");
- final SearchResponse response = client.prepareSearch("blog").setTypes("article").addAggregation(aggregation).execute().actionGet();
+ final SearchResponse response = client.prepareSearch("blog").setTypes("article").addAggregation(aggregation)
+ .execute().actionGet();
final Map results = response.getAggregations().asMap();
final StringTerms topTags = (StringTerms) results.get("top_tags");
- final List keys = topTags.getBuckets().stream().map(b -> b.getKeyAsString()).collect(toList());
- Collections.sort(keys);
+ final List keys = topTags.getBuckets().stream()
+ .map(MultiBucketsAggregation.Bucket::getKeyAsString)
+ .sorted()
+ .collect(toList());
assertEquals(asList("about", "article", "data", "elasticsearch", "engines", "search", "second", "spring", "tutorial"), keys);
}
@Test
public void givenNotAnalyzedQuery_whenMakeAggregationOnTermCount_thenEachTermCountsIndividually() {
- final TermsBuilder aggregation = AggregationBuilders.terms("top_tags").field("tags").order(Terms.Order.aggregation("_count", false));
- final SearchResponse response = client.prepareSearch("blog").setTypes("article").addAggregation(aggregation).execute().actionGet();
+ final TermsBuilder aggregation = AggregationBuilders.terms("top_tags").field("tags")
+ .order(Terms.Order.aggregation("_count", false));
+ final SearchResponse response = client.prepareSearch("blog").setTypes("article").addAggregation(aggregation)
+ .execute().actionGet();
final Map results = response.getAggregations().asMap();
final StringTerms topTags = (StringTerms) results.get("top_tags");
- final List keys = topTags.getBuckets().stream().map(b -> b.getKeyAsString()).collect(toList());
+ final List keys = topTags.getBuckets().stream()
+ .map(MultiBucketsAggregation.Bucket::getKeyAsString)
+ .collect(toList());
assertEquals(asList("elasticsearch", "spring data", "search engines", "tutorial"), keys);
}
@Test
public void givenNotExactPhrase_whenUseSlop_thenQueryMatches() {
- final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchPhraseQuery("title", "spring elasticsearch").slop(1)).build();
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(matchPhraseQuery("title", "spring elasticsearch").slop(1)).build();
final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
}
@Test
public void givenPhraseWithType_whenUseFuzziness_thenQueryMatches() {
- final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("title", "spring date elasticserch").operator(AND).fuzziness(Fuzziness.ONE).prefixLength(3)).build();
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(matchQuery("title", "spring date elasticserch").operator(AND).fuzziness(Fuzziness.ONE)
+ .prefixLength(3)).build();
final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(1, articles.size());
@@ -169,9 +184,23 @@ public class ElasticSearchQueryIntegrationTest {
@Test
public void givenMultimatchQuery_whenDoSearch_thenAllProvidedFieldsMatch() {
- final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(multiMatchQuery("tutorial").field("title").field("tags").type(MultiMatchQueryBuilder.Type.BEST_FIELDS)).build();
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder()
+ .withQuery(multiMatchQuery("tutorial").field("title").field("tags")
+ .type(MultiMatchQueryBuilder.Type.BEST_FIELDS)).build();
final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
assertEquals(2, articles.size());
}
+
+ @Test
+ public void givenBoolQuery_whenQueryByAuthorsName_thenFoundArticlesByThatAuthorAndFilteredTag() {
+ final QueryBuilder builder = boolQuery().must(nestedQuery("authors", boolQuery().must(termQuery("authors.name", "doe"))))
+ .filter(termQuery("tags", "elasticsearch"));
+
+ final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder)
+ .build();
+ final List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
+
+ assertEquals(2, articles.size());
+ }
}
diff --git a/spring-data-spring-security/README.md b/spring-data-spring-security/README.md
new file mode 100644
index 0000000000..15b4b50870
--- /dev/null
+++ b/spring-data-spring-security/README.md
@@ -0,0 +1,14 @@
+# About this project
+This project contains examples from the [Spring Data with Spring Security](http://www.baeldung.com/spring-data-with-spring-security) article from Baeldung.
+
+# Running the project
+The application uses [Spring Boot](http://projects.spring.io/spring-boot/), so it is easy to run. You can start it any of a few ways:
+* Run the `main` method from `SpringDataRestApplication`
+* Use the Maven Spring Boot plugin: `mvn spring-boot:run`
+* Package the application as a JAR and run it using `java -jar spring-data-spring-security.jar`
+
+# Viewing the running application
+To view the running application, visit [http://localhost:8080](http://localhost:8080) in your browser
+
+###Relevant Articles:
+- [Spring Data with Spring Security](http://www.baeldung.com/spring-data-with-spring-security)
diff --git a/spring-data-spring-security/pom.xml b/spring-data-spring-security/pom.xml
new file mode 100644
index 0000000000..d6b671ee57
--- /dev/null
+++ b/spring-data-spring-security/pom.xml
@@ -0,0 +1,67 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ spring-data-spring-security
+ 1.0
+ jar
+
+ intro-spring-data-spring-security
+ Spring Data with Spring Security
+
+
+ parent-boot-5
+ com.baeldung
+ 0.0.1-SNAPSHOT
+ ../parent-boot-5
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.security
+ spring-security-data
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+ org.apache.tomcat.embed
+ tomcat-embed-jasper
+
+
+
+ com.h2database
+ h2
+
+
+ javax.servlet
+ jstl
+
+
+
+
+ ${project.artifactId}
+
+
+
+
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/AppConfig.java b/spring-data-spring-security/src/main/java/com/baeldung/AppConfig.java
new file mode 100644
index 0000000000..16bbe8b326
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/AppConfig.java
@@ -0,0 +1,64 @@
+package com.baeldung;
+
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+@SpringBootApplication
+@PropertySource("classpath:persistence-h2.properties")
+@EnableJpaRepositories(basePackages = { "com.baeldung.data.repositories" })
+@EnableWebMvc
+@Import(SpringSecurityConfig.class)
+public class AppConfig extends WebMvcConfigurerAdapter {
+
+ @Autowired
+ private Environment env;
+
+ @Bean
+ public DataSource dataSource() {
+ final DriverManagerDataSource dataSource = new DriverManagerDataSource();
+ dataSource.setDriverClassName(env.getProperty("driverClassName"));
+ dataSource.setUrl(env.getProperty("url"));
+ dataSource.setUsername(env.getProperty("user"));
+ dataSource.setPassword(env.getProperty("password"));
+ return dataSource;
+ }
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
+ final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
+ em.setDataSource(dataSource());
+ em.setPackagesToScan(new String[] { "com.baeldung.models" });
+ em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
+ em.setJpaProperties(additionalProperties());
+ return em;
+ }
+
+ final Properties additionalProperties() {
+ final Properties hibernateProperties = new Properties();
+ if (env.getProperty("hibernate.hbm2ddl.auto") != null) {
+ hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
+ }
+ if (env.getProperty("hibernate.dialect") != null) {
+ hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
+ }
+ if (env.getProperty("hibernate.show_sql") != null) {
+ hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
+ }
+ return hibernateProperties;
+ }
+
+}
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/SpringSecurityConfig.java b/spring-data-spring-security/src/main/java/com/baeldung/SpringSecurityConfig.java
new file mode 100644
index 0000000000..ee13678a24
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/SpringSecurityConfig.java
@@ -0,0 +1,89 @@
+package com.baeldung;
+
+import javax.annotation.PostConstruct;
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.security.AuthenticationSuccessHandlerImpl;
+import com.baeldung.security.CustomUserDetailsService;
+
+@Configuration
+@EnableWebSecurity
+@ComponentScan("com.baeldung.security")
+public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Autowired
+ private WebApplicationContext applicationContext;
+ private CustomUserDetailsService userDetailsService;
+ @Autowired
+ private AuthenticationSuccessHandlerImpl successHandler;
+ @Autowired
+ private DataSource dataSource;
+
+ @PostConstruct
+ public void completeSetup() {
+ userDetailsService = applicationContext.getBean(CustomUserDetailsService.class);
+ }
+
+ @Override
+ protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
+ auth.userDetailsService(userDetailsService)
+ .passwordEncoder(encoder())
+ .and()
+ .authenticationProvider(authenticationProvider())
+ .jdbcAuthentication()
+ .dataSource(dataSource);
+ }
+
+ @Override
+ public void configure(WebSecurity web) throws Exception {
+ web.ignoring()
+ .antMatchers("/resources/**");
+ }
+
+ @Override
+ protected void configure(final HttpSecurity http) throws Exception {
+ http.authorizeRequests()
+ .antMatchers("/login")
+ .permitAll()
+ .and()
+ .formLogin()
+ .permitAll()
+ .successHandler(successHandler)
+ .and()
+ .csrf()
+ .disable();
+ }
+
+ @Bean
+ public DaoAuthenticationProvider authenticationProvider() {
+ final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
+ authProvider.setUserDetailsService(userDetailsService);
+ authProvider.setPasswordEncoder(encoder());
+ return authProvider;
+ }
+
+ @Bean
+ public PasswordEncoder encoder() {
+ return new BCryptPasswordEncoder(11);
+ }
+
+ @Bean
+ public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
+ return new SecurityEvaluationContextExtension();
+ }
+}
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/TweetRepository.java b/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/TweetRepository.java
new file mode 100644
index 0000000000..7d6446ed0d
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/TweetRepository.java
@@ -0,0 +1,14 @@
+package com.baeldung.data.repositories;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import com.baeldung.models.Tweet;
+
+public interface TweetRepository extends PagingAndSortingRepository {
+
+ @Query("select twt from Tweet twt JOIN twt.likes as lk where lk = ?#{ principal?.username } or twt.owner = ?#{ principal?.username }")
+ Page getMyTweetsAndTheOnesILiked(Pageable pageable);
+}
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/UserRepository.java b/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/UserRepository.java
new file mode 100644
index 0000000000..9f13c3197e
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/UserRepository.java
@@ -0,0 +1,27 @@
+package com.baeldung.data.repositories;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.models.AppUser;
+import com.baeldung.models.Tweet;
+
+public interface UserRepository extends CrudRepository {
+ AppUser findByUsername(String username);
+
+ List findByName(String name);
+
+ @Query("UPDATE AppUser u SET u.lastLogin=:lastLogin WHERE u.username = ?#{ principal?.username }")
+ @Modifying
+ @Transactional
+ public void updateLastLogin(@Param("lastLogin") Date lastLogin);
+}
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/models/AppUser.java b/spring-data-spring-security/src/main/java/com/baeldung/models/AppUser.java
new file mode 100644
index 0000000000..e48233f90a
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/models/AppUser.java
@@ -0,0 +1,83 @@
+package com.baeldung.models;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "users")
+public class AppUser {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ private long id;
+
+ private String name;
+ @Column(unique = true)
+ private String username;
+ private String password;
+ private boolean enabled = true;
+ private Date lastLogin;
+
+ private AppUser() {
+ }
+
+ public AppUser(String name, String email, String password) {
+ this.username = email;
+ this.name = name;
+ this.password = password;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Date getLastLogin() {
+ return lastLogin;
+ }
+
+ public void setLastLogin(Date lastLogin) {
+ this.lastLogin = lastLogin;
+ }
+}
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/models/Tweet.java b/spring-data-spring-security/src/main/java/com/baeldung/models/Tweet.java
new file mode 100644
index 0000000000..b2e45009f6
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/models/Tweet.java
@@ -0,0 +1,63 @@
+package com.baeldung.models;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Tweet {
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ private long id;
+ private String tweet;
+ private String owner;
+ @ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
+ private Set likes = new HashSet();
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ private Tweet() {
+ }
+
+ public Tweet(String tweet, String owner) {
+ this.tweet = tweet;
+ this.owner = owner;
+ }
+
+ public String getTweet() {
+ return tweet;
+ }
+
+ public void setTweet(String tweet) {
+ this.tweet = tweet;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public void setOwner(String owner) {
+ this.owner = owner;
+ }
+
+ public Set getLikes() {
+ return likes;
+ }
+
+ public void setLikes(Set likes) {
+ this.likes = likes;
+ }
+
+}
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/security/AppUserPrincipal.java b/spring-data-spring-security/src/main/java/com/baeldung/security/AppUserPrincipal.java
new file mode 100644
index 0000000000..195f9f7bf6
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/security/AppUserPrincipal.java
@@ -0,0 +1,67 @@
+package com.baeldung.security;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import com.baeldung.models.AppUser;
+
+public class AppUserPrincipal implements UserDetails {
+
+ private final AppUser user;
+
+ //
+
+ public AppUserPrincipal(AppUser user) {
+ this.user = user;
+ }
+
+ //
+
+ @Override
+ public String getUsername() {
+ return user.getUsername();
+ }
+
+ @Override
+ public String getPassword() {
+ return user.getPassword();
+ }
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ final List authorities = Collections.singletonList(new SimpleGrantedAuthority("User"));
+ return authorities;
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ //
+
+ public AppUser getAppUser() {
+ return user;
+ }
+
+}
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/security/AuthenticationSuccessHandlerImpl.java b/spring-data-spring-security/src/main/java/com/baeldung/security/AuthenticationSuccessHandlerImpl.java
new file mode 100644
index 0000000000..3fc2bc6559
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/security/AuthenticationSuccessHandlerImpl.java
@@ -0,0 +1,28 @@
+package com.baeldung.security;
+
+import java.io.IOException;
+import java.util.Date;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.stereotype.Component;
+
+import com.baeldung.data.repositories.UserRepository;
+
+@Component
+public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Override
+ public void onAuthenticationSuccess(HttpServletRequest arg0, HttpServletResponse arg1, Authentication arg2) throws IOException, ServletException {
+ userRepository.updateLastLogin(new Date());
+ }
+
+}
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/security/CustomUserDetailsService.java b/spring-data-spring-security/src/main/java/com/baeldung/security/CustomUserDetailsService.java
new file mode 100644
index 0000000000..016f4f7fa9
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/security/CustomUserDetailsService.java
@@ -0,0 +1,40 @@
+package com.baeldung.security;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.baeldung.data.repositories.UserRepository;
+import com.baeldung.models.AppUser;
+
+@Service
+public class CustomUserDetailsService implements UserDetailsService {
+
+ @Autowired
+ private WebApplicationContext applicationContext;
+ private UserRepository userRepository;
+
+ public CustomUserDetailsService() {
+ super();
+ }
+
+ @PostConstruct
+ public void completeSetup() {
+ userRepository = applicationContext.getBean(UserRepository.class);
+ }
+
+ @Override
+ public UserDetails loadUserByUsername(final String username) {
+ final AppUser appUser = userRepository.findByUsername(username);
+ if (appUser == null) {
+ throw new UsernameNotFoundException(username);
+ }
+ return new AppUserPrincipal(appUser);
+ }
+
+}
diff --git a/spring-data-spring-security/src/main/java/com/baeldung/util/DummyContentUtil.java b/spring-data-spring-security/src/main/java/com/baeldung/util/DummyContentUtil.java
new file mode 100644
index 0000000000..f1640264d2
--- /dev/null
+++ b/spring-data-spring-security/src/main/java/com/baeldung/util/DummyContentUtil.java
@@ -0,0 +1,63 @@
+package com.baeldung.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+import com.baeldung.models.AppUser;
+import com.baeldung.models.Tweet;
+
+public class DummyContentUtil {
+
+ public static final List generateDummyUsers() {
+ List appUsers = new ArrayList<>();
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ appUsers.add(new AppUser("Lionel Messi", "lionel@messi.com", passwordEncoder.encode("li1234")));
+ appUsers.add(new AppUser("Cristiano Ronaldo", "cristiano@ronaldo.com", passwordEncoder.encode("c1234")));
+ appUsers.add(new AppUser("Neymar Dos Santos", "neymar@neymar.com", passwordEncoder.encode("n1234")));
+ appUsers.add(new AppUser("Luiz Suarez", "luiz@suarez.com", passwordEncoder.encode("lu1234")));
+ appUsers.add(new AppUser("Andres Iniesta", "andres@iniesta.com", passwordEncoder.encode("a1234")));
+ appUsers.add(new AppUser("Ivan Rakitic", "ivan@rakitic.com", passwordEncoder.encode("i1234")));
+ appUsers.add(new AppUser("Ousman Dembele", "ousman@dembele.com", passwordEncoder.encode("o1234")));
+ appUsers.add(new AppUser("Sergio Busquet", "sergio@busquet.com", passwordEncoder.encode("s1234")));
+ appUsers.add(new AppUser("Gerard Pique", "gerard@pique.com", passwordEncoder.encode("g1234")));
+ appUsers.add(new AppUser("Ter Stergen", "ter@stergen.com", passwordEncoder.encode("t1234")));
+ return appUsers;
+ }
+
+ public static final List generateDummyTweets(List users) {
+ List tweets = new ArrayList<>();
+ Random random = new Random();
+ IntStream.range(0, 9)
+ .sequential()
+ .forEach(i -> {
+ Tweet twt = new Tweet(String.format("Tweet %d", i), users.get(random.nextInt(users.size()))
+ .getUsername());
+ twt.getLikes()
+ .addAll(users.subList(0, random.nextInt(users.size()))
+ .stream()
+ .map(AppUser::getUsername)
+ .collect(Collectors.toSet()));
+ tweets.add(twt);
+ });
+ return tweets;
+ }
+
+ public static Collection getAuthorities() {
+ Collection grantedAuthorities = new ArrayList();
+ GrantedAuthority grantedAuthority = new GrantedAuthority() {
+ public String getAuthority() {
+ return "ROLE_USER";
+ }
+ };
+ grantedAuthorities.add(grantedAuthority);
+ return grantedAuthorities;
+ }
+
+}
diff --git a/spring-data-spring-security/src/main/resources/application.properties b/spring-data-spring-security/src/main/resources/application.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/spring-data-spring-security/src/main/resources/persistence-h2.properties b/spring-data-spring-security/src/main/resources/persistence-h2.properties
new file mode 100644
index 0000000000..a4b2af6361
--- /dev/null
+++ b/spring-data-spring-security/src/main/resources/persistence-h2.properties
@@ -0,0 +1,8 @@
+driverClassName=org.h2.Driver
+url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1
+username=sa
+password=
+
+hibernate.dialect=org.hibernate.dialect.H2Dialect
+hibernate.show_sql=false
+hibernate.hbm2ddl.auto=create-drop
\ No newline at end of file
diff --git a/spring-data-spring-security/src/test/java/com/baeldung/relationships/SpringDataWithSecurityTest.java b/spring-data-spring-security/src/test/java/com/baeldung/relationships/SpringDataWithSecurityTest.java
new file mode 100644
index 0000000000..dbbfe7e85e
--- /dev/null
+++ b/spring-data-spring-security/src/test/java/com/baeldung/relationships/SpringDataWithSecurityTest.java
@@ -0,0 +1,100 @@
+package com.baeldung.relationships;
+
+import static org.springframework.util.Assert.isTrue;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+
+import com.baeldung.AppConfig;
+import com.baeldung.data.repositories.TweetRepository;
+import com.baeldung.data.repositories.UserRepository;
+import com.baeldung.models.AppUser;
+import com.baeldung.models.Tweet;
+import com.baeldung.security.AppUserPrincipal;
+import com.baeldung.util.DummyContentUtil;
+
+@RunWith(SpringRunner.class)
+@WebAppConfiguration
+@ContextConfiguration
+@DirtiesContext
+public class SpringDataWithSecurityTest {
+ AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
+ @Autowired
+ private ServletContext servletContext;
+ private static UserRepository userRepository;
+ private static TweetRepository tweetRepository;
+
+ @Before
+ public void testInit() {
+ ctx.register(AppConfig.class);
+ ctx.setServletContext(servletContext);
+ ctx.refresh();
+ userRepository = ctx.getBean(UserRepository.class);
+ tweetRepository = ctx.getBean(TweetRepository.class);
+ List appUsers = (List) userRepository.save(DummyContentUtil.generateDummyUsers());
+ tweetRepository.save(DummyContentUtil.generateDummyTweets(appUsers));
+ }
+
+ @AfterClass
+ public static void tearDown() {
+ tweetRepository.deleteAll();
+ userRepository.deleteAll();
+ }
+
+ @Test
+ public void givenAppUser_whenLoginSuccessful_shouldUpdateLastLogin() {
+ AppUser appUser = userRepository.findByUsername("lionel@messi.com");
+ Authentication auth = new UsernamePasswordAuthenticationToken(new AppUserPrincipal(appUser), null, DummyContentUtil.getAuthorities());
+ SecurityContextHolder.getContext()
+ .setAuthentication(auth);
+ userRepository.updateLastLogin(new Date());
+ }
+
+ @Test(expected = InvalidDataAccessApiUsageException.class)
+ public void givenNoAppUserInSecurityContext_whenUpdateLastLoginAttempted_shouldFail() {
+ userRepository.updateLastLogin(new Date());
+ }
+
+ @Test
+ public void givenAppUser_whenLoginSuccessful_shouldReadMyPagedTweets() {
+ AppUser appUser = userRepository.findByUsername("lionel@messi.com");
+ Authentication auth = new UsernamePasswordAuthenticationToken(new AppUserPrincipal(appUser), null, DummyContentUtil.getAuthorities());
+ SecurityContextHolder.getContext()
+ .setAuthentication(auth);
+ Page page = null;
+ do {
+ page = tweetRepository.getMyTweetsAndTheOnesILiked(new PageRequest(page != null ? page.getNumber() + 1 : 0, 5));
+ for (Tweet twt : page.getContent()) {
+ isTrue((twt.getOwner() == appUser.getUsername()) || (twt.getLikes()
+ .contains(appUser.getUsername())), "I do not have any Tweets");
+ }
+ } while (page.hasNext());
+ }
+
+ @Test(expected = InvalidDataAccessApiUsageException.class)
+ public void givenNoAppUser_whenPaginatedResultsRetrievalAttempted_shouldFail() {
+ Page page = null;
+ do {
+ page = tweetRepository.getMyTweetsAndTheOnesILiked(new PageRequest(page != null ? page.getNumber() + 1 : 0, 5));
+ } while (page != null && page.hasNext());
+ }
+}
diff --git a/spring-jinq/pom.xml b/spring-jinq/pom.xml
new file mode 100644
index 0000000000..a895ae8dd4
--- /dev/null
+++ b/spring-jinq/pom.xml
@@ -0,0 +1,83 @@
+
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+ 4.0.0
+ spring-jinq
+ 0.1-SNAPSHOT
+
+ spring-jinq
+
+ jar
+
+
+ UTF-8
+ 1.8
+
+ 1.8.22
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ 1.5.9.RELEASE
+ pom
+ import
+
+
+
+
+
+
+ org.jinq
+ jinq-jpa
+ ${jinq.version}
+
+
+
+
+ com.h2database
+ h2
+
+
+
+ org.hibernate
+ hibernate-entitymanager
+
+
+
+
+ org.springframework
+ spring-orm
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+ false
+
+
+
+
+
+
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/JinqApplication.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/JinqApplication.java
new file mode 100644
index 0000000000..d53b585d36
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/JinqApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.spring.jinq;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class JinqApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(JinqApplication.class, args);
+ }
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/config/JinqProviderConfiguration.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/config/JinqProviderConfiguration.java
new file mode 100644
index 0000000000..6d921045b7
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/config/JinqProviderConfiguration.java
@@ -0,0 +1,18 @@
+package com.baeldung.spring.jinq.config;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.jinq.jpa.JinqJPAStreamProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class JinqProviderConfiguration {
+
+ @Bean
+ @Autowired
+ JinqJPAStreamProvider jinqProvider(EntityManagerFactory emf) {
+ return new JinqJPAStreamProvider(emf);
+ }
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Car.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Car.java
new file mode 100644
index 0000000000..263e6c7622
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Car.java
@@ -0,0 +1,58 @@
+package com.baeldung.spring.jinq.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+
+@Entity(name = "CAR")
+public class Car {
+ private String model;
+ private String description;
+ private int year;
+ private String engine;
+ private Manufacturer manufacturer;
+
+ @Id
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ public String getEngine() {
+ return engine;
+ }
+
+ public void setEngine(String engine) {
+ this.engine = engine;
+ }
+
+ @OneToOne
+ @JoinColumn(name = "name")
+ public Manufacturer getManufacturer() {
+ return manufacturer;
+ }
+
+ public void setManufacturer(Manufacturer manufacturer) {
+ this.manufacturer = manufacturer;
+ }
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Manufacturer.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Manufacturer.java
new file mode 100644
index 0000000000..f6e5fd23de
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Manufacturer.java
@@ -0,0 +1,42 @@
+package com.baeldung.spring.jinq.entities;
+
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+
+@Entity(name = "MANUFACTURER")
+public class Manufacturer {
+
+ private String name;
+ private String city;
+ private List cars;
+
+ @Id
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ @OneToMany(mappedBy = "model")
+ public List getCars() {
+ return cars;
+ }
+
+ public void setCars(List cars) {
+ this.cars = cars;
+ }
+
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/BaseJinqRepositoryImpl.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/BaseJinqRepositoryImpl.java
new file mode 100644
index 0000000000..42b81ecc59
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/BaseJinqRepositoryImpl.java
@@ -0,0 +1,26 @@
+package com.baeldung.spring.jinq.repositories;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.jinq.jpa.JPAJinqStream;
+import org.jinq.jpa.JinqJPAStreamProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public abstract class BaseJinqRepositoryImpl {
+ @Autowired
+ private JinqJPAStreamProvider jinqDataProvider;
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ protected abstract Class entityType();
+
+ public JPAJinqStream stream() {
+ return streamOf(entityType());
+ }
+
+ protected JPAJinqStream streamOf(Class clazz) {
+ return jinqDataProvider.streamAll(entityManager, clazz);
+ }
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepository.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepository.java
new file mode 100644
index 0000000000..56f6106e08
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepository.java
@@ -0,0 +1,27 @@
+package com.baeldung.spring.jinq.repositories;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.jinq.tuples.Pair;
+import org.jinq.tuples.Tuple3;
+
+import com.baeldung.spring.jinq.entities.Car;
+import com.baeldung.spring.jinq.entities.Manufacturer;
+
+public interface CarRepository {
+
+ Optional findByModel(String model);
+
+ List findByModelAndDescription(String model, String desc);
+
+ List> findWithModelYearAndEngine();
+
+ Optional findManufacturerByModel(String model);
+
+ List> findCarsPerManufacturer();
+
+ long countCarsByModel(String model);
+
+ List findAll(int skip, int limit);
+}
diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepositoryImpl.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepositoryImpl.java
new file mode 100644
index 0000000000..bf16c87461
--- /dev/null
+++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepositoryImpl.java
@@ -0,0 +1,72 @@
+package com.baeldung.spring.jinq.repositories;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.jinq.orm.stream.JinqStream;
+import org.jinq.tuples.Pair;
+import org.jinq.tuples.Tuple3;
+import org.springframework.stereotype.Repository;
+
+import com.baeldung.spring.jinq.entities.Car;
+import com.baeldung.spring.jinq.entities.Manufacturer;
+
+@Repository
+public class CarRepositoryImpl extends BaseJinqRepositoryImpl implements CarRepository {
+
+ @Override
+ public Optional findByModel(String model) {
+ return stream().where(c -> c.getModel()
+ .equals(model))
+ .findFirst();
+ }
+
+ @Override
+ public List findByModelAndDescription(String model, String desc) {
+ return stream().where(c -> c.getModel()
+ .equals(model)
+ && c.getDescription()
+ .contains(desc))
+ .toList();
+ }
+
+ @Override
+ public List> findWithModelYearAndEngine() {
+ return stream().select(c -> new Tuple3<>(c.getModel(), c.getYear(), c.getEngine()))
+ .toList();
+ }
+
+ @Override
+ public Optional findManufacturerByModel(String model) {
+ return stream().where(c -> c.getModel()
+ .equals(model))
+ .select(c -> c.getManufacturer())
+ .findFirst();
+ }
+
+ @Override
+ public List> findCarsPerManufacturer() {
+ return streamOf(Manufacturer.class).join(m -> JinqStream.from(m.getCars()))
+ .toList();
+ }
+
+ @Override
+ public long countCarsByModel(String model) {
+ return stream().where(c -> c.getModel()
+ .equals(model))
+ .count();
+ }
+
+ @Override
+ public List findAll(int skip, int limit) {
+ return stream().skip(skip)
+ .limit(limit)
+ .toList();
+ }
+
+ @Override
+ protected Class entityType() {
+ return Car.class;
+ }
+
+}
diff --git a/spring-jinq/src/main/resources/application.properties b/spring-jinq/src/main/resources/application.properties
new file mode 100644
index 0000000000..dc73bed0c5
--- /dev/null
+++ b/spring-jinq/src/main/resources/application.properties
@@ -0,0 +1,7 @@
+spring.datasource.url=jdbc:h2:~/jinq
+spring.datasource.username=sa
+spring.datasource.password=
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.show-sql=true
+spring.jpa.properties.hibernate.format_sql=true
\ No newline at end of file
diff --git a/spring-jinq/src/test/java/com/baeldung/spring/jinq/repositories/CarRepositoryIntegrationTest.java b/spring-jinq/src/test/java/com/baeldung/spring/jinq/repositories/CarRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..9cb126cbaa
--- /dev/null
+++ b/spring-jinq/src/test/java/com/baeldung/spring/jinq/repositories/CarRepositoryIntegrationTest.java
@@ -0,0 +1,42 @@
+package com.baeldung.spring.jinq.repositories;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.baeldung.spring.jinq.JinqApplication;
+
+@ContextConfiguration(classes = JinqApplication.class)
+@RunWith(SpringJUnit4ClassRunner.class)
+public class CarRepositoryIntegrationTest {
+
+ @Autowired
+ private CarRepository repository;
+
+ @Test
+ public void givenACar_whenFilter_thenShouldBeFound() {
+ assertThat(repository.findByModel("model1")
+ .isPresent()).isFalse();
+ }
+
+ @Test
+ public void givenACar_whenMultipleFilters_thenShouldBeFound() {
+ assertThat(repository.findByModelAndDescription("model1", "desc")
+ .isEmpty()).isTrue();
+ }
+
+ @Test
+ public void whenUseASelectClause() {
+ assertThat(repository.findWithModelYearAndEngine()
+ .isEmpty()).isTrue();
+ }
+
+ @Test
+ public void whenUsingOneToOneRelationship() {
+ assertThat(repository.findManufacturerByModel("model1")).isNotNull();
+ }
+}
diff --git a/spring-mvc-push/.gitignore b/spring-mvc-push/.gitignore
deleted file mode 100644
index 448298d47f..0000000000
--- a/spring-mvc-push/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/.tern-project
diff --git a/spring-mvc-push/pom.xml b/spring-mvc-push/pom.xml
deleted file mode 100644
index 2eb10381be..0000000000
--- a/spring-mvc-push/pom.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-
- 4.0.0
- com.baeldung
- spring-mvc-push
- war
- 0.0.1-SNAPSHOT
- spring-mvc-push
-
- 1.8
- 1.8
- 2.20
- 3.7.0
- 3.2.0
- UTF-8
- 5.0.2
- 5.0.2.RELEASE
- 4.0.0
- 1.2
- 2.3.2-b02
- 5.0.2
- 1.0.2
-
-
-
- org.springframework
- spring-webmvc
- ${spring.version}
-
-
- javax.servlet
- javax.servlet-api
- ${servlet.version}
- provided
-
-
- javax.servlet
- jstl
- ${jstl.version}
-
-
- javax.servlet.jsp
- javax.servlet.jsp-api
- ${jsp-api.version}
-
-
-
- org.springframework
- spring-test
- ${spring.version}
- test
-
-
- org.junit.jupiter
- junit-jupiter-engine
- ${junit.jupiter.version}
- test
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- ${maven.compiler.version}
-
-
- org.apache.maven.plugins
- maven-war-plugin
- ${maven-war-plugin.version}
-
- spring-mvc-push
- false
- ${deploy-path}
-
-
-
- maven-surefire-plugin
- ${maven-surefire-plugin.version}
-
-
- org.junit.platform
- junit-platform-surefire-provider
- ${junit.platform.version}
-
-
-
-
- spring-mvc-push
-
-
diff --git a/spring-mvc-push/src/main/java/com/baeldung/config/PushConfiguration.java b/spring-mvc-push/src/main/java/com/baeldung/config/PushConfiguration.java
deleted file mode 100644
index e6188da92d..0000000000
--- a/spring-mvc-push/src/main/java/com/baeldung/config/PushConfiguration.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.baeldung.config;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRegistration;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.WebApplicationInitializer;
-import org.springframework.web.context.ContextLoaderListener;
-import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
-import org.springframework.web.servlet.DispatcherServlet;
-import org.springframework.web.servlet.config.annotation.EnableWebMvc;
-import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import org.springframework.web.servlet.view.InternalResourceViewResolver;
-
-@Configuration
-@EnableWebMvc
-@ComponentScan(basePackages = "com.baeldung.controller")
-public class PushConfiguration implements WebApplicationInitializer, WebMvcConfigurer {
-
- @Override
- public void onStartup(ServletContext container) throws ServletException {
- AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
- context.register(PushConfiguration.class);
- container.addListener(new ContextLoaderListener(context));
- ServletRegistration.Dynamic dispatcher = container.addServlet("DispatcherServlet", new DispatcherServlet(context));
- dispatcher.setLoadOnStartup(1);
- dispatcher.addMapping("/");
- }
-
- @Bean
- public InternalResourceViewResolver jspViewResolver() {
- InternalResourceViewResolver bean = new InternalResourceViewResolver();
- bean.setPrefix("/WEB-INF/views/");
- bean.setSuffix(".jsp");
- return bean;
- }
-
- @Override
- public void addResourceHandlers(ResourceHandlerRegistry registry) {
- registry.addResourceHandler("/resources/**")
- .addResourceLocations("/resources/");
- }
-
-}
diff --git a/spring-mvc-push/src/main/webapp/index.jsp b/spring-mvc-push/src/main/webapp/index.jsp
deleted file mode 100644
index 82ecb68003..0000000000
--- a/spring-mvc-push/src/main/webapp/index.jsp
+++ /dev/null
@@ -1,14 +0,0 @@
-<%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
-
-
-
-PushBuilder demo
-
-
-
-
-
\ No newline at end of file
diff --git a/spring-mvc-push/src/main/webapp/resources/script.js b/spring-mvc-push/src/main/webapp/resources/script.js
deleted file mode 100644
index 9bc97c006a..0000000000
--- a/spring-mvc-push/src/main/webapp/resources/script.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log('Script')
\ No newline at end of file
diff --git a/spring-mvc-push/src/main/webapp/resources/style.css b/spring-mvc-push/src/main/webapp/resources/style.css
deleted file mode 100644
index d5fc158135..0000000000
--- a/spring-mvc-push/src/main/webapp/resources/style.css
+++ /dev/null
@@ -1,9 +0,0 @@
-.single-title {
- font-size: 30px;
- color: #535353;
- font-weight: 200;
- letter-spacing: -1.5px;
- line-height: 64px;
- max-width: 750px;
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif
-}
\ No newline at end of file
diff --git a/spring-mvc-simple/README.md b/spring-mvc-simple/README.md
index 197a22cbac..69a9027280 100644
--- a/spring-mvc-simple/README.md
+++ b/spring-mvc-simple/README.md
@@ -2,3 +2,4 @@
- [HandlerAdapters in Spring MVC](http://www.baeldung.com/spring-mvc-handler-adapters)
- [Template Engines for Spring](http://www.baeldung.com/spring-template-engines)
+- [Spring 5 and Servlet 4 – The PushBuilder](http://www.baeldung.com/spring-5-push)
diff --git a/spring-mvc-simple/pom.xml b/spring-mvc-simple/pom.xml
index 2cc6aec906..595e58f5f3 100644
--- a/spring-mvc-simple/pom.xml
+++ b/spring-mvc-simple/pom.xml
@@ -8,83 +8,63 @@
Spring MVC simple Maven Webapp
http://maven.apache.org
-
- com.baeldung
- parent-modules
- 1.0.0-SNAPSHOT
-
-
- 4.3.10.RELEASE
- 3.1.0
+ 1.8
+ 1.8
+ UTF-8
+ 5.0.2.RELEASE
+ 3.2.0
+ 3.7.0
+ 2.20
1.2
- 2.3.1
- 3.1.0
+ 2.3.2-b02
+ 4.0.0
5.4.1.Final
enter-location-of-server
1.3.2
1.8
3.0.7.RELEASE
2.4.12
- 2.3.23
+ 2.3.27-incubating
1.2.5
+ 5.0.2
+ 5.0.2
+ 1.0.2
+ 1.9.0
javax.servlet
javax.servlet-api
- 3.1.0
-
-
- org.springframework
- spring-webmvc
- ${springframework.version}
-
-
- org.springframework
- spring-context
- ${springframework.version}
-
-
- org.springframework
- spring-core
- ${springframework.version}
-
-
- commons-logging
- commons-logging
-
-
+ ${javax.servlet-api.version}
javax.servlet.jsp
javax.servlet.jsp-api
${javax.servlet.jsp-api.version}
-
javax.servlet
jstl
${jstl.version}
-
org.hibernate
hibernate-validator
${hibernate-validator.version}
-
- org.springframework
- spring-webmvc
- ${springframework.version}
-
commons-fileupload
commons-fileupload
${fileupload.version}
-
+
+ org.springframework
+ spring-webmvc
+ ${springframework.version}
+
+
org.thymeleaf
@@ -115,7 +95,7 @@
groovy-templates
${groovy.version}
-
+
de.neuland-bfi
@@ -123,6 +103,24 @@
${jade.version}
+
+
+ org.springframework
+ spring-test
+ ${springframework.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit.jupiter.version}
+ test
+
+
+ com.rometools
+ rome
+ ${rome.version}
+
@@ -141,11 +139,18 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.7.0
-
- 1.8
- 1.8
-
+ ${maven.compiler.version}
+
+
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+ org.junit.platform
+ junit-platform-surefire-provider
+ ${junit.platform.version}
+
+
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java
index b62ccae465..b9a8336bf2 100644
--- a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java
@@ -7,13 +7,13 @@ import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.baeldung.springmvcforms", "com.baeldung.spring.controller", "com.baeldung.spring.validator" })
-class ApplicationConfiguration extends WebMvcConfigurerAdapter {
+class ApplicationConfiguration implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/JadeTemplateConfiguration.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/JadeTemplateConfiguration.java
index 10345bac58..4c95e5a0bd 100644
--- a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/JadeTemplateConfiguration.java
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/JadeTemplateConfiguration.java
@@ -16,24 +16,24 @@ import de.neuland.jade4j.spring.view.JadeViewResolver;
public class JadeTemplateConfiguration {
@Bean
public SpringTemplateLoader templateLoader() {
- SpringTemplateLoader templateLoader = new SpringTemplateLoader();
- templateLoader.setBasePath("/WEB-INF/views/");
- templateLoader.setSuffix(".jade");
- return templateLoader;
+ SpringTemplateLoader templateLoader = new SpringTemplateLoader();
+ templateLoader.setBasePath("/WEB-INF/views/");
+ templateLoader.setSuffix(".jade");
+ return templateLoader;
}
@Bean
public JadeConfiguration jadeConfiguration() {
- JadeConfiguration configuration = new JadeConfiguration();
- configuration.setCaching(false);
- configuration.setTemplateLoader(templateLoader());
- return configuration;
+ JadeConfiguration configuration = new JadeConfiguration();
+ configuration.setCaching(false);
+ configuration.setTemplateLoader(templateLoader());
+ return configuration;
}
@Bean
public ViewResolver viewResolver() {
- JadeViewResolver viewResolver = new JadeViewResolver();
- viewResolver.setConfiguration(jadeConfiguration());
- return viewResolver;
+ JadeViewResolver viewResolver = new JadeViewResolver();
+ viewResolver.setConfiguration(jadeConfiguration());
+ return viewResolver;
}
}
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/PushConfiguration.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/PushConfiguration.java
new file mode 100644
index 0000000000..3072501cfa
--- /dev/null
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/PushConfiguration.java
@@ -0,0 +1,30 @@
+package com.baeldung.spring.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import org.springframework.web.servlet.view.InternalResourceViewResolver;
+
+@Configuration
+@EnableWebMvc
+@ComponentScan(basePackages = "com.baeldung.spring.controller.push")
+public class PushConfiguration implements WebMvcConfigurer {
+
+ @Bean
+ public InternalResourceViewResolver jspViewResolver() {
+ InternalResourceViewResolver bean = new InternalResourceViewResolver();
+ bean.setPrefix("/WEB-INF/views/");
+ bean.setSuffix(".jsp");
+ return bean;
+ }
+
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ registry.addResourceHandler("/resources/**")
+ .addResourceLocations("/resources/");
+ }
+
+}
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/WebInitializer.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/WebInitializer.java
index d57d2c621a..09030a8347 100644
--- a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/WebInitializer.java
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/WebInitializer.java
@@ -11,42 +11,23 @@ import javax.servlet.ServletRegistration;
public class WebInitializer implements WebApplicationInitializer {
- public void onStartup(ServletContext container) throws ServletException {
+ public void onStartup(ServletContext container) throws ServletException {
- AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
- ctx.register(ApplicationConfiguration.class);
- //ctx.register(ThymeleafConfiguration.class);
- //ctx.register(FreemarkerConfiguration.class);
- //ctx.register(GroovyConfiguration.class);
- //ctx.register(JadeTemplateConfiguration.class);
- ctx.setServletContext(container);
+ AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
+ ctx.register(ApplicationConfiguration.class);
+ // ctx.register(ThymeleafConfiguration.class);
+ // ctx.register(FreemarkerConfiguration.class);
+ // ctx.register(GroovyConfiguration.class);
+ // ctx.register(JadeTemplateConfiguration.class);
+ // ctx.register(PushConfiguration.class);
+ // ctx.setServletContext(container);
- // Manage the lifecycle of the root application context
- container.addListener(new ContextLoaderListener(ctx));
+ // Manage the lifecycle of the root application context
+ container.addListener(new ContextLoaderListener(ctx));
- ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx));
+ ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx));
- servlet.setLoadOnStartup(1);
- servlet.addMapping("/");
-
- }
-// @Override
-// public void onStartup(ServletContext container) {
-// // Create the 'root' Spring application context
-// AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
-// rootContext.register(ServiceConfig.class, JPAConfig.class, SecurityConfig.class);
-//
-// // Manage the lifecycle of the root application context
-// container.addListener(new ContextLoaderListener(rootContext));
-//
-// // Create the dispatcher servlet's Spring application context
-// AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
-// dispatcherServlet.register(MvcConfig.class);
-//
-// // Register and map the dispatcher servlet
-// ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
-// dispatcher.setLoadOnStartup(1);
-// dispatcher.addMapping("/");
-//
-// }
+ servlet.setLoadOnStartup(1);
+ servlet.addMapping("/");
+ }
}
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/AnnotationMethodHandlerAdapterExample.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/AnnotationMethodHandlerAdapterExample.java
index 164830cd6a..89f5b2501b 100644
--- a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/AnnotationMethodHandlerAdapterExample.java
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/AnnotationMethodHandlerAdapterExample.java
@@ -6,10 +6,10 @@ import org.springframework.web.servlet.ModelAndView;
@Controller
public class AnnotationMethodHandlerAdapterExample {
- @RequestMapping("/annotedName")
- public ModelAndView getEmployeeName() {
- ModelAndView model = new ModelAndView("Greeting");
- model.addObject("message", "Dinesh");
- return model;
- }
+ @RequestMapping("/annotedName")
+ public ModelAndView getEmployeeName() {
+ ModelAndView model = new ModelAndView("Greeting");
+ model.addObject("message", "Dinesh");
+ return model;
+ }
}
\ No newline at end of file
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/FileUploadController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/FileUploadController.java
index 47af2ab50d..2ca9e2b135 100644
--- a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/FileUploadController.java
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/FileUploadController.java
@@ -23,13 +23,13 @@ public class FileUploadController implements HandlerExceptionResolver {
}
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
- public ModelAndView uploadFile(MultipartFile file) throws IOException{
+ public ModelAndView uploadFile(MultipartFile file) throws IOException {
ModelAndView modelAndView = new ModelAndView("file");
-
- InputStream in = file.getInputStream();
+
+ InputStream in = file.getInputStream();
File currDir = new File(".");
String path = currDir.getAbsolutePath();
- FileOutputStream f = new FileOutputStream(path.substring(0, path.length()-1)+ file.getOriginalFilename());
+ FileOutputStream f = new FileOutputStream(path.substring(0, path.length() - 1) + file.getOriginalFilename());
int ch = 0;
while ((ch = in.read()) != -1) {
f.write(ch);
@@ -37,15 +37,17 @@ public class FileUploadController implements HandlerExceptionResolver {
f.flush();
f.close();
- modelAndView.getModel().put("message", "File uploaded successfully!");
+ modelAndView.getModel()
+ .put("message", "File uploaded successfully!");
return modelAndView;
}
-
+
@Override
- public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object object, Exception exc) {
+ public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object object, Exception exc) {
ModelAndView modelAndView = new ModelAndView("file");
if (exc instanceof MaxUploadSizeExceededException) {
- modelAndView.getModel().put("message", "File size exceeds limit!");
+ modelAndView.getModel()
+ .put("message", "File size exceeds limit!");
}
return modelAndView;
}
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/RequestMappingHandlerAdapterExample.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/RequestMappingHandlerAdapterExample.java
index 76ac3e2806..754bea79f1 100644
--- a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/RequestMappingHandlerAdapterExample.java
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/RequestMappingHandlerAdapterExample.java
@@ -6,10 +6,10 @@ import org.springframework.web.servlet.ModelAndView;
@Controller
public class RequestMappingHandlerAdapterExample {
- @RequestMapping("/requestName")
- public ModelAndView getEmployeeName() {
- ModelAndView model = new ModelAndView("Greeting");
- model.addObject("message", "Madhwal");
- return model;
- }
+ @RequestMapping("/requestName")
+ public ModelAndView getEmployeeName() {
+ ModelAndView model = new ModelAndView("Greeting");
+ model.addObject("message", "Madhwal");
+ return model;
+ }
}
\ No newline at end of file
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/SimpleControllerHandlerAdapterExample.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/SimpleControllerHandlerAdapterExample.java
index bac091ffeb..17c4ab689e 100644
--- a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/SimpleControllerHandlerAdapterExample.java
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/SimpleControllerHandlerAdapterExample.java
@@ -6,13 +6,11 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
-public class SimpleControllerHandlerAdapterExample extends
- AbstractController {
- @Override
- protected ModelAndView handleRequestInternal(HttpServletRequest request,
- HttpServletResponse response) throws Exception {
- ModelAndView model = new ModelAndView("Greeting");
- model.addObject("message", "Dinesh Madhwal");
- return model;
- }
+public class SimpleControllerHandlerAdapterExample extends AbstractController {
+ @Override
+ protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ ModelAndView model = new ModelAndView("Greeting");
+ model.addObject("message", "Dinesh Madhwal");
+ return model;
+ }
}
\ No newline at end of file
diff --git a/spring-mvc-push/src/main/java/com/baeldung/controller/PushController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/push/PushController.java
similarity index 92%
rename from spring-mvc-push/src/main/java/com/baeldung/controller/PushController.java
rename to spring-mvc-simple/src/main/java/com/baeldung/spring/controller/push/PushController.java
index c4698fe976..b557c65c93 100644
--- a/spring-mvc-push/src/main/java/com/baeldung/controller/PushController.java
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/push/PushController.java
@@ -1,4 +1,4 @@
-package com.baeldung.controller;
+package com.baeldung.spring.controller.push;
import javax.servlet.http.PushBuilder;
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleFeedView.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleFeedView.java
new file mode 100644
index 0000000000..cfbd33cd57
--- /dev/null
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleFeedView.java
@@ -0,0 +1,54 @@
+package com.baeldung.spring.controller.rss;
+
+import com.rometools.rome.feed.rss.Channel;
+import com.rometools.rome.feed.rss.Description;
+import com.rometools.rome.feed.rss.Item;
+import org.springframework.stereotype.Service;
+import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@Service("articleFeedView")
+public class ArticleFeedView extends AbstractRssFeedView {
+
+ protected Channel newFeed() {
+ Channel channel = new Channel("rss_2.0");
+ channel.setLink("http://localhost:8080/spring-mvc-simple/rss");
+ channel.setTitle("Article Feed");
+ channel.setDescription("Article Feed Description");
+ channel.setPubDate(new Date());
+ return channel;
+ }
+
+ @Override
+ protected List
- buildFeedItems(Map map, HttpServletRequest httpStRequest, HttpServletResponse httpStResponse) throws Exception {
+ List list = new ArrayList
- ();
+
+ Item item1 = new Item();
+ item1.setLink("http://www.baeldung.com/netty-exception-handling");
+ item1.setTitle("Exceptions in Netty");
+ Description description1 = new Description();
+ description1.setValue("In this quick article, we’ll be looking at exception handling in Netty.");
+ item1.setDescription(description1);
+ item1.setPubDate(new Date());
+ item1.setAuthor("Carlos");
+
+ Item item2 = new Item();
+ item2.setLink("http://www.baeldung.com/cockroachdb-java");
+ item2.setTitle("Guide to CockroachDB in Java");
+ Description description2 = new Description();
+ description2.setValue("This tutorial is an introductory guide to using CockroachDB with Java.");
+ item2.setDescription(description2);
+ item2.setPubDate(new Date());
+ item2.setAuthor("Baeldung");
+
+ list.add(item1);
+ list.add(item2);
+ return list;
+ }
+}
diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java
new file mode 100644
index 0000000000..1f51b238ac
--- /dev/null
+++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java
@@ -0,0 +1,14 @@
+package com.baeldung.spring.controller.rss;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class ArticleRssController {
+
+ @GetMapping(value = "/rss", produces = "application/*")
+ public String articleFeed() {
+ return "articleFeedView";
+ }
+
+}
diff --git a/spring-mvc-simple/src/main/resources/spring-servlet_AnnotationMethodHandlerAdapter.xml b/spring-mvc-simple/src/main/resources/spring-servlet_AnnotationMethodHandlerAdapter.xml
deleted file mode 100644
index 430b849012..0000000000
--- a/spring-mvc-simple/src/main/resources/spring-servlet_AnnotationMethodHandlerAdapter.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/spring-mvc-simple/src/main/resources/spring-servlet_RequestMappingHandlerAdapter.xml b/spring-mvc-simple/src/main/resources/spring-servlet_RequestMappingHandlerAdapter.xml
deleted file mode 100644
index d3783c2e67..0000000000
--- a/spring-mvc-simple/src/main/resources/spring-servlet_RequestMappingHandlerAdapter.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/spring-mvc-simple/src/main/resources/spring-servlet_SimpleControllerHandlerAdapter.xml b/spring-mvc-simple/src/main/resources/spring-servlet_SimpleControllerHandlerAdapter.xml
deleted file mode 100644
index 1d6e5628df..0000000000
--- a/spring-mvc-simple/src/main/resources/spring-servlet_SimpleControllerHandlerAdapter.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/spring-mvc-push/src/main/webapp/WEB-INF/views/demo.jsp b/spring-mvc-simple/src/main/webapp/WEB-INF/views/demo.jsp
similarity index 87%
rename from spring-mvc-push/src/main/webapp/WEB-INF/views/demo.jsp
rename to spring-mvc-simple/src/main/webapp/WEB-INF/views/demo.jsp
index 28b27322ae..d5579debf7 100644
--- a/spring-mvc-push/src/main/webapp/WEB-INF/views/demo.jsp
+++ b/spring-mvc-simple/src/main/webapp/WEB-INF/views/demo.jsp
@@ -12,7 +12,6 @@
" alt="Logo"
height="126" width="411">
-
Go to
- index
+
\ No newline at end of file
diff --git a/spring-mvc-simple/src/main/webapp/WEB-INF/views/registration-jade.jade b/spring-mvc-simple/src/main/webapp/WEB-INF/views/registration-jade.jade
index 44b6293ff0..f271ac6852 100644
--- a/spring-mvc-simple/src/main/webapp/WEB-INF/views/registration-jade.jade
+++ b/spring-mvc-simple/src/main/webapp/WEB-INF/views/registration-jade.jade
@@ -4,7 +4,7 @@ html
title User Registration
body
form(action="register" method="post" )
- label(for="email") Emailaaaaaaaa:
+ label(for="email") Email:
input(type="text" name="email")
label(for="password") Password:
input(type="password" name="password")
diff --git a/spring-mvc-push/src/main/webapp/resources/logo.png b/spring-mvc-simple/src/main/webapp/resources/logo.png
similarity index 100%
rename from spring-mvc-push/src/main/webapp/resources/logo.png
rename to spring-mvc-simple/src/main/webapp/resources/logo.png
diff --git a/spring-mvc-push/src/test/java/com/baeldung/controller/PushControllerIntegrationTest.java b/spring-mvc-simple/src/test/java/com/baeldung/controller/push/PushControllerIntegrationTest.java
similarity index 90%
rename from spring-mvc-push/src/test/java/com/baeldung/controller/PushControllerIntegrationTest.java
rename to spring-mvc-simple/src/test/java/com/baeldung/controller/push/PushControllerIntegrationTest.java
index 570e05cad6..a03d02895f 100644
--- a/spring-mvc-push/src/test/java/com/baeldung/controller/PushControllerIntegrationTest.java
+++ b/spring-mvc-simple/src/test/java/com/baeldung/controller/push/PushControllerIntegrationTest.java
@@ -1,10 +1,9 @@
-package com.baeldung.controller;
+package com.baeldung.controller.push;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
@@ -12,9 +11,8 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
-import com.baeldung.config.PushConfiguration;
+import com.baeldung.spring.configuration.PushConfiguration;
-@Disabled
@SpringJUnitWebConfig(PushConfiguration.class)
public class PushControllerIntegrationTest {
@Autowired
diff --git a/spring-rest-embedded-tomcat/pom.xml b/spring-rest-embedded-tomcat/pom.xml
index cee9933c0d..3622e84101 100644
--- a/spring-rest-embedded-tomcat/pom.xml
+++ b/spring-rest-embedded-tomcat/pom.xml
@@ -84,14 +84,13 @@
**/JdbcTest.java
**/*LiveTest.java
-
- 5.0.1.RELEASE
+ 5.0.2.RELEASE
2.19.1
4.12
2.9.2
diff --git a/spring-rest/pom.xml b/spring-rest/pom.xml
index 6da891b054..50ac00e1c3 100644
--- a/spring-rest/pom.xml
+++ b/spring-rest/pom.xml
@@ -169,6 +169,12 @@
commons-io
2.4
+
+
+ au.com.dius
+ pact-jvm-provider-junit_2.11
+ ${pact.version}
+
@@ -324,6 +330,8 @@
3.4.1
2.2.0
+
+ 3.5.11
diff --git a/spring-rest/src/main/java/org/baeldung/web/controller/PactController.java b/spring-rest/src/main/java/org/baeldung/web/controller/PactController.java
new file mode 100644
index 0000000000..4f586479ef
--- /dev/null
+++ b/spring-rest/src/main/java/org/baeldung/web/controller/PactController.java
@@ -0,0 +1,32 @@
+package org.baeldung.web.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.baeldung.web.dto.PactDto;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class PactController {
+
+ List pacts = new ArrayList<>();
+
+ @GetMapping(value = "/pact", produces = MediaType.APPLICATION_JSON_VALUE)
+ @ResponseBody
+ public PactDto getPact() {
+ return new PactDto(true, "tom");
+ }
+
+ @PostMapping("/pact")
+ @ResponseStatus(HttpStatus.CREATED)
+ public void createPact(PactDto pact) {
+ pacts.add(pact);
+ }
+
+}
diff --git a/spring-rest/src/main/java/org/baeldung/web/dto/PactDto.java b/spring-rest/src/main/java/org/baeldung/web/dto/PactDto.java
new file mode 100644
index 0000000000..e34e2bdf3b
--- /dev/null
+++ b/spring-rest/src/main/java/org/baeldung/web/dto/PactDto.java
@@ -0,0 +1,33 @@
+package org.baeldung.web.dto;
+
+public class PactDto {
+
+ private boolean condition;
+ private String name;
+
+ public PactDto() {
+ }
+
+ public PactDto(boolean condition, String name) {
+ super();
+ this.condition = condition;
+ this.name = name;
+ }
+
+ public boolean isCondition() {
+ return condition;
+ }
+
+ public void setCondition(boolean condition) {
+ this.condition = condition;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/spring-rest/src/main/resources/pacts/test_consumer-test_provider.json b/spring-rest/src/main/resources/pacts/test_consumer-test_provider.json
new file mode 100644
index 0000000000..c8082798f4
--- /dev/null
+++ b/spring-rest/src/main/resources/pacts/test_consumer-test_provider.json
@@ -0,0 +1,61 @@
+{
+ "provider": {
+ "name": "test_provider"
+ },
+ "consumer": {
+ "name": "test_consumer"
+ },
+ "interactions": [
+ {
+ "description": "GET REQUEST",
+ "request": {
+ "method": "GET",
+ "path": "/pact"
+ },
+ "response": {
+ "status": 200,
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "condition": true,
+ "name": "tom"
+ }
+ },
+ "providerStates": [
+ {
+ "name": "test GET"
+ }
+ ]
+ },
+ {
+ "description": "POST REQUEST",
+ "request": {
+ "method": "POST",
+ "path": "/pact",
+ "headers": {
+ "Content-Type": "application/json"
+ },
+ "body": {
+ "name": "Michael"
+ }
+ },
+ "response": {
+ "status": 201
+ },
+ "providerStates": [
+ {
+ "name": "test POST"
+ }
+ ]
+ }
+ ],
+ "metadata": {
+ "pact-specification": {
+ "version": "3.0.0"
+ },
+ "pact-jvm": {
+ "version": "3.5.0"
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-rest/src/test/java/org/baeldung/pact/PactProviderTest.java b/spring-rest/src/test/java/org/baeldung/pact/PactProviderTest.java
new file mode 100644
index 0000000000..0456b0d3e7
--- /dev/null
+++ b/spring-rest/src/test/java/org/baeldung/pact/PactProviderTest.java
@@ -0,0 +1,40 @@
+package org.baeldung.pact;
+
+import org.baeldung.config.MainApplication;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.springframework.boot.SpringApplication;
+import org.springframework.web.context.ConfigurableWebApplicationContext;
+
+import au.com.dius.pact.provider.junit.PactRunner;
+import au.com.dius.pact.provider.junit.Provider;
+import au.com.dius.pact.provider.junit.State;
+import au.com.dius.pact.provider.junit.loader.PactFolder;
+import au.com.dius.pact.provider.junit.target.HttpTarget;
+import au.com.dius.pact.provider.junit.target.Target;
+import au.com.dius.pact.provider.junit.target.TestTarget;
+
+@RunWith(PactRunner.class)
+@Provider("test_provider")
+@PactFolder("pacts")
+public class PactProviderTest {
+
+ @TestTarget
+ public final Target target = new HttpTarget("http", "localhost", 8082, "/spring-rest");
+
+ private static ConfigurableWebApplicationContext application;
+
+ @BeforeClass
+ public static void start() {
+ application = (ConfigurableWebApplicationContext) SpringApplication.run(MainApplication.class);
+ }
+
+ @State("test GET")
+ public void toGetState() {
+ }
+
+ @State("test POST")
+ public void toPostState() {
+ }
+
+}
diff --git a/testing-modules/testing/README.md b/testing-modules/testing/README.md
index 3511bb1bb9..2894da3496 100644
--- a/testing-modules/testing/README.md
+++ b/testing-modules/testing/README.md
@@ -17,3 +17,4 @@
- [Introduction to Jukito](http://www.baeldung.com/jukito)
- [Custom JUnit 4 Test Runners](http://www.baeldung.com/junit-4-custom-runners)
- [Guide to JSpec](http://www.baeldung.com/jspec)
+- [Custom Assertions with AssertJ](http://www.baeldung.com/assertj-custom-assertion)
diff --git a/testing-modules/testing/pom.xml b/testing-modules/testing/pom.xml
index 1fd6357b87..c76045380b 100644
--- a/testing-modules/testing/pom.xml
+++ b/testing-modules/testing/pom.xml
@@ -154,6 +154,16 @@
+
+ org.assertj
+ assertj-assertions-generator-maven-plugin
+ ${assertj-generator.version}
+
+
+ com.baeldung.testing.assertj.custom.Person
+
+
+
@@ -164,6 +174,7 @@
21.0
3.1.0
3.6.1
+ 2.1.0
0.32
1.1.0
0.12
diff --git a/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java
new file mode 100644
index 0000000000..a0b3d0daac
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java
@@ -0,0 +1,19 @@
+package com.baeldung.testing.assertj;
+
+public class Member {
+ private String name;
+ private int age;
+
+ public Member(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+}
diff --git a/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/custom/Person.java b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/custom/Person.java
new file mode 100644
index 0000000000..34afc480e4
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/custom/Person.java
@@ -0,0 +1,32 @@
+package com.baeldung.testing.assertj.custom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Person {
+ private String fullName;
+ private int age;
+ private List nicknames;
+
+ public Person(String fullName, int age) {
+ this.fullName = fullName;
+ this.age = age;
+ this.nicknames = new ArrayList<>();
+ }
+
+ public void addNickname(String nickname) {
+ nicknames.add(nickname);
+ }
+
+ public String getFullName() {
+ return fullName;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public List getNicknames() {
+ return nicknames;
+ }
+}
diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java
new file mode 100644
index 0000000000..153af828f1
--- /dev/null
+++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java
@@ -0,0 +1,72 @@
+package com.baeldung.testing.assertj;
+
+import static org.assertj.core.api.Assertions.allOf;
+import static org.assertj.core.api.Assertions.anyOf;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.not;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.assertj.core.api.Condition;
+import org.junit.Test;
+
+public class AssertJConditionUnitTest {
+ private Condition senior = new Condition<>(m -> m.getAge() >= 60, "senior");
+ private Condition nameJohn = new Condition<>(m -> m.getName().equalsIgnoreCase("John"), "name John");
+
+ @Test
+ public void whenUsingMemberAgeCondition_thenCorrect() {
+ Member member = new Member("John", 65);
+ assertThat(member).is(senior);
+
+ try {
+ assertThat(member).isNot(senior);
+ fail();
+ } catch (AssertionError e) {
+ assertThat(e).hasMessageContaining("not to be ");
+ }
+ }
+
+ @Test
+ public void whenUsingMemberNameCondition_thenCorrect() {
+ Member member = new Member("Jane", 60);
+ assertThat(member).doesNotHave(nameJohn);
+
+ try {
+ assertThat(member).has(nameJohn);
+ fail();
+ } catch (AssertionError e) {
+ assertThat(e).hasMessageContaining("to have:\n ");
+ }
+ }
+
+ @Test
+ public void whenCollectionConditionsAreSatisfied_thenCorrect() {
+ List members = new ArrayList<>();
+ members.add(new Member("Alice", 50));
+ members.add(new Member("Bob", 60));
+
+ assertThat(members).haveExactly(1, senior);
+ assertThat(members).doNotHave(nameJohn);
+ }
+
+ @Test
+ public void whenCombiningAllOfConditions_thenCorrect() {
+ Member john = new Member("John", 60);
+ Member jane = new Member("Jane", 50);
+
+ assertThat(john).is(allOf(senior, nameJohn));
+ assertThat(jane).is(allOf(not(nameJohn), not(senior)));
+ }
+
+ @Test
+ public void whenCombiningAnyOfConditions_thenCorrect() {
+ Member john = new Member("John", 50);
+ Member jane = new Member("Jane", 60);
+
+ assertThat(john).is(anyOf(senior, nameJohn));
+ assertThat(jane).is(anyOf(nameJohn, senior));
+ }
+}
diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/AssertJCustomAssertionsUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/AssertJCustomAssertionsUnitTest.java
new file mode 100644
index 0000000000..4c09311bac
--- /dev/null
+++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/AssertJCustomAssertionsUnitTest.java
@@ -0,0 +1,44 @@
+package com.baeldung.testing.assertj.custom;
+
+import static com.baeldung.testing.assertj.custom.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class AssertJCustomAssertionsUnitTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void whenPersonNameMatches_thenCorrect() {
+ Person person = new Person("John Doe", 20);
+ assertThat(person).hasFullName("John Doe");
+ }
+
+ @Test
+ public void whenPersonAgeLessThanEighteen_thenNotAdult() {
+ Person person = new Person("Jane Roe", 16);
+
+ try {
+ assertThat(person).isAdult();
+ fail();
+ } catch (AssertionError e) {
+ org.assertj.core.api.Assertions.assertThat(e).hasMessage("Expected person to be adult");
+ }
+ }
+
+ @Test
+ public void whenPersonDoesNotHaveAMatchingNickname_thenIncorrect() {
+ Person person = new Person("John Doe", 20);
+ person.addNickname("Nick");
+
+ try {
+ assertThat(person).hasNickname("John");
+ fail();
+ } catch (AssertionError e) {
+ org.assertj.core.api.Assertions.assertThat(e).hasMessage("Expected person to have nickname John");
+ }
+ }
+}
diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/Assertions.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/Assertions.java
new file mode 100644
index 0000000000..fcffb8fc6c
--- /dev/null
+++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/Assertions.java
@@ -0,0 +1,9 @@
+package com.baeldung.testing.assertj.custom;
+
+public class Assertions {
+ public static PersonAssert assertThat(Person actual) {
+ return new PersonAssert(actual);
+ }
+
+ // static factory methods of other assertion classes
+}
diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/PersonAssert.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/PersonAssert.java
new file mode 100644
index 0000000000..d6cc585e96
--- /dev/null
+++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/PersonAssert.java
@@ -0,0 +1,38 @@
+package com.baeldung.testing.assertj.custom;
+
+import org.assertj.core.api.AbstractAssert;
+
+public class PersonAssert extends AbstractAssert {
+
+ public PersonAssert(Person actual) {
+ super(actual, PersonAssert.class);
+ }
+
+ public static PersonAssert assertThat(Person actual) {
+ return new PersonAssert(actual);
+ }
+
+ public PersonAssert hasFullName(String fullName) {
+ isNotNull();
+ if (!actual.getFullName().equals(fullName)) {
+ failWithMessage("Expected person to have full name %s but was %s", fullName, actual.getFullName());
+ }
+ return this;
+ }
+
+ public PersonAssert isAdult() {
+ isNotNull();
+ if (actual.getAge() < 18) {
+ failWithMessage("Expected person to be adult");
+ }
+ return this;
+ }
+
+ public PersonAssert hasNickname(String nickName) {
+ isNotNull();
+ if (!actual.getNicknames().contains(nickName)) {
+ failWithMessage("Expected person to have nickname %s", nickName);
+ }
+ return this;
+ }
+}
diff --git a/vavr/src/main/java/com/baeldung/samples/java/vavr/VavrSampler.java b/vavr/src/main/java/com/baeldung/samples/java/vavr/VavrSampler.java
new file mode 100644
index 0000000000..f4e0728f32
--- /dev/null
+++ b/vavr/src/main/java/com/baeldung/samples/java/vavr/VavrSampler.java
@@ -0,0 +1,99 @@
+package com.baeldung.samples.java.vavr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.vavr.collection.Stream;
+
+/**
+ *
+ * @author baeldung
+ */
+public class VavrSampler {
+
+ static int[] intArray = new int[] { 1, 2, 4 };
+ static List intList = new ArrayList<>();
+ static int[][] intOfInts = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
+
+ public static void main(String[] args) {
+ vavrStreamElementAccess();
+ System.out.println("====================================");
+ vavrParallelStreamAccess();
+ System.out.println("====================================");
+ vavrFlatMapping();
+ System.out.println("====================================");
+ vavrStreamManipulation();
+ System.out.println("====================================");
+ vavrStreamDistinct();
+ }
+
+ public static void vavrStreamElementAccess() {
+ System.out.println("Vavr Element Access");
+ System.out.println("====================================");
+ Stream vavredStream = Stream.ofAll(intArray);
+ System.out.println("Vavr index access: " + vavredStream.get(2));
+ System.out.println("Vavr head element access: " + vavredStream.get());
+
+ Stream vavredStringStream = Stream.of("foo", "bar", "baz");
+ System.out.println("Find foo " + vavredStringStream.indexOf("foo"));
+ }
+
+ public static void vavrParallelStreamAccess() {
+
+ System.out.println("Vavr Stream Concurrent Modification");
+ System.out.println("====================================");
+ Stream vavrStream = Stream.ofAll(intList);
+ // intList.add(5);
+ vavrStream.forEach(i -> System.out.println("in a Vavr Stream: " + i));
+
+ // Stream wrapped = Stream.ofAll(intArray);
+ // intArray[2] = 5;
+ // wrapped.forEach(i -> System.out.println("Vavr looped " + i));
+ }
+
+ public static void jdkFlatMapping() {
+ System.out.println("Java flatMapping");
+ System.out.println("====================================");
+ java.util.stream.Stream.of(42).flatMap(i -> java.util.stream.Stream.generate(() -> {
+ System.out.println("nested call");
+ return 42;
+ })).findAny();
+ }
+
+ public static void vavrFlatMapping() {
+ System.out.println("Vavr flatMapping");
+ System.out.println("====================================");
+ Stream.of(42)
+ .flatMap(i -> Stream.continually(() -> {
+ System.out.println("nested call");
+ return 42;
+ }))
+ .get(0);
+ }
+
+ public static void vavrStreamManipulation() {
+ System.out.println("Vavr Stream Manipulation");
+ System.out.println("====================================");
+ List stringList = new ArrayList<>();
+ stringList.add("foo");
+ stringList.add("bar");
+ stringList.add("baz");
+ Stream vavredStream = Stream.ofAll(stringList);
+ vavredStream.forEach(item -> System.out.println("Vavr Stream item: " + item));
+ Stream vavredStream2 = vavredStream.insert(2, "buzz");
+ vavredStream2.forEach(item -> System.out.println("Vavr Stream item after stream addition: " + item));
+ stringList.forEach(item -> System.out.println("List item after stream addition: " + item));
+ Stream deletionStream = vavredStream.remove("bar");
+ deletionStream.forEach(item -> System.out.println("Vavr Stream item after stream item deletion: " + item));
+
+ }
+
+ public static void vavrStreamDistinct() {
+ Stream vavredStream = Stream.of("foo", "bar", "baz", "buxx", "bar", "bar", "foo");
+ Stream distinctVavrStream = vavredStream.distinctBy((y, z) -> {
+ return y.compareTo(z);
+ });
+ distinctVavrStream.forEach(item -> System.out.println("Vavr Stream item after distinct query " + item));
+
+ }
+}