Merge pull request #10934 from yavuztas/BAEL-3682

BAEL-3682
This commit is contained in:
Jonathan Cook 2021-06-29 10:08:03 +02:00 committed by GitHub
commit 9b5d2b8077
9 changed files with 250 additions and 79 deletions

View File

@ -0,0 +1,29 @@
package com.baeldung.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.oxm.xstream.XStreamMarshaller;
/**
* Another possibility is to create a bean which will be automatically added to the Spring Boot Autoconfigurations.
*
* ATTENTION: Multiple converter registration of the same type most likely causes problem (serialize twice, etc.)
* Therefore, be sure to remove manually added XML message converter first then uncomment
* this @{@link org.springframework.context.annotation.Configuration} to use
*/
//@Configuration
public class ConverterExtensionsConfig {
@Bean
public HttpMessageConverter<Object> createXmlHttpMessageConverter() {
final MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
final XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
xmlConverter.setMarshaller(xstreamMarshaller);
xmlConverter.setUnmarshaller(xstreamMarshaller);
return xmlConverter;
}
}

View File

@ -5,7 +5,6 @@ import java.util.List;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter; import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
@ -16,35 +15,24 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration @Configuration
public class WebConfig implements WebMvcConfigurer { public class WebConfig implements WebMvcConfigurer {
// @Override @Override
// public void configureMessageConverters(final List<HttpMessageConverter<?>> messageConverters) { public void configureMessageConverters(final List<HttpMessageConverter<?>> messageConverters) {
// messageConverters.add(new MappingJackson2HttpMessageConverter()); messageConverters.add(new MappingJackson2HttpMessageConverter());
// messageConverters.add(createXmlHttpMessageConverter()); messageConverters.add(createXmlHttpMessageConverter());
// } }
//
// private HttpMessageConverter<Object> createXmlHttpMessageConverter() {
// final MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
//
// final XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
// xstreamMarshaller.setAutodetectAnnotations(true);
// xmlConverter.setMarshaller(xstreamMarshaller);
// xmlConverter.setUnmarshaller(xstreamMarshaller);
//
// return xmlConverter;
// }
// Another possibility is to create a bean which will be automatically added to the Spring Boot Autoconfigurations /**
// @Bean * There is another possibility to add a message converter, see {@link ConverterExtensionsConfig}
// public HttpMessageConverter<Object> createXmlHttpMessageConverter() { */
// final MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter(); private HttpMessageConverter<Object> createXmlHttpMessageConverter() {
// final MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
// final XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
// xstreamMarshaller.setAutodetectAnnotations(true); final XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
// xmlConverter.setMarshaller(xstreamMarshaller); xmlConverter.setMarshaller(xstreamMarshaller);
// xmlConverter.setUnmarshaller(xstreamMarshaller); xmlConverter.setUnmarshaller(xstreamMarshaller);
//
// return xmlConverter; return xmlConverter;
// } }
// Etags // Etags
@ -52,16 +40,17 @@ public class WebConfig implements WebMvcConfigurer {
// AbstractAnnotationConfigDispatcherServletInitializer#getServletFilters // AbstractAnnotationConfigDispatcherServletInitializer#getServletFilters
@Bean @Bean
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() { public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
FilterRegistrationBean<ShallowEtagHeaderFilter> filterRegistrationBean = new FilterRegistrationBean<>( new ShallowEtagHeaderFilter()); FilterRegistrationBean<ShallowEtagHeaderFilter> filterRegistrationBean =
new FilterRegistrationBean<>(new ShallowEtagHeaderFilter());
filterRegistrationBean.addUrlPatterns("/foos/*"); filterRegistrationBean.addUrlPatterns("/foos/*");
filterRegistrationBean.setName("etagFilter"); filterRegistrationBean.setName("etagFilter");
return filterRegistrationBean; return filterRegistrationBean;
} }
// We can also just declare the filter directly // We can also just declare the filter directly
// @Bean // @Bean
// public ShallowEtagHeaderFilter shallowEtagHeaderFilter() { // public ShallowEtagHeaderFilter shallowEtagHeaderFilter() {
// return new ShallowEtagHeaderFilter(); // return new ShallowEtagHeaderFilter();
// } // }
} }

