spring boot setContentType is not working - spring

I'm trying to return an image on spring-boot (1.2.2)
How should I set the content-type?
Non of the following are working for me (meaning that response headers are not containing 'content-type' header at all ):
#RequestMapping(value = "/files2/{file_name:.+}", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> getFile2(final HttpServletResponse response) throws IOException {
InputStream is = //someInputStream...
org.apache.commons.io.IOUtils.copy(is, response.getOutputStream());
response.setContentType("image/jpeg");
InputStreamResource inputStreamR = new InputStreamResource(is);
return new ResponseEntity<>(inputStreamR, HttpStatus.OK);
}
#RequestMapping(value = "/files3/{file_name:.+}", method = RequestMethod.GET)
public HttpEntity<byte[]> getFile3() throws IOException {
InputStream is = //someInputStream...
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
return new HttpEntity<>(IOUtils.toByteArray(is), headers);
}

Firstly, you'll need to apply the #ResponseBody annotation in addition to #RequestMapping, unless you are using #RestController at the class level instead of just #Controller. Also, try the produces element of #RequestMapping e.g.
#RequestMapping(value = "/files2/{file_name:.+}", method = RequestMethod.GET, produces = {MediaType.IMAGE_JPEG_VALUE})
This should 'narrow the primary mapping' and ensure the correct content type is set. See the docs: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-requestmapping-produces

Got it... Had to add ByteArrayHttpMessageConverter to WebConfiguration class:
#Configuration
#EnableWebMvc
#ComponentScan
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> httpMessageConverters) {
httpMessageConverters.add(new ByteArrayHttpMessageConverter());
}
}
And the then my second attempt (getFile3()) was working correctly

Related

Get return value in custom annotation spring aop

I have write a simple custom annotation to set HttpHeaders to ResponseEntity because of duplicating the code every where .
Annotation Interface and Class.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface JsonHeader {}
#Component
#Aspect
public class JsonHeaderAspect {
private final Log logger = LogFactory.getLog(getClass());
#Around(value = "#annotation(JsonHeader)")
public Object aroundServiceResponse(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
return proceedingJoinPoint.proceed(new Object[] {headers});
}
}
RestController Class
#RestController
#RequestMapping(path = "/login")
public class LoginRestController {
private final Log logger = LogFactory.getLog(getClass());
#Autowired
LoginServiceImpl loginService;
#JsonHeader
#RequestMapping(value = "/user",consumes = MediaType.APPLICATION_JSON_VALUE,produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResponseBean> postCheckUser(#RequestBody LoginBean loginBean) {
ResponseBean responseBean = loginService.checkUser(loginBean);
return new ResponseEntity<ResponseBean>(responseBean,headers, HttpStatus.OK);
}
}
Now I want to get the return HttpHeaders value annotaion to rest controller class.
Is any one can describe why it happen and how to fix this issue it will be great helpful. Thanks in advance
You can do this simply by modifying your advice like this. You don't need to do anything in the controller.
#Around(value = "#annotation(requestMapping)")
public Object aroundServiceResponse(ProceedingJoinPoint proceedingJoinPoint,RequestMapping requestMapping) throws Throwable {
String[] consumes = requestMapping.consumes();
consumes[consumes.length] = MediaType.APPLICATION_JSON_VALUE;
String[] produces = requestMapping.produces();
produces[produces.length] = MediaType.APPLICATION_JSON_VALUE;
return proceedingJoinPoint.proceed();
}

Spring MVC Controller show 404

All i need help
this is my simple controller when i try to hit the url on postman it's
show 404 => response can any one tell me why it's come. i'm using the spring-boot project.
#Controller
#RequestMapping(value = "/rtb")
public class RtbTestController {
#RequestMapping(value = {"/naveen", "/nabeel", "/harsh"}, method = RequestMethod.GET)
public ModelAndView rtbResponseValidator(HttpServletRequest request, HttpServletResponse response) {
HashMap<String, Object> model = new HashMap<String, Object>();
model.put("pakistan", "zindabad");
model.put("indian", "Zindabad");
return new ModelAndView("openRTB", model);
}
}
Try this:
#Controller
#RequestMapping(value = "/rtb")
public class RtbTestController {
#RequestMapping(value = {"/naveen", "/nabeel", "/harsh"}, method = RequestMethod.GET, headers= "Accept=application/json")
public ModelAndView rtbResponseValidator(HttpServletRequest request, HttpServletResponse response) {
HashMap<String, Object> model = new HashMap<String, Object>();
model.put("pakistan", "zindabad");
model.put("indian", "Zindabad");
return new ModelAndView("openRTB", model);
}
}

