Java - How to get http header in interface implementation? - java

I'm trying to get the x-forwarded-for header from an http request using postman with an interface method. I want to get the IP address in the implementation method, but it either comes in null or blank.
When I test using Postman, if I use #Headerparam it returns null and if I use #RequestHeader it returns blank.
DataService interface class:
#POST
#Path(PATH)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#WebMethod(operationName="submit")
#ExecutableBy(anonymous = true)
public Response submit(Data data, #RequestHeader(value = "x-forwarded-for") String ipAddr);
DataService implementation:
#Override
public Response submit(Data data, String ipAddr) {
LOG.debug("ip addr from header " + ipAddr);
...
}

Are you sure that "x-forwarded-for" header is there?
#HeaderParam("x-forwarded-for") works for me.

Related

Spring Contracts: how to send a Collection of Strings as a RequestBody

A question about how to write a contract for a method annotated with #RequestBody taking a Collection of Strings as a parameter.
I have the following method:
#PostMapping(path = "/some/uri", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
#ApiOperation("GET with body")
public Response<Boolean> someMethod(#RequestParam(value = "key") final String key,
#RequestBody final Collection<String> numbers){
return some logic;
}
and I have written the following contract for testing purposes:
import org.springframework.cloud.contract.spec.Contract
Contract.make {
description "Should return true"
request {
method POST()
url("/some/uri?key=NEW_KEY")
body'''["12345",
"00143"]'''
}
response {
status 200
headers {header 'Content-Type': 'application/json;charset=UTF-8'}
body '''true'''
}
I keep getting 415, the test cannot find my method, I guess my mistake might be in the way I send the collection of strings, I have tried some other options but did not succed.
I tried the suggestions above but unfortunately they both did not solve my issue. The reason I got 415 was that when I added a body to my request, the check was also made behind the scenes on the content type of the body, so I had to explicitly specify that the body was in json format also in the request:
request {
method POST()
url("/some/uri?key=NEW_KEY")
headers {header 'Content-Type': 'application/json;charset=UTF-8'}
body'''["12345",
"00143"]'''
}

How to set priority to Spring-Boot request mapping methods

I have a Spring-Boot (v2.0.2) application with a RestController with 2 methods which only differ by the Accept header. A simplified version of the code is this:
#RestController
#RequestMapping("/myapp")
public class FooController {
#GetMapping(value = "/foo/{id}", headers = "Accept=application/json", produces = "application/json;charset=UTF-8")
public ResponseEntity<String> fooJson(#PathVariable id) {
return foo(pageId, true);
}
#GetMapping(value = "/foo/{id}", headers = "Accept=application/ld+json", produces = "application/ld+json;charset=UTF-8")
public ResponseEntity<String> fooJsonLd(#PathVariable id) {
return foo(pageId, false);
}
private ResponseEntity<String> foo(String id, boolean isJson) {
String result = generateBasicResponse(id);
if (isJson) {
return result
}
return addJsonLdContext(result);
}
This works fine. If we sent a request with accept header such as application/json;q=0.5,application/ld+json;q=0.6 for example it will return a json-ld response as it should.
My problem is that if we sent a request with no accept header, an empty accept header or a wildcard */* then it will by default always return a json response whereas I want the default response to be json-ld.
I've tried various things to make the json-ld request mapping take priority over the json one:
Reversing the order in which the mappings are declared.
Adding an #Order annotation to both methods (with value 1 for json-ld and value 2 for the json method)
Creating different classes and putting the #Order annotation at class-level
Adding Accept=*/* as a second accept header to the json-ld mapping does work in giving it preference but has the unwanted side-affect that all accept headers are accepted, even unsupported types as application/xml for example.
The only solution I can think of is creating one request-mapping method that accepts both headers and then processing the accept header ourselves, but I don't really like that solution. Is there a better, easier way to give preference to json-ld?
After some more searching this question on configuring custom MediaTypes pointed me in the right direction.
The WebMvcConfigurerAdapter (Spring 3 or 4) or WebMvcConfigurer (Spring 5) allows you to set a default mediatype like this:
public static final String MEDIA_TYPE_JSONLD = "application/ld+json";
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.valueOf(MEDIA_TYPE_JSONLD));
}
}
This works great for requests with no or an empty accept header, as well as accept: */*. However when you combine an unsupported type with the wildcard, for example accept: */*,text/plain it will return json instead of json-ld!? I suspect this is a bug in Spring.
I solved the issue using the consumes in the #GetMapping annotation. According to the official documentation:
The format is a single media type or a sequence of media types, with a request only mapped if the Content-Type matches one of these media types. Expressions can be negated by using the "!" operator, as in "!text/plain", which matches all requests with a Content-Type other than "text/plain".
In the solution bellow, note that I've added the consumes array to the normal json request mapping, making the client only be able to use the json endpoint if it have the correct Content-Type. Other requests go to the ld+json endpoint.
#GetMapping(value = "/json", headers = "Accept=application/json", consumes = {"application/json"})
#ResponseBody
public String testJson() {
return "{\"type\":\"json\"}";
}
#GetMapping(value = "/json", headers = "Accept=application/ld+json")
#ResponseBody
public String textLDJson() {
return "{\"type\":\"ld\"}";
}