View File

@ -1,16 +0,0 @@
package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {SpringBootRestApplication.class})
public class SpringContextTest {
@Test
public void contextLoads() {
}
}

View File

@ -24,6 +24,7 @@ import com.google.common.net.HttpHeaders;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import io.restassured.response.Response; import io.restassured.response.Response;
import org.springframework.http.MediaType;
public abstract class AbstractBasicLiveTest<T extends Serializable> extends AbstractLiveTest<T> { public abstract class AbstractBasicLiveTest<T extends Serializable> extends AbstractLiveTest<T> {
@ -36,7 +37,7 @@ public abstract class AbstractBasicLiveTest<T extends Serializable> extends Abst
@Test @Test
public void whenResourcesAreRetrievedPaged_then200IsReceived() { public void whenResourcesAreRetrievedPaged_then200IsReceived() {
create(); create();
final Response response = RestAssured.get(getURL() + "?page=0&size=10"); final Response response = RestAssured.get(getURL() + "?page=0&size=10");
assertThat(response.getStatusCode(), is(200)); assertThat(response.getStatusCode(), is(200));
@ -54,7 +55,8 @@ public abstract class AbstractBasicLiveTest<T extends Serializable> extends Abst
public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() { public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() {
create(); create();
final Response response = RestAssured.get(getURL() + "?page=0&size=10"); final Response response = RestAssured.given()
.accept(MediaType.APPLICATION_JSON_VALUE).get(getURL() + "?page=0&size=10");
assertFalse(response.body().as(List.class).isEmpty()); assertFalse(response.body().as(List.class).isEmpty());
} }
@ -64,7 +66,7 @@ public abstract class AbstractBasicLiveTest<T extends Serializable> extends Abst
create(); create();
create(); create();
create(); create();
final Response response = RestAssured.get(getURL() + "?page=0&size=2"); final Response response = RestAssured.get(getURL() + "?page=0&size=2");
final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next"); final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next");
@ -95,7 +97,7 @@ public abstract class AbstractBasicLiveTest<T extends Serializable> extends Abst
create(); create();
create(); create();
create(); create();
final Response first = RestAssured.get(getURL() + "?page=0&size=2"); final Response first = RestAssured.get(getURL() + "?page=0&size=2");
final String uriToLastPage = extractURIByRel(first.getHeader(HttpHeaders.LINK), "last"); final String uriToLastPage = extractURIByRel(first.getHeader(HttpHeaders.LINK), "last");
@ -104,7 +106,7 @@ public abstract class AbstractBasicLiveTest<T extends Serializable> extends Abst
final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next"); final String uriToNextPage = extractURIByRel(response.getHeader(HttpHeaders.LINK), "next");
assertNull(uriToNextPage); assertNull(uriToNextPage);
} }
// etags // etags
@Test @Test

View File

@ -1,21 +1,22 @@
package com.baeldung.web; package com.baeldung.web;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.baeldung.persistence.dao.IFooDao;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
/** /**
* * We'll start the whole context, but not the server. We'll mock the REST calls instead.
* We'll start the whole context, but not the server. We'll mock the REST calls instead.
*
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest @SpringBootTest
@ -25,12 +26,22 @@ public class FooControllerAppIntegrationTest {
@Autowired @Autowired
private MockMvc mockMvc; private MockMvc mockMvc;
@Autowired
private IFooDao fooDao;
@Before
public void setup() {
this.fooDao.deleteAll();
}
@Test @Test
public void whenFindPaginatedRequest_thenEmptyResponse() throws Exception { public void whenFindPaginatedRequest_thenEmptyResponse() throws Exception {
this.mockMvc.perform(get("/foos").param("page", "0") this.mockMvc.perform(get("/foos")
.param("size", "2")) .param("page", "0")
.andExpect(status().isOk()) .param("size", "2")
.andExpect(content().json("[]")); .accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().json("[]"));
} }
} }

View File

@ -40,7 +40,7 @@ public class FooControllerCustomEtagIntegrationTest {
private static String createFooJson() throws Exception { private static String createFooJson() throws Exception {
return serializeFoo(new Foo(randomAlphabetic(6))); return serializeFoo(new Foo(randomAlphabetic(6)));
} }
private static Foo deserializeFoo(String fooJson) throws Exception { private static Foo deserializeFoo(String fooJson) throws Exception {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(fooJson, Foo.class); return mapper.readValue(fooJson, Foo.class);
@ -97,7 +97,8 @@ public class FooControllerCustomEtagIntegrationTest {
.getResponse() .getResponse()
.getHeader(HttpHeaders.LOCATION); .getHeader(HttpHeaders.LOCATION);
ResultActions findOneResponse = this.mvc ResultActions findOneResponse = this.mvc
.perform(get(createdResourceUri + CUSTOM_ETAG_ENDPOINT_SUFFIX).contentType(MediaType.APPLICATION_JSON)); .perform(get(createdResourceUri + CUSTOM_ETAG_ENDPOINT_SUFFIX)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON));
String etag = findOneResponse.andReturn().getResponse().getHeader(HttpHeaders.ETAG); String etag = findOneResponse.andReturn().getResponse().getHeader(HttpHeaders.ETAG);
Foo createdFoo = deserializeFoo(findOneResponse.andReturn().getResponse().getContentAsString()); Foo createdFoo = deserializeFoo(findOneResponse.andReturn().getResponse().getContentAsString());
createdFoo.setName("updated name"); createdFoo.setName("updated name");

View File

@ -20,6 +20,7 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
@ -30,7 +31,7 @@ import com.baeldung.web.exception.CustomException1;
import com.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent; import com.baeldung.web.hateoas.event.PaginatedResultsRetrievedEvent;
/** /**
* *
* We'll start only the web layer. * We'll start only the web layer.
* *
*/ */
@ -54,20 +55,22 @@ public class FooControllerWebLayerIntegrationTest {
doNothing().when(publisher) doNothing().when(publisher)
.publishEvent(any(PaginatedResultsRetrievedEvent.class)); .publishEvent(any(PaginatedResultsRetrievedEvent.class));
this.mockMvc.perform(get("/foos").param("page", "0") this.mockMvc.perform(get("/foos")
.param("size", "2")) .param("page", "0")
.andExpect(status().isOk()) .param("size", "2")
.andExpect(jsonPath("$",Matchers.hasSize(1))); .accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.hasSize(1)));
} }
@Test @Test
public void delete_forException_fromService() throws Exception { public void delete_forException_fromService() throws Exception {
Mockito.when(service.findAll()).thenThrow(new CustomException1()); Mockito.when(service.findAll()).thenThrow(new CustomException1());
this.mockMvc.perform(get("/foos")).andDo(h -> { this.mockMvc.perform(get("/foos")).andDo(h -> {
final Exception expectedException = h.getResolvedException(); final Exception expectedException = h.getResolvedException();
Assert.assertTrue(expectedException instanceof CustomException1); Assert.assertTrue(expectedException instanceof CustomException1);
}); });
} }
} }

