Spring Boot integration test - TestRestTemplate how to set response Content-Type to UTF-8 - spring-boot

I tried to integrate test Spring Boot application, now I got one issue
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class org.springframework.http.ResponseEntity] and content type [application/x-json;charset=iso-8859-1]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:109)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:917)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:901)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
at org.springframework.boot.test.web.client.TestRestTemplate.exchange(TestRestTemplate.java:735)
If I do below
#Before
public void init() {
List<HttpMessageConverter<?>> converters = restTemplate.getRestTemplate().getMessageConverters();
for (HttpMessageConverter converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter jsonConverter = (MappingJackson2HttpMessageConverter) converter;
jsonConverter.setObjectMapper(new ObjectMapper());
jsonConverter.setSupportedMediaTypes(ImmutableList
.of(new MediaType("application", "x-json", Charset.forName("iso-8859-1"))));
}
}
}
I added the application/x-json and iso8859-1 support to MappingJackson2HttpMessageConverter, it can works well.
This is an workaround, but I want to know why the response content-type is application/x-json;charset=iso-8859-1? I have the produces configuration in my controller
#RequestMapping(method = RequestMethod.GET, value = "/{id}", produces = "application/json;charset=UTF-8")
Does someone know how to config it and let the response use "application/json;charset=UTF-8" content type?
Below is my test method
#Autowired
protected TestRestTemplate restTemplate;
#Test
public void testGetPerformanceObligationById() {
PerformanceObligationEntity entity = restTemplate.getForObject("/performance-obligations/{id}", PerformanceObligationEntity.class, "InvalidId");
Assert.assertNull(entity.getId());
}
I added one filter
#TestConfiguration
static class Config {
#Bean
public CharacterEncodingFilter characterEncodingFilter() {
final CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return characterEncodingFilter;
}
}
Also modify the converter to
#Before
public void init() {
List<HttpMessageConverter<?>> converters =
restTemplate.getRestTemplate().getMessageConverters();
for (HttpMessageConverter converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter jsonConverter = (MappingJackson2HttpMessageConverter) converter;
jsonConverter.setObjectMapper(new ObjectMapper());
jsonConverter.setSupportedMediaTypes(ImmutableList
.of(new MediaType("application", "x-json", Charset.forName("UTF-8"))));
}
}
}
Now I got application/x-json;charset=utf-8, so just remain how to config from application/x-json to application/json

Related

Spring WS - return non-MTOM on MTOM request

I have a SOAP service that receives a binary attachment (MTOM). The issue is that I would like to return a non-MTOM response (a "clean" SOAP return). The current code return a multipart response and uses "xop+xml" content-type.
The code is:
#Configuration
public class MyWebServiceConfig {
#Value("${config1}")
private String contextPath;
#Value("${config2}")
private String namespace;
#Value("${config3}")
private String wsdl;
#Bean
ServletRegistrationBean<?> webServicesRegistration(ApplicationContext ctx) {
MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet();
messageDispatcherServlet.setApplicationContext(ctx);
messageDispatcherServlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(messageDispatcherServlet, contextPath, "*.wsdl");
}
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(namespace);
marshaller.setMtomEnabled(true);
return marshaller;
}
#Bean
public MarshallingPayloadMethodProcessor methodProcessor(Jaxb2Marshaller marshaller) {
return new MarshallingPayloadMethodProcessor(marshaller);
}
#Bean
DefaultMethodEndpointAdapter endpointAdapter(MarshallingPayloadMethodProcessor methodProcessor) {
DefaultMethodEndpointAdapter adapter = new DefaultMethodEndpointAdapter();
adapter.setMethodArgumentResolvers(Collections.singletonList(methodProcessor));
adapter.setMethodReturnValueHandlers(Collections.singletonList(methodProcessor));
return adapter;
}
#Bean
public SimpleWsdl11Definition contentStore() {
SimpleWsdl11Definition definition = new SimpleWsdl11Definition();
definition.setWsdl(new ClassPathResource(wsdl));
return definition;
}
}
I have tried changing to setMtomEnabled(false) - but then the request is not handled correctly.
Is the anyway of receiving MTOM - but returning a non-MTOM response?
Edit:
Endpoint looks like this:
#Endpoint
public class MyEndpoint {
private ObjectFactory objectFactory;
public MyEndpoint() {
this.objectFactory = new ObjectFactory();
}
#PayloadRoot(localPart = "SendMyRequest", namespace = "somenamespace")
#ResponsePayload
public JAXBElement<MyReceipt> store(#RequestPayload JAXBElement<MyRequest> storeContentRequest) throws IOException {
MyReceipt receipt = new MyReceipt();
receipt.setf1(123);
receipt.setf2(456);
return this.objectFactory.createMyResponse(receipt);
}
}