Jersey Spring Boot add custom response header

I want to add custom header in spring boot JAX-RS application. I know couple of ways to add headers but my use case is not able to use these use cases.
My use case is that I want to create a random string on the one of the class and then add it to the header at the same time and move on.
These are some ways to add response header.
1.
`#Produces(MediaType.APPLICATION_JSON)
public UserClass getValues(#Context HttpHeaders header, #Context HttpServletResponse response) {
response.setHeader("yourheadername", "yourheadervalue");
... }`
2.
`#GET
#Produces({ MediaType.APPLICATION_JSON })
#Path("/values")
public Response getValues(String body) {
//Prepare your entity
Response response = Response.status(200).
entity(yourEntity).
header("yourHeaderName", "yourHeaderValue").build();
return response;
}`
implementing ContainerResponseFilter class and add.
But none of this solves my use case.
Let's say in my class I generated one string and wanted to add in the response header like this
#Component
public class AsyncPublisher{
public void publishLogs(Object request, Object response, Object serviceBin, long elapsedTime ){
String headerValue = "headerValue";
*// get response header list here and add header like this*
// responseHeaders.add("Custom-Header", headerValue)
}
}
Anyone know how to do this Cause above all three method does not solve this purpose.

How to pass List of hash map as query param in jersey

I tried something like below, M getting error
[[FATAL] No injection source found for a parameter of type public Response
#context UriInfo wont work as i need different data types as query param,like it may be integers and date.Kindly Help.
#GET
#Path("/getdetails")
#Produces({ "application/json", "application/xml" })
public Response getDetails(#QueryParam("field1") String fieldOne,#QueryParam("field2") List<HasMap<String,String>> fieldTwo){
//Processing
}
You will have to use POST and attach the list inside the request body
If the list your passing is json, you should also add the appropriate #Consumes value.
#POST
#Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
#Consumes(MediaType.APPLICATION_JSON)
public void getDetails(List<HasMap<String,String>> listFromClient) {
// do something with your list..
}

restful post with additional url parameters?

I have a web service which consumes a json request and outputs a json response. I have an issue where the customer needs to send an additional parameter in the url that can't be in the json body. Is there a way to do that?
For example, here is the method of a #WebService that consumes the incoming json request:
#POST
#Path("/bsghandles")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public BsgHandleResponse getBsgHandlesJson(BsgHandleRequest obj) {
HttpServletRequest request = getRequestObject();
return processGetBsgHandleByRateCode("key", obj.getRateCodes(), obj.getCorp(),
obj.getHeadend(), obj.getEquipmentProtocolAiu(), obj.getEquipmentTypeAiu(), request);
}
Notice that "key" is a hard-coded parameter. I need that parameter to be passed to it by the user in the url, but not the json structure. Is there a way to do that?
Just add a parameter annotated with #QueryParam to your method:
#POST
#Path("/bsghandles")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public BsgHandleResponse getBsgHandlesJson(#QueryParam("key") String key,
BsgHandleRequest obj) {
...
}
And consume it using:
POST /api/bsghandles?key=value HTTP/1.1
Content-Type: application/json
Accept: application/json
{
...
}
Yes there is!
You can pass it as a Query Param. For example:
www.yourhost.com/server?key=value
In java, yo can define it like this in your code:
#GET
#Path("/server")
public Response myMethod(#QueryParam("key") String value) { //your RESTFULL code}
So if you call that url as said before, you will have what you want in the variable value.
Hope it helps..
Cheers

Categories