Jersey get credentials from url - jersey

I have an url like this:
http://log:pass#localhost:8080/myendpoint
And Jersey endpoint:
#GET #Produces(MediaType.APPLICATION_JSON) #Path("/login")
#Consumes(MediaType.APPLICATION_JSON) public Response login(
#Context HttpHeaders headers, #QueryParam("callback") String callback)
{
}
And ideally I want to get 'log' and 'pass' in my endpoint method. How to do that in Jersey? I tried many endpint method signatures, filters, etc but it shows me
http://localhost instead of http://log:pass#localhost everywhere
How to achieve this?

Assuming that in your front end, you are sending your parameters as a json object using JSON.stringify() then back in your endpoint method. Add this as a second argument to that method signature JsonObject payload. Then you can access your query parameters within that method as follows
String log = payload.getString("log");
String pass = payload.getString("pass");
Revised Version
#Path("/login")
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response login(#Context UriInfo uriInfo, #Context HttpHeaders headers, #QueryParam("callback") String callback) {
URI requestUri = uriInfo.getRequestUri();
String authority = requestUri.getAuthority(); // authority contains what you need;
}

Related

Supporting application/json and application/x-www-form-urlencoded simultaneously from Spring's rest controller

Am writing a REST endpoint which needs to support both application/x-www-form-urlencoded and application/json as request body simultaneously. I have made below configuration,
#RequestMapping(method = RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE }, consumes = {
MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE }, path = Constants.ACCESS_TOKEN_V1_ENDPOINT)
public OAuth2Authorization createAccessTokenPost(
#RequestBody(required = false) MultiValueMap<String, String> paramMap) { ..
While it supports application/x-www-form-urlencoded or application/json individually (when I comment out one content type from consumes = {}), but it does not support both simultaneously. Any ideas ?
So RestControllers by default can handle application/json fairly easily and can create a request pojo from a #RequestBody annotated parameter, while application/x-www-form-urlencoded takes a little more work. A solution could be creating an extra RestController method that has the same mapping endpoint to handle the different kinds of requests that come in (application/json, application/x-www-form-urlencoded, etc). This is because application/x-www-form-urlencoded endpoints need to use the #RequestParam instead of the #RequestBody annotation (for application/json).
For instance if I wanted to host a POST endpoint for /emp that takes either application/json or application/x-www-form-urlencoded as Content-Types and uses a service to do something, I could create Overload methods like so
#Autowired
private EmpService empService;
#PostMapping(path = "/emp", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public ResponseEntity createEmp(final #RequestHeader(value = "Authorization", required = false) String authorizationHeader,
final #RequestParam Map<String, String> map) {
//After receiving a FORM URLENCODED request, change it to your desired request pojo with ObjectMapper
final ObjectMapper mapper = new ObjectMapper();
final TokenRequest tokenRequest = mapper.convertValue(map, CreateEmpRequest.class);
return empService.create(authorizationHeader, createEmpRequest);
}
#PostMapping(path = "/emp", consumes = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity createEmp(final #RequestHeader(value = "Authorization", required = false) String authorizationHeader,
final #RequestBody CreateEmpRequest createEmpRequest) {
//Receieved a JSON request, the #RequestBody Annotation can handle turning the body of the request into a request pojo without extra lines of code
return empService.create(authorizationHeader, createEmpRequest);
}
As per my findings, spring does not support content types "application/x-www-form-urlencoded", "application/json" and "application/xml" together.
Reason I figured: Spring processes JSON and XML types by parsing and injecting them into the java pojo marked with #RequestBody spring annotation. However, x-www-form-urlencoded must be injected into a MultiValueMap<> object marked with #RequestBody. Two different java types marked with #RequestBody will not be supported simultaneously, as spring may not know where to inject the payload.
A working solution:
"application/x-www-form-urlencoded" can be supported as it is in the API. That is, it can be injected into spring's MultiValueMap<> using an #RequestBody annotation.
To support JSON and XML on the same method, we can leverage servlet specification and spring's class built on top of them to extract the payload as stream.
Sample code:
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.MultiValueMap;
// usual REST service class
#Autowired
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;
#Autowired
private Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter;
public ResponseEntity<Object> authorizationRequestPost(HttpServletResponse response, HttpServletRequest request,#RequestBody(required = false) MultiValueMap<String, String> parameters) {
// this MultiValueMap<String,String> will contain key value pairs of "application/x-www-form-urlencoded" parameters.
// payload object to be populated
Authorization authorization = null;
HttpInputMessage inputMessage = new ServletServerHttpRequest(request) {
#Override
public InputStream getBody() throws IOException {
return request.getInputStream();
}
};
if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
authorization = (Authorization) mappingJackson2HttpMessageConverter.read(Authorization.class, inputMessage);
}
else if (request.getContentType().equals(MediaType.APPLICATION_XML_VALUE)) {
authorization = (Authorization)jaxb2RootElementHttpMessageConverter.read(Authorization.class, inputMessage);
}
else{
// extract values from MultiValueMap<String,String> and populate Authorization
}
// remaining method instructions
}
Point to note that any custom data type/markup/format can be supported using this approach. Spring's org.springframework.http.converter.HttpMessageConverter<> can be extended to write the parsing logic.
Another possible approach could be an AOP style solution which would execute the same logic: parse payload by extracting it from HttpServlet input stream and inject into the payload object.
A third approach will be to write a filter for executing the logic.
It's not possible to handle application/json and application/x-www-form-urlencoded requests simultaneously with a single Spring controller method.
Spring get application/x-www-form-urlencoded data by ServletRequest.getParameter(java.lang.String), the document said:
For HTTP servlets, parameters are contained in the query string or posted form data.
If the parameter data was sent in the request body, such as occurs with an HTTP POST request, then reading the body directly via getInputStream() or getReader() can interfere with the execution of this method.
So, if your method parameter is annotated with #RequestBody, Spring will read request body and parse it to the method parameter object. But application/x-www-form-urlencoded leads Spring to populate the parameter object by invoking ServletRequest.getParameter(java.lang.String).
Just to make it, the above answer doesn't work as even if you do not annotate MultiValueMap with #RequestBody it would always check for contentType==MediaType.APPLICATION_FORM_URLENCODED_VALUE which again in rest of the cases resolves to 415 Unsupported Media Type.

