How to use #produces annotation? - java

I want to use #Produces({Mediatype.Application_XML , Mediatype.Application_JSON}) in a program that I am writing. I want to use this on only one method, but I am confused that when will it return a JSON object and when will it return an XML page. Here is the code I am writing and in both the cases it returns me an XML feed. I want it to return an JSON object if it does not meet the if-else criterion.
#Path("/{search}")
#GET
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public String getCountryData(#PathParam("search") String search, #QueryParam("ccode") String ccode , #QueryParam("scode") String scode) {
if(ccode.equals("XML")){
return "<note> <to>Tove</to> <from>Jani</from><heading>Reminder</heading> <body>Don't forget me this weekend!</body></note>";
}
return EndecaConn.ConnectDB("Search", search,"mode matchallpartial" );
}

The media type will be part of the request, you shouldn't include it as a query parameter. Below is some sample Java code that would request the data as application/xml.
String uri =
"http://localhost:8080/CustomerService/rest/customers/1";
URL url = new URL(uri);
HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
JAXBContext jc = JAXBContext.newInstance(Customer.class);
InputStream xml = connection.getInputStream();
Customer customer =
(Customer) jc.createUnmarshaller().unmarshal(xml);
connection.disconnect();
In your example you could have different methods corresponding to the same path for the different media types.
#Path("/{search}")
#GET
#Produces(MediaType.APPLICATION_JSON)
public String getCountryDataJSON(#PathParam("search") String search, #QueryParam("scode") String scode) {
return JSON;
}
#Path("/{search}")
#GET
#Produces(MediaType.APPLICATION_XML)
public String getCountryDataXML(#PathParam("search") String search, #QueryParam("scode") String scode) {
return XML;
}

You have to return a Response object with the entity set to your domain entity. The serialization of the xml/json is done automatically.
See: https://jsr311.java.net/nonav/releases/1.1/javax/ws/rs/core/Response.html
yYou can return an entity like this:
Foo myReturn = new Foo(blah,blah,blah)
return Response.ok(myReturn).build()
If you need fine grained serialization you can use annotations on your domain class.

Related

How to wrap an external API inside a custom API with Spring Boot