Spring MVC 5 Rest API convert XML to Bean using JAXB

We are migrating Jersey Endpoints to Spring MVC Rest endpoints. These endpoints consumes and produces XML. But Spring MVC is unable to convert the XML input bean because XML tag and Bean's property name is different. I have to take request as String and Convert it using JAXB explicitly. Is there any better way to do that?
Web Configuration
#EnableWebMvc
#Configuration
public class WebConfig implements WebMvcConfigurer {
public static final String JAXB_PACKAGE = "com.comp.platform.dataholder";
#Autowired
private Jackson2ObjectMapperBuilder builder;
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new StringHttpMessageConverter());
converters.add(new FormHttpMessageConverter());
converters.add(createXmlHttpMessageConverter());
converters.add(createMappingJacksonHttpMessageConverter(builder));
// converters.add(createMappingJackson2XmlHttpMessageConverter(xmlMapper));
Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter = new Jaxb2RootElementHttpMessageConverter();
jaxb2RootElementHttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_XML));
converters.add(jaxb2RootElementHttpMessageConverter);
}
#Bean
public Jackson2ObjectMapperBuilder customJson() {
return new Jackson2ObjectMapperBuilder().indentOutput(true).serializationInclusion(JsonInclude.Include.NON_NULL)
.propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE).failOnUnknownProperties(false);
}
#Bean
#Primary
public ObjectMapper createObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper mapper = builder.build();
mapper.setSerializationInclusion(Include.NON_NULL);
return mapper;
}
#Bean
public Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(NonFinancialDataHolder.class, JaxbDataHolder.class, ViestimateDataHolder.class,CTRequest.class,com.app.rest.PolicyDetailRequest.class,com.app.rest.TransactionSubmitRequest.class,com.app.rest.AgentSuppressInfoRequest.class);
return marshaller;
}
/**
* #return
*/
#Bean
public MappingJackson2HttpMessageConverter createMappingJacksonHttpMessageConverter(
Jackson2ObjectMapperBuilder builder) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(builder.build());
return converter;
}
#Autowired
Jaxb2Marshaller jaxb2Marshaller;
private HttpMessageConverter<Object> createXmlHttpMessageConverter() {
Assert.notNull(jaxb2Marshaller, "Jaxb Marshaller dependency required");
MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter(jaxb2Marshaller);
xmlConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_XML));
return xmlConverter;
}
public JAXBContext getMarshaller() throws JAXBException {
return JAXBContext.newInstance(JAXB_PACKAGE);
}
}
Bean
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"_UserId",
"_Password",
"_RequestDateTime",
"_Policy"
})
#XmlRootElement(name = "PolicyDetailRequest")
public class PolicyDetailRequest
{
#XmlElement(name = "UserId")
protected String _UserId;
#XmlElement(name = "Password")
protected String _Password;
#XmlElement(name = "RequestDateTime")
protected String _RequestDateTime;
#XmlElement(name = "Policy")
protected String _Policy;
}
Rest Endpoint
#Slf4j
#RestController
#RequestMapping("/api")
public class api
{
#Autowired
Jaxb2Marshaller jaxb2Marshaller;
#PostMapping(value="/PolicyResponse",produces=MediaType.APPLICATION_XML_VALUE,consumes = MediaType.APPLICATION_XML_VALUE)
#ResponseBody
public PolicyDetailResponse getPolicyResponse(#RequestBody String data)
{
PolicyDetailRequest request = (PolicyDetailRequest) jaxb2Marshaller.unmarshal(new StreamSource(new StringReader(data)));
PolicyDetailResponse response = new PolicyDetailResponse();
InternetRSHandler handler = new InternetRSHandler();
response= handler.getPolicyRSResponse(request);
return response;
}
}
Input Request
<PolicyDetailRequest>
<UserId>1234567890</UserId>
<Password>password</Password>
<RequestDateTime>20200420-15:07:23</RequestDateTime>
<Policy>A76ABCD12</Policy>
</PolicyDetailRequest>

Override JSON properties in #RestController in Spring 4.3.3 WebMVC

I want to override the following properties in Spring RestController in WebMVC.
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper.setDateFormat(DATEFORMAT);
I've tried the following in multiple combinations, but nothing worked. Still getting the null value without root name in the response.
#EnableWebMvc
public class ApplicationContextConfig extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper.setDateFormat(DATEFORMAT);
//jsonConverter.setObjectMapper(objectMapper);
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(objectMapper);
//jsonConverter.setJsonPrefix(jsonPrefix);
converters.add(jsonConverter);
}
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter jsonMessageConverter = (MappingJackson2HttpMessageConverter) converter;
ObjectMapper objectMapper = jsonMessageConverter.getObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper.setDateFormat(DATEFORMAT);
break;
}
}
}
#Bean
#Primary
public ObjectMapper getObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper.setDateFormat(DATEFORMAT);
return objectMapper;
}
}
Reponse:
{
"Message": null,
"Admin": null,
"Company": null
}
You should "substitute" the object mapper bean provided by spring with your own and configure it.
#Configuration
public class MyJacksonCustomConfiguration {
#Bean
public ObjectMapper objectMapper() { // note the name should be 'objectMapper'
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper.setDateFormat(DATEFORMAT);
return objectMapper;
}
}
All in all, make sure that only one bean of type object mapper should exist in the application context. Apart of fact that its a pretty "heavy" object, if spring will inject a wrong mapper you won't be able to benefit from customization that you've done.