Spring boot/Spring MVC - How to forward a response from another request

I need a rest end point whose response is HTML. But instead of a view defined in my project, i would like to forward the HTML response from another request made inside that rest end point.
For example, my rest end point makes a http request to an internal service and returns the HTML returned from that service? Is it possible? Any thoughts?
Here is a code example
#RequestMapping("/test")
public String testMe(Model model, #RequestParam("param1") String param1, #RequestParam("param2") String param2)
{
//Make a Http call to an internal service and return the response from that call
return "<RESPONSE_FROM_THAT_CALL>";
}
I would like to return the HTML response from the internal service
You can use a RestTemplate to fetch the result from the other service and just return it as a String:
#Controller
public class MyController {
private RestTemplate restTemplate = new RestTemplate();
#ResponseBody
#RequestMapping("/test")
public String testMe(Model model, #RequestParam("param1") String param1, #RequestParam("param2") String param2) {
URI uri = UriComponentsBuilder.fromHttpUrl("http://www.example.com");
.queryParam("param1", param1)
.queryParam("param2", param2)
.build()
.toUri());
return restTemplate.getForObject(uri, String.class);
}
}
If you'll have more endpoints that you wanna proxy to another service, you should consider using e.g. Zuul as a micro proxy. See e.g. this blog post explaining how you can easily create such a proxy.

How to pass json parameters with jax-rs?

