How to pass InputStream to REST service POST method - java

How to pass InputStream to createParcel() method using Java REST client? How to call POST request using POSTMAN?
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.TEXT_PLAIN)
public int createParcel(InputStream is) {
int awbNo = 0;
try {
ParcelInfo parcelInfo = null;
parcelInfo = buildParcelInfo(is);
awbNo = index.incrementAndGet();
parcelInfo.setAwbNo(awbNo);
parcelInfo.setStatus("new");
parcelDataMap.put(awbNo, parcelInfo);
} catch(Exception ex) {
logger.error("Getting some exception for creating parcel : "+ex.getMessage(), ex);
}
return awbNo;
}
#GET
#Produces(MediaType.APPLICATION_XML)
public StreamingOutput getParcelInfo(#QueryParam("awbNo") int awbNo) {
ParcelInfo parcelInfo = null;
String xml = null;
parcelInfo = parcelDataMap.get(awbNo);
if (parcelInfo != null) {
xml = convert(parcelInfo);
}
return new ParcelInfoWriter(xml);
}

Because you are not consuming structured data but rather a raw InputStream, you first remove the #Consumes annotation; so your resource method should be:
#POST
#Produces(MediaType.TEXT_PLAIN)
public int createParcel(InputStream is) {
int awbNo = 0;
try {
ParcelInfo parcelInfo = null;
parcelInfo = buildParcelInfo(is);
// the rest of your code here
}catch(Exception ex) {
// catch specific exception instead of `Exception`
}
return awbNo;
}
Now use Postman to call your resource. The content body of your request can be any conent (in my example it is XML but you can send anything you like). Look at the screenshot below how to set the request correctly:
Execuse me for the drawing :-)

Related

error in grader test. Infinite recursion error

I am learning Spring MVC online. As part of my course, I have to develop a Cloud Video Service. Specifications are mentioned here.
https://github.com/juleswhite/mobile-cloud-asgn1
Below is my controller class.
#Controller
public class VideosController {
private final AtomicLong currentId = new AtomicLong(1L);
//A Map to hold incoming Video meta data
private HashMap<Long, Video> videoMap = new HashMap<Long, Video>();
//Receives GET requests to /video and returns the current list
// list of videos in memory
#RequestMapping(value = "/video", method = RequestMethod.GET)
public #ResponseBody List<Video> getVideoList() throws IOException{
List<Video> resultList = new ArrayList<Video>();
for(Long id : videoMap.keySet()) {
resultList.add(videoMap.get(id));
}
return resultList;
}
//Receives POST requests to /video and adds the video object
//created from request data to the Map
#RequestMapping(value = "/video", method = RequestMethod.POST)
public #ResponseBody() Video addVideoMetadata(#RequestBody Video data)
{
//create a Video object
Video video = Video.create().withContentType(data.getContentType())
.withDuration(data.getDuration())
.withSubject(data.getSubject())
.withTitle(data.getTitle()).build();
//set the id for the video
long videoId = currentId.incrementAndGet();
video.setId(videoId);
//set the URL for this Video
String videoURL = getDataUrl(videoId);
video.setDataUrl(videoURL);
//save the Video metadata object to map
Video v = save(video);
return v;
}
// Receives POST requests to /video/{id}/data e.g. /videoa/2/data
// uploads the video file sent as MultipartFile
// and writes it to the disc
#RequestMapping(value = "/video/{id}/data", method = RequestMethod.POST)
public #ResponseBody ResponseEntity<VideoStatus> uploadVideo
(#RequestParam("data") MultipartFile data,
#PathVariable("id") long id,
HttpServletResponse response
) throws IOException
{
// if video with id not present
if(!videoMap.containsKey(id)) {
System.out.println(" this id not present");
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
//return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
InputStream in = null;
try {
//read the input stream
in = data.getInputStream();
}
catch(IOException ie){
System.out.println("Exception reading inputstream");
}
finally {
in.close();
}
//get the video
Video v = videoMap.get(id);
//write it to disk
VideoFileManager.get().saveVideoData(v, in);
VideoStatus vs = new VideoStatus(VideoStatus.VideoState.READY);
return new ResponseEntity<>(vs, HttpStatus.OK);
//response.setStatus(200);
//return new ResponseEntity<>(vs, HttpStatus.OK);
}
//Reads GET request to /vide/{id}/data and returns the video
//binary data as output stream
#RequestMapping(value = "/video/{id}/data", method = RequestMethod.GET)
public #ResponseBody ResponseEntity<OutputStream> getBinaryData(
#PathVariable("id") long videoId,
HttpServletResponse response) throws IOException {
//if id is incorrect
if(!videoMap.containsKey(videoId)) {
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
//get the video from Map
Video outVideo = videoMap.get(videoId);
VideoFileManager vm = VideoFileManager.get();
//write the binary data to OutputStream
OutputStream os = response.getOutputStream();
vm.copyVideoData(outVideo, os);
return new ResponseEntity<>(os, HttpStatus.OK);
}
//save incoming video metadata to a Map
public Video save(Video v) {
checkAndSetId(v);
if(!videoMap.containsKey(v.getId())) {
videoMap.put(v.getId(), v);
}
return v;
}
//helper method to generate url for video
private String getDataUrl(long videoId){
String url = getUrlBaseForLocalServer() + "/video/" + videoId + "/data";
return url;
}
private String getUrlBaseForLocalServer() {
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String base =
"http://"+request.getServerName()
+ ((request.getServerPort() != 80) ? ":"+request.getServerPort() : "");
return base;
}
private void checkAndSetId(Video entity) {
if(entity.getId() == 0){
entity.setId(currentId.incrementAndGet());
}
}
}
Now, I pass all the tests in AutoGradingTest.java Unit code but not the testAddVideoData(). It gives a Socket Time out error, followed by Infinite recursion error, pointing to line number 159 in the AutoGradingTest.java
Logically, my code seems to be fine. Lot of other learners are facing problem with thirstiest case too but there is no help from the course instructors.
Can somebody please help me here? Thanks a lot.