View File

@ -0,0 +1,149 @@
package com.baeldung.web;
import static com.baeldung.Consts.APPLICATION_PORT;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import com.baeldung.common.web.AbstractLiveTest;
import com.baeldung.persistence.model.Foo;
import com.baeldung.spring.ConfigIntegrationTest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.oxm.xstream.XStreamMarshaller;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.web.client.RestTemplate;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ConfigIntegrationTest.class }, loader = AnnotationConfigContextLoader.class)
@ActiveProfiles("test")
public class FooMessageConvertersLiveTest extends AbstractLiveTest<Foo> {
private static final String BASE_URI = "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/";
public FooMessageConvertersLiveTest() {
super(Foo.class);
}
@Override
public final void create() {
create(new Foo(randomAlphabetic(6)));
}
@Override
public final String createAsUri() {
return createAsUri(new Foo(randomAlphabetic(6)));
}
@Before
public void setup(){
create();
}
/**
* Without specifying Accept Header, uses the default response from the
* server (in this case json)
*/
@Test
public void whenRetrievingAFoo_thenCorrect() {
final String URI = BASE_URI + "foos/{id}";
final RestTemplate restTemplate = new RestTemplate();
final Foo resource = restTemplate.getForObject(URI, Foo.class, "1");
assertThat(resource, notNullValue());
}
@Test
public void givenConsumingXml_whenReadingTheFoo_thenCorrect() {
final String URI = BASE_URI + "foos/{id}";
final RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(getXmlMessageConverters());
final HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_XML));
final HttpEntity<String> entity = new HttpEntity<>(headers);
final ResponseEntity<Foo>
response = restTemplate.exchange(URI, HttpMethod.GET, entity, Foo.class, "1");
final Foo resource = response.getBody();
assertThat(resource, notNullValue());
}
private List<HttpMessageConverter<?>> getXmlMessageConverters() {
final XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.setAnnotatedClasses(Foo.class);
final MarshallingHttpMessageConverter marshallingConverter = new MarshallingHttpMessageConverter(marshaller);
final List<HttpMessageConverter<?>> converters = new ArrayList<>();
converters.add(marshallingConverter);
return converters;
}
@Test
public void givenConsumingJson_whenReadingTheFoo_thenCorrect() {
final String URI = BASE_URI + "foos/{id}";
final RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(getJsonMessageConverters());
final HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
final HttpEntity<String> entity = new HttpEntity<String>(headers);
final ResponseEntity<Foo> response = restTemplate.exchange(URI, HttpMethod.GET, entity, Foo.class, "1");
final Foo resource = response.getBody();
assertThat(resource, notNullValue());
}
private List<HttpMessageConverter<?>> getJsonMessageConverters() {
final List<HttpMessageConverter<?>> converters = new ArrayList<>();
converters.add(new MappingJackson2HttpMessageConverter());
return converters;
}
@Test
public void givenConsumingXml_whenWritingTheFoo_thenCorrect() {
final String URI = BASE_URI + "foos";
final RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(getJsonAndXmlMessageConverters());
final Foo resource = new Foo("jason");
final HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType((MediaType.APPLICATION_XML));
final HttpEntity<Foo> entity = new HttpEntity<>(resource, headers);
final ResponseEntity<Foo> response = restTemplate.exchange(URI, HttpMethod.POST, entity, Foo.class);
final Foo fooResponse = response.getBody();
assertThat(fooResponse, notNullValue());
assertEquals(resource.getName(), fooResponse.getName());
}
private List<HttpMessageConverter<?>> getJsonAndXmlMessageConverters() {
final List<HttpMessageConverter<?>> converters = getJsonMessageConverters();
converters.addAll(getXmlMessageConverters());
return converters;
}
}

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ -43,12 +44,12 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest<Foo> {
public final String createAsUri() { public final String createAsUri() {
return createAsUri(new Foo(randomAlphabetic(6))); return createAsUri(new Foo(randomAlphabetic(6)));
} }
@Override @Override
@Test @Test
public void whenResourcesAreRetrievedPaged_then200IsReceived() { public void whenResourcesAreRetrievedPaged_then200IsReceived() {
this.create(); this.create();
final Response response = RestAssured.get(getPageableURL() + "?page=0&size=10"); final Response response = RestAssured.get(getPageableURL() + "?page=0&size=10");
assertThat(response.getStatusCode(), is(200)); assertThat(response.getStatusCode(), is(200));
@ -68,13 +69,15 @@ public class FooPageableLiveTest extends AbstractBasicLiveTest<Foo> {
public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() { public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources() {
create(); create();
final Response response = RestAssured.get(getPageableURL() + "?page=0&size=10"); final Response response = RestAssured.given()
.accept(MediaType.APPLICATION_JSON_VALUE)
.get(getPageableURL() + "?page=0&size=10");
assertFalse(response.body().as(List.class).isEmpty()); assertFalse(response.body().as(List.class).isEmpty());
} }
protected String getPageableURL() { protected String getPageableURL() {
return "http://localhost:" + APPLICATION_PORT + "/spring-boot-rest/foos/pageable"; return getURL() + "/pageable";
} }
} }