if I want to post json parameter to a url with jax-rs, how to receive the parameters in the back end and convert it into an integer array?
parameters:{"sbfIdList":[14]}
backend service(in java): I tried below , but feel no luck, I just got an empty array.
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Path("/delete")
public String deleteSbc(#QueryParam("sbfIdList") List<Long> sbfIds,#Context HttpServletRequest request, #Context HttpServletResponse response) {
return "";
}
I request the backend service using POST method.

How to get access to HTTP header information in Spring MVC REST controller?

I am new to web programming in general, especially in Java, so I just learned what a header and body is.
I'm writing RESTful services using Spring MVC. I am able to create simple services with the #RequestMapping in my controllers. I need help understanding how to get HTTP header information from a request that comes to my method in my REST service controller. I would like to parse out the header and get some attributes from it.
Could you explain how I go about getting that information?
When you annotate a parameter with #RequestHeader, the parameter retrieves the header information. So you can just do something like this:
#RequestHeader("Accept")
to get the Accept header.
So from the documentation:
#RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(#RequestHeader("Accept-Encoding") String encoding,
#RequestHeader("Keep-Alive") long keepAlive) {
}
The Accept-Encoding and Keep-Alive header values are provided in the encoding and keepAlive parameters respectively.
And no worries. We are all noobs with something.
You can use the #RequestHeader annotation with HttpHeaders method parameter to gain access to all request headers:
#RequestMapping(value = "/restURL")
public String serveRest(#RequestBody String body, #RequestHeader HttpHeaders headers) {
// Use headers to get the information about all the request headers
long contentLength = headers.getContentLength();
// ...
StreamSource source = new StreamSource(new StringReader(body));
YourObject obj = (YourObject) jaxb2Mashaller.unmarshal(source);
// ...
}
My solution in Header parameters with example is user="test" is:
#RequestMapping(value = "/restURL")
public String serveRest(#RequestBody String body, #RequestHeader HttpHeaders headers){
System.out.println(headers.get("user"));
}
You can use HttpEntity to read both Body and Headers.
#RequestMapping(value = "/restURL")
public String serveRest(HttpEntity<String> httpEntity){
MultiValueMap<String, String> headers =
httpEntity.getHeaders();
Iterator<Map.Entry<String, List<String>>> s =
headers.entrySet().iterator();
while(s.hasNext()) {
Map.Entry<String, List<String>> obj = s.next();
String key = obj.getKey();
List<String> value = obj.getValue();
}
String body = httpEntity.getBody();
}

Using both #RequestBody and #RequestParam together in spring mvc3

I am using spring-mvc 3.1.0.RELEASE and for some reason, mapping POST with query params and request body does not work.
Here is how my controller method looks:
#RequestMapping(method = POST, value = "/post-to-me/")
public void handlePost(
#RequestBody Content content,
#RequestParam("param1") String param1,
#RequestParam("param2") String param2
){
//do stuff
}
However, if I convert all the request params to path params, mapping works. Has anyone run into something similar?
Thanks!
EDIT:
"does not work" == 404 when I try doing, POST /post-to-me?param1=x&param2=y
First, your POST url doen't match the controller method url, your POST url must be "/post-to-me/?param1=x&param2=y" not "/post-to-me?param1=x&param2=y"
Second, where did Content class come from?? I used a String and works fine for me
#RequestMapping(method = RequestMethod.POST, value = "/post-to-me/")
public void handlePost(#RequestBody String content,
#RequestParam("param1") String param1,
#RequestParam("param2") String param2, HttpServletResponse response) {
System.out.println(content);
System.out.println(param1);
System.out.println(param2);
response.setStatus(HttpServletResponse.SC_OK);
}
Note that I used HttpServletResponse to return a HTTP 200 code, but I think there is a better solution for return Http codes, check this: Multiple response http status in Spring MVC
Trailing slash at the end of your request mapping value might be the problem.
Try:
#RequestMapping(method = RequestMethod.POST, value = "/post-to-me")
or send your POST request to POST /post-to-me/?param1=x&param2=y

Resources