Status code 404 when calling spring-boot API, but not for postman or browser

I want to make an API call to a local REST server built with Spring-Boot which is interacting with mongodb. I already checked some posts which I found to this topic, but my problem seems to be a little bit different.
Here are some code snippets which are relevant:
protected static CoreEntity[] sendGET(CoreEntity[] resultList, String path) throws IOException {
path = String.join("%20", path.split(" "));
return handleResponse(resultList, getConnection(path, "Get"));
}
private static HttpURLConnection getConnection(String path, String requestMethod) throws IOException {
URL url = new URL(REQUEST_URL + path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("accept", "application/json");
connection.setConnectTimeout(50000);
connection.setReadTimeout(50000);
connection.setRequestMethod(requestMethod);
initializeGSON();
return connection;
}
private static CoreEntity[] handleResponse(CoreEntity[] resultList, HttpURLConnection connection) {
try {
final int status = connection.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) { // Success
try (InputStreamReader reader = new InputStreamReader(connection.getInputStream()); BufferedReader in = new BufferedReader(reader)) {
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) { response.append(inputLine); }
reader.close();
in.close();
JSONArray jsonArray = getJSONAsArray(response.toString());
resultList = (CoreEntity[]) Array.newInstance(resultList.getClass().getComponentType(), jsonArray.length());
for (int i = 0; i < jsonArray.length(); i++)
resultList[i] = (CoreEntity) GSON.fromJson(jsonArray.get(i).toString(), resultList.getClass().getComponentType());
} catch (IOException | JSONException e) { e.printStackTrace(); }
} else {
System.out.println("\nRequest failed with error code: " + status);
}
connection.disconnect();
return resultList;
} catch (ConnectException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
The response for http://www.google.com or any other homepage is successful with status code 200. But as soon as I call my API I get an error with status code 404. Strange is that everything works when I am using Postman or the browser. So when I do a get request via postman to the following method (http://localhost:8080/pets/3), I can see the print out and get the data from mongodb, but not for the code above. For the code above nothing happens on server side, no print out, no exception, nothing.
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<T> getById(#PathVariable final long id) {
System.out.println("TEST ===> " + id);
T entity = getService().getById(id);
return entity == null ? ResponseEntity.notFound().build() : ResponseEntity.ok(entity);
}
It seems like my application is not able to find the API, but I already verified that the URL is correct which is why I don’t understand the error code 404.
I also read about package visibility, but my structure looks like the following which is why I don't think that this is the reason.
Package Structure (Don't be confused from name Aerospike)
I've spend way too much time for this now, and I am really desperate for help and hope you can help me or at least point me in the right direction.
Edit
Here is the entire RestController:
#Controller
public abstract class CoreController<S extends CoreService<T>, T extends CoreEntity> {
public static final String SERVER = "http://localhost", PORT = ":8080",
CORE_API = SERVER + PORT + "/"; // controller/v2/
public static final String ID = "id";
private String api;
public CoreController() { }
public CoreController(final String api) { this.api = CORE_API + api; }
#RequestMapping(value = "/{" + ID + "}", method = RequestMethod.GET)
public ResponseEntity<T> getById(#PathVariable final long id) {
System.out.println("TEST ===> " + id);
T entity = getService().getById(id);
return entity == null ? ResponseEntity.notFound().build() : ResponseEntity.ok(entity);
}
public abstract S getService();
}
#Controller
#RequestMapping(value = "pets/")
public class PetController extends CoreController<PetService, Pet> {
#Autowired
protected PetService service;
public static final String API = "pets";
public PetController() { super(API); }
public PetService getService() { return service; }
}
Here the evidence that the spring-boot is listening on 8080 and also postman works with port 8080.
Server print out on start up
I think you missing the slash ("/") in the start and you have duplicate in the end of the exposed value so it's looking for pets//{id} in the controller change to value = { "/pets"}
Anyway, when starting the service syou should see in the logs the exposed uri's

How to receive form parameters values in server?

i have React JS application where i send post request to server with form submission using axios library.
client request:
sendData(data,price) {
axios.post('http://localhost:8080/SampleJavaAPP/UserServer', {
item: data,//these value
price:price//these value
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
i am not sure how to get these values into server i am doing in server for getting value like this
String name = request.getParameter("item");
String price = request.getParameter("price");
System.out.println("Result "+name + price);
But it gives null values in server. how to receive these values parameters in server?
As Axios is sending Json data you will not be able to read its direct.
There are 2 possible solutions:
Either send data as form-data.
Read & Parse JSON at servlet:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
StringBuffer jb = new StringBuffer();
String line = null;
try {
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null) {
jb.append(line);
}
} catch (Exception e) { /*report an error*/ }
try {
JSONObject jsonObject = HTTP.toJSONObject(jb.toString());
String price = jsonObject.get("price"); // will return price value.
} catch (JSONException e) {
throw new IOException("Error parsing JSON request string");
}
}
Request Body is not retrieved by request.getParameter(). You need to retrieve it by request.getReader().
String body = IOUtils.toString(request.getReader());
It is suggested to use Apache Commons IO to get Content first. As your request is in JSON format. You can use Jackson to convert the String into Map.
Map<String, String> map = mapper.readValue(body, new TypeReference<Map<String, String>>(){});
System.out.println(map.get("item"));
System.out.println(map.get("price"));
request.getParameter()is referring to URL parameters ->myurl?someparameter=1
By doing request.getParameter("item"), your URL would need to look like http://localhost:8080/SampleJavaAPP/UserServer?item=myitem
What you are actually doing here
sendData(data,price) {
axios.post('http://localhost:8080/SampleJavaAPP/UserServer', {
item: data,//these value
price:price//these value
}
is adding the objects to the request body, which is IMHO correct. There for you won't find any parameters item or price on your server side request object.
What you need to do, is to parse the requests body. With request.getInputStream() you can get the Inputstream. I suggest you use an object mapper which makes that really easy. See Intro to the Jackson ObjectMapper
In your servlet, you do something like this:
ObjectMapper objectMapper = new ObjectMapper();
MyItem myItem = objectMapper.readValue(request.getInputStream(), MyItem.class);
public class MyItem{
String price;
String item;
public void setItem(String item) {
this.item = item;
}
public void setPrice(String price) {
this.price = price;
}
public String getItem() {
return item;
}
public String getPrice() {
return price;
}
}

How to give parameters to a method which implements another method

I used a jersey server and I want that a endpoint redirect to the download of a file depending on parameters.
I have difficulties with the function below :
#GET
#Path("/get/{id}/{chunk}")
public Response getDescription(#PathParam("id") String id, #PathParam("chunk") String chunk) {
{
StreamingOutput fileStream = new StreamingOutput()
{
#Override
public void write(java.io.OutputStream output, String id) throws IOException, WebApplicationException
{
try
{
if (Objects.equals(chunk, new String("init"))) {
java.nio.file.Path path = Paths.get("src/main/uploads/example/frame_init.pdf");
}
else {
java.nio.file.Path path = Paths.get("src/main/uploads/example/"+ id +".pdf");
}
byte[] data = Files.readAllBytes(path);
output.write(data);
output.flush();
}
catch (Exception e)
{
throw new WebApplicationException("File Not Found !!");
}
}
};
return Response
.ok(fileStream, MediaType.APPLICATION_OCTET_STREAM)
.header("content-disposition","attachment; filename = myfile.pdf")
.build();
}
I have a problem with passing parameters to the function write. I have my parameters id and chunk by the endpoint but I can't use it in the write method because it implements StreamingOutput().
How I can handle it ? Thank you
For java, final keyword should solve your problem.
As updated code;
#GET
#Path("/get/{id}/{chunk}")
public Response getDescription(#PathParam("id") final String id, #PathParam("chunk") final String chunk) {
{
StreamingOutput fileStream = new StreamingOutput()
{
#Override
public void write(java.io.OutputStream output, String id2) throws IOException, WebApplicationException
{
try
{
if (Objects.equals(chunk, new String("init"))) {
java.nio.file.Path path = Paths.get("src/main/uploads/example/frame_init.pdf");
}
else {
java.nio.file.Path path = Paths.get("src/main/uploads/example/"+ id2 +".pdf");
}
byte[] data = Files.readAllBytes(path);
output.write(data);
output.flush();
}
catch (Exception e)
{
throw new WebApplicationException("File Not Found !!");
}
}
};
return Response
.ok(fileStream, MediaType.APPLICATION_OCTET_STREAM)
.header("content-disposition","attachment; filename = myfile.pdf")
.build();
}

Encapsulating common exception handling logic

I have a series of web service method calls which all follow the below format. The only difference in each method is httpRequest.methodName(). Can anybody think of a way I can encapsulate the common logic? Also note that my environment is J2ME.
public Response webserviceCall(Request request) {
HTTPRequest httpRequest = new HTTPRequest(new ConnectionProperties());
String errorMessage = "";
String errorCode = "";
try {
// the only thing different
httpRequest.methodName();
} catch (SDKException e) {
errorMessage = e.getMessage();
errorCode = e.getErrorCode();
}
Error error = new Error(errorMessage,errorCode);
return new Response(error);
}
One alternative is to put that code in an abstract class, and change it to call an abstract method (name it process, for example):
abstract class BaseWebService {
public abstract Response process(HTTPRequest request) throws SDKException;
public Response webserviceCall(Request request) {
HTTPRequest httpRequest = new HTTPRequest(new ConnectionProperties());
String errorMessage = "";
String errorCode = "";
try {
process(httpRequest);
} catch (SDKException e) {
errorMessage = e.getMessage();
errorCode = e.getErrorCode();
}
Error error = new Error(errorMessage,errorCode);
return new Response(error);
}
}
Then make each of your services extend that class and implement the process method as needed
class OneService extends BaseWebService {
Response process(HTTPRequest request) throws SDKException{
return request.methodName();
}
}
For the records, this is the Template Method Pattern

Categories

Resources