Let's say I have a third party rest api ("https://example.com/write") that allows POST requests with the following body structure:
{
"id": "abc",
"Config": {"Comments":"text"}
}
I am completely new to Java and the Spring Framework, but I want to create a custom API with Spring that only allow users to change the text part of the body. Other parts of the JSON body should have a fixed value (for example id is always "abc"). Basically, when user input a custom text string, my api will compile the input and consume the external api and get the results from it accordingly
I understand the basics of #Getmapping / #RequestMapping after doing some research. Here is what I have so far for my custom API, and I am stuck at the post mapping section.
#RestController
#RequestMapping("/api")
public class ApiController {
#Autowired
private Environment env;
// GET
#RequestMapping(value = "/retrive", method = { RequestMethod.GET })
public ResponseEntity<?> retrive (HttpServletRequest request, HttpServletResponse response) throws IOException {
// URL
URL u = new URL("https://example.com/get");
HttpURLConnection uc = (HttpURLConnection) u.openConnection();
// Create HttpHeaders for ResponseEntity
HttpHeaders responseHeaders = new HttpHeaders();
uc.setRequestProperty ("Authentication", "Bearer "+ env.getProperty("api-key"));
try (InputStream inputStream = uc.getInputStream();
OutputStream outputStream = response.getOutputStream();
)
{IOUtils.copy(inputStream, outputStream);
}
return new ResponseEntity<>(responseHeaders, HttpStatus.OK);
}
// POST
#RequestMapping(value = "/write", method = { RequestMethod.POST },
consumes = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity process(#RequestBody Root input) throws IOException {
// Operation goes here...
return new ResponseEntity<>(input, HttpStatus.OK);
}
public class Root{
private String Comments;
// Getters and Setters
}
Create a Custom DTO class which will represent the response from Third party API. What It means is it should have all fields which should map with corresponding required field of response payload of third party API. It will be populated on de-serializing the third party API response. You can take help of feign client here. Its very easy and declarative way to make REST API call.
Create a separate response DTO with 2 fields 1 which will have the static value and second the DTO which we created above (which will be populated with the response of third party API). This DTO will be the response from POST "/write"

Send XML object through HTTP to a POST REST Service

I have an EJB application which needs to send a XML object to a RESTfull service through HTTP Post. (All in the same infrastructure park)
I have seen some examples which the XML object is converted to String before send it to the service. However, I want to pass all the XML object itself. (I suppose it's possible)
For instance, in a web application architecture, I would do that by using RestTemplate, as follow:
RestTemplate restTemplate = new RestTemplate();
EmployeeVO result = restTemplate.postForObject( uri, newEmployee, EmployeeVO.class);
Now, I strictly should do the same using HttpURLConnection instead.
Someone can help me by showing some example?
The rest service only consumes "application/XML" and returns a String.
Follow my RESTfull signature and my XML object.
RESTFull Service
#RestController
#RequestMapping(value = "/analytic/")
public class AnalyticController {
#RequestMapping(value = "/requestProcessor", method = RequestMethod.POST, consumes = MediaType.APPLICATION_XML_VALUE)
public String analyticRequest(#RequestBody ServiceRequest serviceRequest){
//Some code here...
return "0";
}
}
Domain
#XmlRootElement(name = "ServiceRequest")
public class ServiceRequest implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#XmlAttribute(name = "Method")
private String method;
#XmlElement(name = "Credential")
private Credential credential;
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Credential getCredential() {
return credential;
}
public void setCredential(Credential credential) {
this.credential = credential;
}
}
Thanks in advance.
Thank you all for your thoughts!
I could solve my issue by doing the below code.
URL url = new URL("http://server:port/service_path");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/xml");
OutputStream os = connection.getOutputStream();
JAXBContext jaxbContext = JAXBContext.newInstance(MyClass.class);
jaxbContext.createMarshaller().marshal(MyClass, os);
os.flush();

How to get data from response

I have created 2 web services and I was able to send some data.
Using this three lines of code
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet("http://localhost/<appln-folder-name>/method/domethod?data1=abc&data2=xyz");
HttpResponse response = client.execute(request);
In this situation, the method that I posted send to a Web Server the 2 data.
#Path("/domethod")
// Produces JSON as response
#Produces(MediaType.APPLICATION_JSON)
// Query parameters are parameters: http://localhost/<appln-folder-name>/method/domethod?data1=abc&data2=xyz
public String doLogin(#QueryParam("data1") String d1, #QueryParam("data2") String d2){
String response = "";
System.out.println("Data: d1="+d1+"; d2="+d2);
if(checkData(d1, d1)){
response = Utitlity.constructJSON("tag",true);
}else{
response = Utitlity.constructJSON("tag", false, "Error");
}
return response;
}
System.out works correctely and print: d1=abc; d2=xyz
But now the application isn't able to return response to the first method.
How I can get the response?
You're already getting the response here:
HttpResponse response = client.execute(request);
And since you're already using org.apache.httpcomponents you can do something like:
String result = EntityUtils.toString(response.getEntity());
After that you have your data as a string, simply do what you wish with it.
EDIT:
A little bit more information, your data is in the entity of the response, which is an HttpEntity object. You can get the content from there as an InputStream and read it as you wish, my example was for a simple string.
First of all, I would annotate with get the method. Then I would use a Java Class and let the library convert the class to json for me.
Try to do this:
#GET
#Path("/domethod")
// Produces JSON as response
#Produces(MediaType.APPLICATION_JSON)
// Query parameters are parameters: http://localhost/<appln-folder-name>/method/domethod?data1=abc&data2=xyz
public String doLogin(#QueryParam("data1") String d1, #QueryParam("data2") String d2){
Response response = new Response();
System.out.println("Data: d1="+d1+"; d2="+d2);
if(checkData(d1, d1)){
//set in response the tag property to true and maybe another property to OK
response.setTag(true);
response.setStatus("OK");
}else{
//set in response the tag property to false and maybe another property to ERROR
response.setTag(false);
response.setStatus("ERROR");
}
return response;
}

Send and receive JSON to REST WebService in Jersey Java

I am new to Jersey Java REST WebService framework. I am trying to write a service method which consumes and produces JSON. My service code is below. It is simplest code, just for studying purpose.
#Path("/myresource")
public class MyResource {
#Path("/sendReceiveJson")
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String sendReceiveJson(String name)
{
System.out.println("Value in name: " + name);
return "{\"serviceName\": \"Mr.Server\"}";
}
}
And following is JerseyClient code.
public class Program {
public static void main(String[] args) throws Exception{
String urlString="http://localhost:8080/MyWebService/webresources/myresource/sendReceiveJson";
URL url=new URL(urlString);
URLConnection connection=url.openConnection();
connection.setDoOutput(true);
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
out.write("{\"clientName\": \"Mr.Client\"}");
out.close();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String decodedString;
while ((decodedString = in.readLine()) != null) {
System.out.println(decodedString);
}
in.close();
}
}
But when i run service and then client, i am unable to send/receive JSON data. I get Exception at connection.getInputStream() which is
Server returned HTTP response code: 405 for URL: http://localhost:8080/hellointernet/webresources/myresource/sendReceiveJson
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1625)
Please guide me, what needs to correct, or whether i am in wrong direction.
Your resource method is annotated as #GET which means any input data would have to be query string parameters.
In this context #Consumes(MediaType.APPLICATION_JSON) doesn't make a lot of sense as only APPLICATION_FORM_URLENCODED is supported via GET.
When you client calls setDoOutput(true) it probably switches your HTTP call to a POST hence causing the 405 Method Not Allowed.
If you want to consume JSON you should change your #GET annotation with #POST instead. Your client call should then work if it's indeed a POST. You can specify it with the following method:
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setDoOutput(true);
httpCon.setRequestMethod("POST");
This API is pretty low level though, so I'd highly recommend you use Jersey's Client API instead. See https://jersey.java.net/documentation/1.17/client-api.html