Feign Client Error Handling

I am using Feign Client,
I have a Location service. So I created a client for my LocationService using FeignClient.
#FeignClient(url="http://localhost:9003/location/v1", name="location-service")
public interface LocationControllerVOneClient {
#RequestMapping(value = "/getMultipleLocalities", method = RequestMethod.POST)
public Response<Map<Integer, Locality>> getMultipleLocalities(List<Integer> localityIds);
#RequestMapping(value = "/getMultipleCities", method = RequestMethod.POST)
public Response<Map<Integer, City>> getMultipleCities(List<Integer> cityIds);
#RequestMapping(value = "/getMultipleStates", method = RequestMethod.POST)
public Response<Map<Integer, State>> getMultipleStates(List<Integer> stateIds);
#RequestMapping(value = "/getMultipleCitiesName", method = RequestMethod.POST)
public Response<Map<Integer, String>> getMultipleCitiesName(MultiValueMap<String, String> formParams);
#RequestMapping(value = "/getMultipleStatesName", method = RequestMethod.POST)
public Response<Map<Integer, String>> getMultipleStatesName(MultiValueMap<String, String> formParams);
#RequestMapping(value = "/getMultipleLocalitiesName", method = RequestMethod.POST)
public Response<Map<Integer, String>> getMultipleLocalitiesName(MultiValueMap<String, String> formParams);
}
Now other services might call this LocationService via LocationClient.
I want to do exception handling for this Feign Client(LocationClient) at a common place(i.e. I just donot want each caller to do this. This should be part of LocationClient). Exception Could be connection refused(if LocationService is down), timeout etc.
You could use a feign ErrorDecoder for exception handling. Below is the url for your reference.
https://github.com/OpenFeign/feign/wiki/Custom-error-handling
Example :
public class MyErrorDecoder implements ErrorDecoder {
private final ErrorDecoder defaultErrorDecoder = new Default();
#Override
public Exception decode(String methodKey, Response response) {
if (response.status() >= 400 && response.status() <= 499) {
return new MyBadRequestException();
}
return defaultErrorDecoder.decode(methodKey, response);
}
}
To get this ErrorDecoder you need create a bean for it as below :
#Bean
public MyErrorDecoder myErrorDecoder() {
return new MyErrorDecoder();
}
You can define a fallback client that is called when an exception like timeout or connection refused comes up:
#FeignClient(url="http://localhost:9003/location/v1", name="location-service", fallback=LocationFallbackClient.class)
public interface LocationControllerVOneClient {
...
}
LocationFallbackClient must implement LocationControllerVOneClient.

Using #Headers with dynamic values in Feign client + Spring Cloud (Brixton RC2)