Spring Boot 1.5.4 Filter out null values in json response

I am using Spring Boot 1.5.4 version . I am using spring-ws getWebServiceTemplate() to make a webservice call. The SOAP response has lot of null values for the fields.
I am trying to filter out the null values in the JSON response. None of the following approaches seem to work:
Setting the property in the application.properties:
spring.jackson.default-property-inclusion:NON_NULL`
Setting it in Configuration class using Jackson2ObjectMapperBuilder:
#Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
builder.serializationInclusion(JsonInclude.Include.NON_EMPTY);
return builder;
}
Please advise.
lva
I am using Spring Boot 1.5.6.RELEASE version, and you can reference
customize-the-jackson-objectmapper
Following code is work:
#SpringBootApplication
public class Application {
#Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
return builder;
}
public static void main(String[] args) {
SpringApplication.run(DbeeApiApplication.class, args);
}
}
Or you can filter from MappingJackson2HttpMessageConverter, for example:
#Configuration
class WebMvcConfiguration extends WebMvcConfigurationSupport {
#Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for(HttpMessageConverter<?> converter: converters) {
if(converter instanceof MappingJackson2HttpMessageConverter) {
ObjectMapper mapper = ((MappingJackson2HttpMessageConverter)converter).getObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);
}
}
}
}
Using the following in application.properties worked.
spring.jackson.default-property-inclusion=NON_NULL

Resttemplate - how to post object with HAL representation?

When attempting to post to a Spring-Data-Rest web service via RestTemplate, the JSON representation of my domain object is being converted to a full blown JSON object that isn't in HAL representation. My assumption here is that I need to register the Jackson2HalModule as a deserializer though am not sure how to do that considering I register it to the objectMapper. The serialization works correctly when calling GET on the webservice, just not for POST/PUT:
Request outputBuffer field:
{
"id" : 1,
"name" : "Name",
"description" : "",
"childObject" : {
"id" : 1,
"name" : "test"
}
}
Rest Template configuration:
#Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JodaModule());
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.setDateFormat(new ISO8601DateFormat());
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.registerModule(new Jackson2HalModule());
return objectMapper;
}
public void configureMessageConverters(
List<HttpMessageConverter<?>> messageConverters) {
MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
jsonMessageConverter.setObjectMapper(objectMapper());
jsonMessageConverter.setSupportedMediaTypes(MediaType
.parseMediaTypes("application/hal+json,application/json"));
messageConverters.add(jsonMessageConverter);
}
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
configureMessageConverters(messageConverters);
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
Request Headers:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Calling method:
ResponseEntity<DomainObject> responseEntity =
restTemplate.exchange(this.getBaseUri() + resolveResource(), HttpMethod.POST, new HttpEntity(domainObject,createHttpHeaders(tenantId)), DomainObject.class);
I think you should not register your own ObjectMapper. Spring creates it for you and also registers all the modules needed. So I would just try to remove your ObjectMapper bean.
If you need to customize the ObjectMapper you could use a Jackson2ObjectMapperBuilder. See the documentation for more details - http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-customize-the-jackson-objectmapper
#Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
return Jackson2ObjectMapperBuilder //
.json() //
.locale(ENGLISH) //
.timeZone("UTC") //
.indentOutput(true) //
.serializationInclusion(NON_NULL) //
.featuresToDisable(WRITE_DATES_AS_TIMESTAMPS, FAIL_ON_UNKNOWN_PROPERTIES) //
;
}
I would also let spring take care of the message converters:
So let spring inject them when you create the RestTemplate - so something like this:
#Bean
public RestTemplate restTemplate(List<HttpMessageConverter<?>> messageConverters) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}

Resources