Multiple #GET for different MIME - how to consume this with plain HttpURLConnection()

I just realized that it is possible to define something like this in my RESTful resource .java file:
#GET
#Produces("text/plain")
public String getPlainTextHello() { ... }
#GET
#Produces("application/json")
public String getJSONHello() { ... }
Isn't that fantastic? But wait the moment....
PROBLEM
I am consuming my API with simple client. Something like this code with help of HttpURLConnection:
URL obj = new URL("http://some.url/res/hello");
HttpURLConnection conn = (HttpURLConnection) obj.openConnection();
conn.setRequestMethod("GET");
... /* get response ... conn.getInputStream() */
How the server 'know' which one method call to serve the client?
Regards.
First of all you should consider using the same method for different types of "produces":
#GET
#Produces({ "application/xml", "text/plain"})
public String getHello() { ... }
The different types of "produces" could be handled by JAXB (in case the response is an object...).
You can define the client side "accept" mime type by using:
String uri =
"http://localhost:8080/hello/";
URL url = new URL(uri);
HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/json");
This question provides more insights (and other client side frameworks) related with this problem: REST. Jersey. How to programmatically choose what type to return: JSON or XML?
You'd probably want a generic function to do all the common work, and then simply pass this work to the response specific functions you outlined.
getHello(String responseType)
{
// do all your work you'd end up doing in both functions
switch (responseType):
case ("json") {
return getJSONHello(work);
}
case ("text") {
return getPlainTextHello(work);
}
}
I made some more checks on this and what works for me is just settings Accept:
...
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", mime);
...
where mime is "text/plain" or "application/json". This way my server calls one of the GET function.
Anyway I am confused why most answers suggest to use a common one function to serve a #GET and check for type inside this function...

Categories