Is it possible to set dynamic values to a header ?
#FeignClient(name="Simple-Gateway")
interface GatewayClient {
#Headers("X-Auth-Token: {token}")
#RequestMapping(method = RequestMethod.GET, value = "/gateway/test")
String getSessionId(#Param("token") String token);
}
Registering an implementation of RequestInterceptor adds the header but there is no way of setting the header value dynamically
#Bean
public RequestInterceptor requestInterceptor() {
return new RequestInterceptor() {
#Override
public void apply(RequestTemplate template) {
template.header("X-Auth-Token", "some_token");
}
};
}
I found the following issue on github and one of the commenters (lpborges) was trying to do something similar using headers in #RequestMapping annotation.
https://github.com/spring-cloud/spring-cloud-netflix/issues/288
Kind Regards
The solution is to use #RequestHeader annotation instead of feign specific annotations
#FeignClient(name="Simple-Gateway")
interface GatewayClient {
#RequestMapping(method = RequestMethod.GET, value = "/gateway/test")
String getSessionId(#RequestHeader("X-Auth-Token") String token);
}
The #RequestHeader did not work for me. What did work was:
#Headers("X-Auth-Token: {access_token}")
#RequestLine("GET /orders/{id}")
Order get(#Param("id") String id, #Param("access_token") String accessToken);
#HeaderMap,#Header and #Param didn't worked for me, below is the solution to use #RequestHeader when there are multiple header parameters to pass using FeignClient
#PostMapping("/api/channelUpdate")
EmployeeDTO updateRecord(
#RequestHeader Map<String, String> headerMap,
#RequestBody RequestDTO request);
code to call the proxy is as below:
Map<String, String> headers = new HashMap<>();
headers.put("channelID", "NET");
headers.put("msgUID", "1234567889");
ResponseDTO response = proxy.updateRecord(headers,requestDTO.getTxnRequest());
I have this example, and I use #HeaderParam instead #RequestHeader :
import rx.Single;
import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
#Consumes(MediaType.APPLICATION_JSON)
public interface FeignRepository {
#POST
#Path("/Vehicles")
Single<CarAddResponse> add(#HeaderParam(HttpHeaders.AUTHORIZATION) String authorizationHeader, VehicleDto vehicleDto);
}
You can use HttpHeaders.
#PostMapping(path = "${path}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<?> callService(#RequestHeader HttpHeaders headers, #RequestBody Object object);
private HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "1234");
headers.add("CLIENT_IT", "dummy");
return headers;
}
I use #HeaderMap as it seems very handy if you are working with Open feign. Using this way you can pass header keys and values dynamically.
#Headers({"Content-Type: application/json"})
public interface NotificationClient {
#RequestLine("POST")
String notify(URI uri, #HeaderMap Map<String, Object> headers, NotificationBody body);
}
Now create feign REST client to call the service end point, create your header properties map and pass it in method parameter.
NotificationClient notificationClient = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(customDecoder())
.target(Target.EmptyTarget.create(NotificationClient.class));
Map<String, Object> headers = new HashMap<>();
headers.put("x-api-key", "x-api-value");
ResponseEntity<String> response = notificationClient.notify(new URI("https://stackoverflow.com/example"), headers, new NotificationBody());
A bit late to the game here, but if one needs an enforced, templated value, I discovered that this works in Spring Boot. Apparently, as long as the toString() gives a valid header value, you can use any type.
#FeignClient(
name = "my-feign-client",
url = "http://my-url.com"
)
public interface MyClient {
#GetMapping(
path = "/the/endpoint",
produces = MediaType.APPLICATION_JSON_VALUE
)
DataResponse getData(#RequestHeader(HttpHeaders.AUTHORIZATION) BearerHeader bearerHeader);
final class BearerHeader {
private final String token;
private BearerHeader(String token) {
this.token = token;
}
#Override
public String toString() {
return String.format("Bearer %s", token);
}
public static BearerHeader of(String token) {
return new BearerHeader(token);
}
}

Spring Framework TEST RESTful Web Service (Controller) Offline i.e. No Server, No Database

I have a very simple RESTful Controller that consumes and produces JSON. I need to test this controller offline i.e. no server running, no database running. And I am going nuts for not being able to find a solution. My intial test cases will include:
Test REST URIs i.e. GET, POST, PUT, DELETE - I must be able to Assert data returned against data sent.
Assert will test JSON data
I have the following URIs:
/pcusers - Returns all users
/pcusers/{id} - Return a specific user
/pcusers/create/{pcuser} - Add user to db
/pcusers/update/{pcuser} - Update user
/pcusers/delete/{id} - Delete User
NOTE: This is NOT a typical MVC application. I DO NOT have Views. I have a pure REST controller that spits out JSON and consumes data in JSON format.
If someone could guide me in the right direction would be really appreciated.
Just to be clear how my code looks like:
#Controller
#RequestMapping("/pcusers")
public class PcUserController {
protected static Logger logger = Logger.getLogger(PcUserController.class);
#Resource(name = "pcUserService")
private PcUserService pcUserService;
#RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public List<PcUser> readAll() {
logger.debug("Delegating to service to return all PcUsers");
return pcUserService.readAll();
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET, consumes = "application/json", produces = "application/json")
#ResponseBody
public PcUser read(#PathVariable String id) {
logger.debug("Delegating to service to return PcUser " + id);
return pcUserService.read(id);
}
#RequestMapping(value = "/create/{pcUser}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
#ResponseBody
public boolean create(#PathVariable PcUser pcUser) {
logger.debug("Delegating to service to create new PcUser");
return pcUserService.create(pcUser);
}
#RequestMapping(value = "/update/{pcUser}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
#ResponseBody
public boolean update(#PathVariable PcUser pcUser) {
logger.debug("Delegating to service to update existing PcUser");
return pcUserService.update(pcUser);
}
#RequestMapping(value = "/delete/{id}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
#ResponseBody
public boolean delete(#PathVariable String id) {
logger.debug("Delegating to service to delete existing PcUser");
return pcUserService.delete(id);
}
}
UPDATE (2/5/2012):
After some research, I came across a Spring framework called spring-test-mvc. It looks very promising and I have managed to get a good start on this. But now I have a new problem. When I submit a GET request to "/pcusers/{id}", the control is passed to read method which is responsible for handling that mapping. Inside that method I have a pcUserService that does a read. Now, the problem is when I run this test, the pcUserService instance inside real controller is NULL; and therefore it ends up crashing as read cannot be called on a NULL object.
Here's PcUserControllerTest code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/applicationContextTest.xml")
public class PcUserControllerTest {
#Autowired
PcUserService pcUserService;
#Autowired
PcUserController pcUserController;
PcUser pcUser;
#Before
public void setUp() throws Exception {
pcUser = new PcUser("John", "Li", "Weasley", "john", "john", new DateTime());
pcUserService.create(pcUser);
}
public void tearDown() throws Exception {
pcUserService.delete(pcUser.getId());
}
#Test
public void shouldGetPcUser() throws Exception {
standaloneSetup(pcUserController)
.build()
.perform(get("/pcusers/" + pcUser.getId()).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
Here is one suggestion that should give you some ideas. I assume that you are familiar with the SpringJUnit4ClassRunner and the #ContextConfiguration. Start by creating an test application context that contains PcUserController and a mocked PcUserService. In the example PcUserControllerTest class below, Jackson is used to convert JSON messages and Mockito is used for mocking.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(/* Insert test application context here */)
public class PcUserControllerTest {
MockHttpServletRequest requestMock;
MockHttpServletResponse responseMock;
AnnotationMethodHandlerAdapter handlerAdapter;
ObjectMapper mapper;
PcUser pcUser;
#Autowired
PcUserController pcUserController;
#Autowired
PcUserService pcUserServiceMock;
#Before
public void setUp() {
requestMock = new MockHttpServletRequest();
requestMock.setContentType(MediaType.APPLICATION_JSON_VALUE);
requestMock.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
responseMock = new MockHttpServletResponse();
handlerAdapter = new AnnotationMethodHandlerAdapter();
HttpMessageConverter[] messageConverters = {new MappingJacksonHttpMessageConverter()};
handlerAdapter.setMessageConverters(messageConverters);
mapper = new ObjectMapper();
pcUser = new PcUser(...);
reset(pcUserServiceMock);
}
}
Now, we have all the code needed to create the tests:
#Test
public void shouldGetUser() throws Exception {
requestMock.setMethod("GET");
requestMock.setRequestURI("/pcusers/1");
when(pcUserServiceMock.read(1)).thenReturn(pcUser);
handlerAdapter.handle(requestMock, responseMock, pcUserController);
assertThat(responseMock.getStatus(), is(HttpStatus.SC_OK));
PcUser actualPcUser = mapper.readValue(responseMock.getContentAsString(), PcUser.class);
assertThat(actualPcUser, is(pcUser));
}
#Test
public void shouldCreateUser() throws Exception {
requestMock.setMethod("POST");
requestMock.setRequestURI("/pcusers/create/1");
String jsonPcUser = mapper.writeValueAsString(pcUser);
requestMock.setContent(jsonPcUser.getBytes());
handlerAdapter.handle(requestMock, responseMock, pcUserController);
verify(pcUserServiceMock).create(pcUser);
}

Resources